Passing several textures to shader in LibGDX - android

I need to pass 2(or more) textures to one shader. Also I have to bind textures in render method, because I use FrameBuffer and try to bind textures on fly. So, my code is below:
#Override
public void show () {
fbo = new FrameBuffer(Format.RGB565, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
shader = new ShaderProgram(Gdx.files.internal("shaders/vertex.glsl"), Gdx.files.internal("shaders/test_fragment.glsl"));
...
}
#Override
public void render(float delta) {
fbo.begin();
Gdx.graphics.getGL20().glClearColor( 0.0f, 0.0f, 0.0f, 1f );
Gdx.graphics.getGL20().glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT );
cam.update();
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
spriteBatch.draw(someImage, 0, 0, width, height);
spriteBatch.end();
fbo.end();
Texture texture = fbo.getColorBufferTexture();
time+=Gdx.graphics.getDeltaTime();
shader.begin();
shader.setUniformMatrix(u_wview, cam.projection);
Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE0);
texture.bind(0);
shader.setUniformi("u_texture", 0); //passing first texture!!!
Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE1);
tex2.bind(1);
shader.setUniformi("u_texture2", 1); //passing second texture!!!
shader.setUniformf(u_res, new Vector2(Gdx.graphics.getWidth(),Gdx.graphics.getHeight()));
shader.setUniformf(u_time, time);
mesh.render(shader, GL20.GL_TRIANGLES);
shader.end();
}
Fragment shader:
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoords;
uniform vec2 resolution;
uniform float u_time;
uniform sampler2D u_texture;
uniform sampler2D u_texture2;
uniform float u_temp;
const float pi = 3.14159265;
void main()
{
vec2 p = gl_FragCoord.xy / resolution.xy;
vec4 i = texture2D(u_texture2, p);
gl_FragColor = texture2D(u_texture, p)+i;
}
If I pass only one texture everything is ok. Otherwise, I get unexpected result as if the first texture(u_texture) is the second one(u_texture2). What is the proper way to pass more than one texture to shader?

I had to pass textures in back order like below:
texture.bind(1);
shader.setUniformi("u_texture", 1); //passing first texture!!!
texture2.bind(0);
shader.setUniformi("u_texture2", 0); //passing second texture!!!

Related

Overlay texture using GLES20 and apply rotation

