I'm trying to save world space coordinates form fragment shader gl_FragColor output to a texture to use later on using frame buffer but it doesn't seem to work correctly
what is the correct way to do it?
//create method
fbo = new FrameBuffer(Pixmap.Format.RGB888, 256,256,true, true);
//render method
fbo.begin();
Gdx.gl.glViewport(0, 0, fbo.getWidth(), fbo.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl20.glEnable(GL20.GL_BLEND);
fisrtShader.begin();
fisrtShader.end();
fbo.end();
texture = fbo.getColorBufferTexture();
texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
texture.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
textureRegion = new TextureRegion(texture);
textureRegion.flip(false, true);
the shader:
//vertex shader
#ifdef GL_ES
precision mediump float;
#endif
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projViewTrans;
varying vec2 v_texCoord0;
varying vec3 worldSpaceCoords;
void main() {
worldSpaceCoords = a_position + vec3(.5,.5,.5);
v_texCoord0 = a_texCoord0;
gl_Position = u_projViewTrans * u_worldTrans * vec4(a_position, 1.0);
}
//fragment shader
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord0;
varying vec3 worldSpaceCoords;
void main() {
gl_FragColor = vec4(worldSpaceCoords.x , worldSpaceCoords.y, worldSpaceCoords.z, 1);
}
Related
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.
My code:
public void draw1(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to shape's transformation matrix
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// get handle to vertex shader's vPosition member
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
mNormalHandle = GLES20.glGetAttribLocation(mProgram, "a_normal");//new line
fsTexture = GLES20.glGetUniformLocation(mProgram, "Texture");
vsTextureCoord = GLES20.glGetAttribLocation(mProgram, "texCoord");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glUniform1i(fsTexture, 0);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glVertexAttribPointer(vsTextureCoord, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
TextureStride, texBuffer);
GLES20.glEnableVertexAttribArray(vsTextureCoord);
GLES20.glVertexAttribPointer(mNormalHandle, COORDS_PER_NORMAL, GLES20.GL_FLOAT, false,
12, normalbuffer);//new line
GLES20.glEnableVertexAttribArray(mNormalHandle);//new line
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, tablelamp21NumVerts);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(vsTextureCoord);
GLES20.glDisableVertexAttribArray(mNormalHandle);//new line
}
so i am getting a glGetUniformLocation: glError 1281 at MyGLRenderer.checkGlError("glGetUniformLocation"); code line
after debugging i found that my mNormalHandle is -1 i.e GLES20.glGetAttribLocation(mProgram, "a_normal"); is returning -1, even though i using it in the vertex shader and i am using GLES20.glBindAttribLocation(mProgram, 2, "a_normal"); before linking please help.
shaders code:
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"uniform mat4 u_MVMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 texCoord;" +
"attribute vec3 a_normal;"+ //new line
"varying vec3 v_normal;"+//new line
"varying vec2 texCoordOut;" +
"void main() {" +
" v_normal = vec3(u_MVMatrix * vec4(a_normal, 0.0));"+
" texCoordOut = texCoord;" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D Texture;" +
"varying vec2 texCoordOut;"+
"void main() {" +
" gl_FragColor = texture2D(Texture, texCoordOut);" +
"}";
Sorry to answer to an outdated question, but if that can help other developers: I think the GLSL compiler is pretty good to strip unused variables.
For example, with the follow vertex and fragment shader compiled with the OpenGL/ES driver of an Android emulator:
private val vertexShaderCode = """attribute vec4 in_position;
attribute vec2 in_texcoord;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
varying vec2 var_texcoord;
void main() {
var_texcoord = in_texcoord;
gl_Position = projection * view * model * in_position;
}
"""
private val fragmentShaderCode = """
precision mediump float;
varying vec2 var_texcoord;
uniform sampler2D texture;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
"""
GLES20.glGetAttribLocation(program, "in_texcoord"); will return -1
Now if we use var_texcoord to compute the color in the fragment shader:
private val fragmentShaderCode = """
precision mediump float;
varying vec2 var_texcoord;
uniform sampler2D texture;
uniform vec4 color;
void main() {
gl_FragColor = texture2D(texture, var_texcoord);
}
"""
GLES20.glGetAttribLocation(program, "in_texcoord"); will return a valid id, > -1
Apparently the GLSL compiler can strip variable and varying variable, if they are not used, so it's seems possible that your a_normal variable is removed too.
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.
I am trying to use Android Color Matrix in OpenGL ES 2. I have been able to use a 4x4 Matrix using the following code in the Shader (this adds also an intensity parameter):
varying vec2 textureCoordinate;
uniform lowp mat4 colorMatrix;
uniform lowp float intensity;
void main()
{
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
vec4 outputColor = textureColor * colorMatrix;
gl_FragColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);
}
But i am struggling on how i could convert Android 4x5 matrix to a vec4 matrix usable in the shader. I am not interested in Alpha channel.
The most direct approach is probably to split the ColorMatrix into a mat4 and a vec4, where the mat4 contains the multipliers for the input components, and the vec4 the constant offsets.
One detail to watch out for is the order of the matrix elements in memory. OpenGL uses column major storage, where the ColorMatrix appears to be in row major order. But it looks like you're already correcting for this discrepancy by multiplying the input vector from the right in the shader code.
The shader code will then look like this:
uniform lowp mat4 colorMatrix
uniform lowp vec4 colorOffset;
...
vec4 outputColor = textureColor * colorMatrix + colorOffset;
In the Java code, say you have a ColorMatrix named mat:
ColorMatrix mat = ...;
float[] matArr = mat.getArray();
float[] oglMat = {
matArr[0], matArr[1], matArr[2], matArr[3],
matArr[5], matArr[6], matArr[7], matArr[8],
matArr[10], matArr[11], matArr[12], matArr[13],
matArr[15], matArr[16], matArr[17], matArr[18]};
// Set value of colorMatrix uniform using oglMat.
float[] oglOffset = {matArr[4], matArr[9], matArr[14], matArr[19]};
// Set value of colorOffset uniform using oglOffset.
I'm implementing skeletal animation in my android phone, and here is how I do it:
Calcualte all bone transformation matrices on the CPU side
Create a float texture to store these matrices (so this is done at the beginning of each frame). The codes look like below:
if(texID) {
glDeleteTextures(1, &texID);
texID = 0;
}
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, p);
In vertex shader, fetch matrix from this texture and apply to vertex position
This approach works fine in my Motorola Milestone XT-701 using a POWERVR GPU. But when I run it on a Qualcomm snapdragon (SE Xperia X10i and Google Nexus one), there are many triangles disappeared (looks randomly), so it seems the model is flickering.
I also tried to reduce the scene complexity by rendering only one animated model, and the flicker become less but still exists. Does anyone know what I may be doing wrong? Is this some kind of synchronization problem?
You can see the snapshots here (the first two pictures is correct, and the later two are wrong). The APK file of my grogram can be downloaded here. (it does not require any permission so don't worry)
Here is the vertex shader I used:
struct light {
lowp vec4 position; // light position for a point/spot light or
// normalized dir. for a directional light
lowp vec4 ambient_color;
lowp vec4 diffuse_color;
lowp vec4 specular_color;
lowp vec3 spot_direction;
lowp vec3 attenuation_factors;
lowp float spot_exponent;
lowp float spot_cutoff_angle;
bool compute_distance_attenuation;
};
struct material {
lowp vec4 ambient_color;
lowp vec4 diffuse_color;
lowp vec4 specular_color;
lowp vec4 emissive_color;
lowp float specular_exponent;
};
// uniforms used by the vertex shader
// uniform vec4 u_color;
uniform highp mat4 u_mvMatrix;
uniform highp mat4 u_projMatrix;
uniform bool u_enable_lighting;
uniform light u_light_state;
uniform material u_material_state;
uniform bool u_enable_texture;
uniform highp sampler2D s_jointTex; // use highp for float texture
// attributes input to the vertex shader
// attribute lowp vec4 a_color;
attribute highp vec3 a_position;
attribute lowp vec3 a_normal;
attribute mediump vec2 a_texCoord;
attribute highp float a_jointID;
// varying variables – input to the fragment shader
varying lowp vec4 v_front_color;
varying mediump vec2 v_texCoord;
vec2 mapTo2D(float idx)
{
vec2 st = vec2(idx + 0.5, 0.5);
return st / 256.0;
}
void main()
{
mat4 joint = mat4(1.0);
if(a_jointID >= 0.0)
{
float idx = a_jointID * 4.0;
joint = mat4( texture2D(s_jointTex, mapTo2D(idx)),
texture2D(s_jointTex, mapTo2D(idx+1.0)),
texture2D(s_jointTex, mapTo2D(idx+2.0)),
texture2D(s_jointTex, mapTo2D(idx+3.0)) );
gl_Position = (u_projMatrix * u_mvMatrix) * joint * vec4(a_position, 1.0); // hint compiler to extract uniform calculation
// v_front_color = vec4(1.0, 0.0, 0.0, 1.0);
}
else
{
gl_Position = (u_projMatrix * u_mvMatrix) * vec4(a_position, 1.0); // hint compiler to extract uniform calculation
// v_front_color = vec4(0.0, 1.0, 0.0, 1.0);
}
if(u_enable_lighting)
{
lowp vec4 computed_color = vec4(0.0);
vec3 normal = normalize( vec3(u_mvMatrix * joint * vec4(a_normal, 0.0) ) );
vec3 lightDir = normalize( vec3(u_mvMatrix * u_light_state.position) );
float NdotL = max(dot(normal, lightDir), 0.0);
computed_color += u_light_state.ambient_color * u_material_state.ambient_color + NdotL * u_light_state.diffuse_color * u_material_state.diffuse_color;
if(NdotL > 0.0) {
vec3 half_vec = normalize(lightDir + vec3(0.0, 0.0, 1.0)); // why?
float NdotHV = dot(normal, half_vec);
if(NdotHV > 0.0)
computed_color += u_light_state.specular_color * u_material_state.specular_color * pow(NdotHV, u_material_state.specular_exponent);
}
v_front_color = computed_color;
}
else
v_front_color = vec4(1.0, 1.0, 1.0, 1.0); // u_material_state.ambient_color; // TODO?
v_texCoord = a_texCoord;
}
Re-creating a texture each frame is not efficient. You can use the same texID and just call glTexImage* each frame.
Why don't you use 1D texture? It would remove a burden of tex-coord conversion to 2D.
Your joint matrix is 4x4, but you store it as 4 GL_RGBA vectors. This internal format does allow only [0,1] range, which is not appropriate for your task. Try using GL_RGBA_16f as internal format instead.