I am working on a project in which I am using GLES20 to render a texture. I used GLUtils.texImage2D() to draw 2d texture image from the bitmap.
What do I need to implement to make these changes:
Place the texture to the right corner of the screen instead of stretching it to the full screen.
Provide incremental rotation frame by frame to the texture.
Shaders
private final static String FRAGMENT_SHADER =
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform lowp sampler2D sTexture;\n" +
"uniform lowp sampler2D oTexture;\n" +
"void main() {\n" +
" lowp vec4 textureColor = texture2D(sTexture, vTextureCoord);\n" +
" lowp vec4 textureColor2 = texture2D(oTexture, vTextureCoord);\n" +
" \n" +
" gl_FragColor = mix(textureColor, textureColor2, textureColor2.a);\n" +
"}\n";
protected static final String DEFAULT_VERTEX_SHADER =
"attribute highp vec4 aPosition;\n" +
"attribute highp vec4 aTextureCoord;\n" +
"varying highp vec2 vTextureCoord;\n" +
"void main() {\n" +
"gl_Position = aPosition;\n" +
"vTextureCoord = aTextureCoord.xy;\n" +
"}\n";
Texture Generation
int[] textures = new int[1];
#Override
public void setup() {
super.setup();// 1
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
}
#Override
public void onDraw() {
if (bitmap == null) {
return;
}
int offsetDepthMapTextureUniform = getHandle("oTexture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
if (bitmap != null && !bitmap.isRecycled()) {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap, 0);
}
GLES20.glUniform1i(offsetDepthMapTextureUniform, 3);
// Recycle the bitmap, since its data has been loaded into OpenGL.
releaseBitmap();
}
UPDATED
I added the mMVPMatrix for the texture transformation as suggested by alexrnov. Both, camera feed and overlay texture are rotating now.
protected static final String VERTEX_SHADER ="attribute highp vec4 aPosition;\n" +
"uniform mat4 uMVPMatrix;\n" +
"attribute highp vec4 aTextureCoord;\n" +
"varying highp vec2 vTextureCoord;\n" +
"void main() {\n" +
"gl_Position = uMVPMatrix * aPosition;\n" +
"vTextureCoord = aTextureCoord.xy;\n" +
"}\n";
#Override
public void onDraw() {
....
Matrix.setIdentityM(mvpMatrix, 0);
Matrix.rotateM(mvpMatrix, 0, rotation, 0.0f, 0.0f, 1.0f);
rotation++;
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMVPMatrixAsFloatBuffer(mvpMatrix));
...
}
The project structure is quite complicated. I can't write all the code here. Please refer the Github Project
Maybe there is another way, but you can overlay the texture on the rectangle, and apply transformations (movement/rotate) to this rectangle:
Vertex shader:
#version 100
uniform mat4 u_mvpMatrix; // MVP-matrix for moving and rotating texture
attribute vec4 a_position; // data of vertices rectangle
attribute vec2 a_textureCoordinates;
varying vec2 v_textureCoordinates;
void main() {
v_textureCoordinates = a_textureCoordinates;
gl_Position = u_mvpMatrix * a_position;
}
Fragment shader:
#version 100
varying vec2 v_textureCoordinates;
uniform sampler2D s_texture;
void main() {
gl_FragColor = texture2D(s_texture, v_textureCoordinates);
}
Approximate Java-code:
private final int textureID;
...
textureID = loadTexture(R.raw.texture);
...
#Override
public void draw() {
GLES20.glUseProgram(programObject);
GLES20.glEnableVertexAttribArray(positionLink);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, VBO[0]);
GLES20.glVertexAttribPointer(positionLink, VERTEX_COMPONENT,
GLES20.GL_FLOAT, false, VERTEX_STRIDE, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glEnableVertexAttribArray(textureCoordinatesLink);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, VBO[1]);
GLES20.glVertexAttribPointer(textureCoordinatesLink, TEXTURE_COMPONENT,
GLES20.GL_FLOAT, false, TEXTURE_STRIDE, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glUniform1i(samplerLink, 0);
GLES20.glUniformMatrix4fv(mvpMatrixLink, 1, false,
RectangleObject3D.getMVPMatrixAsFloatBuffer());
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, VBO[2]);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, NUMBER_INDICES,
GLES20.GL_UNSIGNED_INT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glDisableVertexAttribArray(positionLink);
GLES20.glDisableVertexAttribArray(textureCoordinatesLink);
}
MVP-matrix:
import android.opengl.Matrix
protected val viewMatrix = FloatArray(16)
protected val projectionMatrix = FloatArray(16)
protected val modelMatrix = FloatArray(16)
protected val modelViewMatrix = FloatArray(16)
protected val mvpMatrix = FloatArray(16)
...
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 0f,
0f, 0f, -4f, 0f, 1.0f, 0.0f) // camera
...
// parameters different for portrait and landscape orientation screen android
Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far)
...
fun spotPosition() { // invoke on every frame
Matrix.setIdentityM(modelMatrix, 0)
Matrix.translateM(modelMatrix, 0, x, y, z) // move object
Matrix.rotateM(modelMatrix, 0, angleX, 0.0f, 1.0f, 0.0f) // rotate object
Matrix.scaleM(modelMatrix, 0, 4f, 4f, 4f) // scale object
Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0)
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0)
}
fun getMVPMatrixAsFloatBuffer(): FloatBuffer = floatBuffer(mvpMatrix)
get FloatBuffer (essential in Java SDK):
public static FloatBuffer floatBuffer(float[] data) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 4)
.order(ByteOrder.nativeOrder());
FloatBuffer returnBuffer = byteBuffer.asFloatBuffer();
returnBuffer.put(data).position(0);
return returnBuffer;
}

pass 2 textures to a single shader in opengl-es 2.0

I am using code from How can I pass multiple textures to a single shader?. It works fine until I load and bind new textures after my bumpmap image. I only can get this to work if my bumpmap is the last bound and loaded texture. Even if all my images are the same size. Here's my code...
public int[] textureIDs = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //texture image ID's
//load bitmap and bind texture (done 10 times) textureIndex is 1-10
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), imageiD);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIDs[textureIndex]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
//render
shaderProgram = GraphicTools.sp_ImageBump;
GLES20.glUseProgram(shaderProgram);
t1 = GLES20.glGetUniformLocation(shaderProgram, "u_texture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, globals.textureIDs[1]);//textureIndex
GLES20.glUniform1i(t1, 0);
t2 = GLES20.glGetUniformLocation(shaderProgram, "u_bumptex");
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, globals.textureIDs[2]);//bumpMapIndex);
GLES20.glUniform1i(t2, 1);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);//added this, it allows me to pass 2 textures to the shaders, otherwise TEXTURE1 is black
//fragment shader
precision mediump float;
uniform sampler2D u_bumptex;
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main()
{
vec4 bumpColor = texture2D(u_bumptex, v_texCoord);//v_bumpCoord);// get bump map color, just use green channel for brightness
gl_FragColor = texture2D(u_texture, v_texCoord) * bumpColor.g;
}

libgdx texture rendering on mesh and Affine Transformation

I am using libgdx to create a virtual trial room app. I am new to both Java and libgdx, so I might be wrong somewhere.
I plan to create a shader and a Mesh, and a texture is rendered on the Mesh(texture is a fabric of purple color with stripes). Then I plan to do affine transformation of very small triangles(shear, rotate, transform or translate) in the mesh to form a shirt(2D image) like below.
My idea is when the triangles transform, they take with them the part of texture with them, and the texture is modified.
Initially when I try to render the texture on the mesh, it shows a black screen instead of the purple fabric. My code:
public class MyAffineTransformation implements ApplicationListener {
Texture img;
String vertexShader;
String fragmentShader;
Mesh mesh;
ShaderProgram shader;
private float[] verts = new float[MAX_VERTS * NUM_COMPONENTS]; //Used to make triangles
private int idx = 0; //The index position
#Override
public void create() {
img = new Texture(Gdx.files.internal("fabric.jpg"));
img.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
img.setFilter(TextureFilter.Linear, TextureFilter.Linear);
mesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, POSITION_COMPONENTS, ShaderProgram.POSITION_ATTRIBUTE),
new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE));
mesh.setVertices(new float[] { -0.5f, -0.5f, 0.5f, -0.5f, 0, 0.5f });
mesh.setIndices(new short[] { 0, 1, 2 });
//Shader - vertex and fragment shader are posted below
vertexShader = Gdx.files.internal("affine.vert").readString();
fragmentShader = Gdx.files.internal("affine.frag").readString();
shader = new ShaderProgram(vertexShader, fragmentShader);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.graphics.getGL20().glEnable(GL20.GL_TEXTURE_2D);
img.bind();
mesh.render(shader, GL20.GL_TRIANGLES, 0, 3);
}
My Vertex Shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_texCoords = a_texCoord;
gl_Position = u_projTrans * a_position;
}
Fragment Shader:
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
varying LOWP vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main()
{
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}
It shows a black screen as of now. Please help me render texture on Mesh.
Also, when that happens, is it possible to do Affine transfotmation(rotation, translation, scaling, shearing etc) of small triangles in the mesh to form a 2D shirt. Please let me know if I am wrong somewhere.

Rendering an image texture into a cubemap in openGL android

I have a bitmap on my device(which is a 6x1 cubemap), which I want to render on all the faces of the cube
InputStream is = getContext().getResources().openRawResource(R.raw.photo);
Bitmap bitmap = BitmapFactory.decodeStream(is);
int bytes = bitmap.getByteCount();
ByteBuffer pixels = ByteBuffer.allocate(bytes);
bitmap.copyPixelsToBuffer(pixels);
Here is my vertex shader:
uniform mat4 uMVPMatrix;
uniform mat4 uSTMatrix;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;
attribute vec4 aColor;
varying vec2 vTextureCoord;
varying vec4 vColor;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = (uSTMatrix * aTextureCoord).xy;
vColor = aColor;
}
Here is my fragment shader:
precision mediump float;
varying vec2 vTextureCoord;
varying vec4 vColor;
uniform samplerCube sTexture;
void main() {
gl_FragColor = textureCube(sTexture, vec3(vTextureCoord, 1.0)) * vColor;
}
And here is what I am doing in my renderer in onSurfaceCreated():
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
int[] texIds = new int[1];
GLES20.glGenTextures(1, texIds, 0);
m360PhotoTextureId = texIds[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(
GLES20.GL_TEXTURE_CUBE_MAP,
mTextureId);
for (int i = 0 ; i < 6 ; i++ ){
pixels.position(0);
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0,
GLES20.GL_RGBA,
1,
1,
0,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
pixels);
}
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, 0);
All I see is a black screen in my texture view, when I expect to see a photo(in the pixels) being rendered on all the faces of the cube.
Any pointers or help would be appreciated.
I tried:
Vertex shader:
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
varying vec3 vTextureCoord;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = aPosition.xyz;
}
Fragment shader:
precision mediump float;
varying vec3 vTextureCoord;
uniform samplerCube sTexture;
void main() {
gl_FragColor = textureCube(sTexture, vTextureCoord);
}
But I get the same black screen.
A cubemap texture is a texture who's images represent the faces of a cube. The "texture coordinate" for a cubemap texture is the vector direction from the center of the cube which points to the color you want to use.
You are trying to use a regular old 2D texture coordinate, with a third component probably added to silence the compiler. You must provide directions, not 2D coordinates. You can generate them in the vertex shader from your position. But that requires knowing what space aPosition is, and you didn't tell me. So I can't show you how to do that.
Regardless, the vertex shader needs to be providing a 3D direction for the texture coordinate. It should either be generated or passed from a VS input.
Note that your program may have other problems. But this is the problem that can be deduced from your code.

Draw an Image based texture in openGl android(Wear)

I am drawing an image based texture using opengl in android, But the image is drawn partially only shown below
my coding
#Override
public void onGlContextCreated() {
super.onGlContextCreated();
shaders = new ShadersDla();
float[] vts = { // x, y, s, t.
-1, 1, 1, 1, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0
};
// AllocateDirect prevents the GC moving this memory.
vtBuffer = ByteBuffer.allocateDirect(vts.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vtBuffer.put(vts);
}
#Override
public void onGlSurfaceCreated(int width, int height) {
super.onGlSurfaceCreated(width, height);
float aspectRatio = (float) width / height;
float dist = .001f;
Matrix.frustumM(projectionMatrix, 0,
-aspectRatio * dist, aspectRatio * dist, // Left, right.
-dist, dist, // Bottom, top.
dist, 100); // Near, far.
makeTexture();
}
Shader
private static final String VERTEX_SHADER =
// Pass in the modelview matrix as a constant.
"uniform mat4 u_mvpMatrix; \n"
// Pass in the position and texture coordinates per vertex.
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
// Varyings are sent on to the fragment shader.
+ "varying vec2 v_texCoord; \n"
+ "void main() { \n"
// Transform the vertex coordinate into clip coordinates.
+ " gl_Position = u_mvpMatrix * a_position; \n"
// Pass through the texture coordinate.
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
Need some help to do this stuff.kindly guide me a easy way i'm new to android and opengl....
Change the texture coordinates as
{-1.0f, 1.0f, 0,0 ,
1.0f, 1.0f, 1,0,
-1.0f,-1.0f, 0,1 ,
1.0f, -1.0f, 1,1

Categories

Resources