How do I allocate an array in an OpenGL fragment shader? - opengl-es

Here is the fragment shader code I am trying to use (in OpenGL ES 2.0, OpenGLES GLSL ES 1.00):
GLchar strFragmentShader[] =
"precision mediump float; \n"
"varying vec2 vTexCoord; \n"
"uniform sampler2D sTexture; \n"
"uniform float offset[] = float[]( 0.0000, 1.3846, 3.2307); \n"
"uniform float weight[] = float[]( 0.2270, 0.3162, 0.0702); \n"
"void main() \n"
"{ \n"
" vec4 sum = texture2D( sTexture, vec2(vTexCoord)/1024.0)*weight[0]; \n"
" for (int i=0;i<3;i++) { \n"
" sum += texture2D( sTexture, ( vec2(vTexCoord+vec2(0.0,offset[i])/1024.0 )*weight[i]; \n"
" sum += texture2D( sTexture, ( vec2(vTexCoord-vec2(0.0,offset[i])/1024.0 )*weight[i]; \n"
" } \n"
" gl_FragColor = sum; \n"
"} \n";
I am basically following the examples on this page, but I get ERROR:LEX/PARSE-1 (fragment shader, line 4) Syntax error.
If I try to declare them as const rather than uniform as suggested here (under Array Constructors), I get ERROR:CUSTOM-5 (fragment shader, line 4) Array cannot be const.
Obviously lines 4 and 5 will have the same problem. How do I get this to compile? What is the correct syntax?

I'd do it like this:
GLchar strFragmentShader[] =
"precision mediump float; \n"
"varying vec2 vTexCoord; \n"
"uniform sampler2D sTexture; \n"
"void main() \n"
"{
" vec3 offset = vec3(0.0000, 1.3846, 3.2307); \n"
" vec3 weight = vec3( 0.2270, 0.3162, 0.0702); \n" \n"
" vec4 sum = texture2D( sTexture, vec2(vTexCoord)/1024.0)*weight[0]; \n"
" for (int i=0;i<3;i++) { \n"
" sum += texture2D( sTexture, ( vec2(vTexCoord+vec2(0.0,offset[i])/1024.0 )*weight[i]; \n"
" sum += texture2D( sTexture, ( vec2(vTexCoord-vec2(0.0,offset[i])/1024.0 )*weight[i]; \n"
" } \n"
" gl_FragColor = sum; \n"
"}"
or this if you need it passed to the shader as a uniform:
GLchar strFragmentShader[] =
"precision mediump float; \n"
"varying vec2 vTexCoord; \n"
"uniform sampler2D sTexture; \n"
"uniform vec3 offset; \n"
"uniform vec3 weight; \n"
"void main() \n"
"{ \n"
" vec4 sum = texture2D( sTexture, vec2(vTexCoord)/1024.0)*weight[0]; \n"
" for (int i=0;i<3;i++) { \n"
" sum += texture2D( sTexture, ( vec2(vTexCoord+vec2(0.0,offset[i])/1024.0 )*weight[i]; \n"
" sum += texture2D( sTexture, ( vec2(vTexCoord-vec2(0.0,offset[i])/1024.0 )*weight[i]; \n"
" } \n"
" gl_FragColor = sum; \n"
"}"
or use uniform float[n] where n is the desired (constant) size in the second example if you need an array, or const float[n] in the first example if you need an array and you don't want to pass the value from your C++ code.

Turns out that this is just a limitation of GLES. It can't be done. An alternative method needs to be found.

Related

No depth buffer on framebuffer when using shadow mapping

I have got shadow mapping working nice on android but there is a problem - shadows 'leak'. So imagine a cylinder imbedded in the floor of a terrain with some portion under that terrain. The portion above creates a nice shadow opposite to the light source but the potion under the terrain casts a shadow forwards - towards the light. Its as if there is no depth buffer.
Here is my frambuffer code (where i think the problem is).
MyGLRenderer.shadowsize=4096;
GLES20.glGenTextures(1, temp2qshadow, 0);
LoadIntroPics.fboTexqshadow = temp2qshadow[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTexqshadow);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, MyGLRenderer.shadowsize, MyGLRenderer.shadowsize/2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_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);
GLES20.glGenFramebuffers(1, tempqshadow, 0);
MyGLRenderer.fboIdshadow = tempqshadow[0];
GLES20.glGenRenderbuffers(1, temp3qshadow, 0);
LoadIntroPics.renderBufferIdqshadow = temp3qshadow[0];
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferIdqshadow);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, MyGLRenderer.shadowsize, MyGLRenderer.shadowsize/2);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, MyGLRenderer.fboIdshadow);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, LoadIntroPics.fboTexqshadow);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER,LoadIntroPics.renderBufferIdqshadow);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, LoadIntroPics.fboTexqshadow, 0);
And this is the shadow map code....
protected String getVertexShaderShadow()//this needs a model view projection matrix
{
final String vertexShader =
"precision highp float; \n"
+"attribute vec4 a_Position; \n"
+"uniform mat4 u_MVPMatrix; \n"
//+"uniform mat4 u_ShadowMatrix; \n"
+"attribute vec2 a_TexCoordinate; \n"
+"varying vec2 v_TexCoordinate; \n"
+"varying vec4 v_v4TexCoord; \n"
+"void main() \n"
+"{ \n"
+"v_TexCoordinate = a_TexCoordinate; \n"
+"gl_Position =u_MVPMatrix * a_Position; \n"
+"v_v4TexCoord = u_MVPMatrix * a_Position; \n"
+"} \n";
return vertexShader;
}
protected void getFragmentShaderShadow()
{
final String fragmentShader =
"precision highp float; \n"
+"uniform sampler2D u_Texture; \n"
+"uniform int decal; \n"
+"varying vec2 v_TexCoordinate; \n"
+"varying vec4 v_v4TexCoord; \n"
+"void main() \n"
+"{ \n"
+"vec4 col=texture2D(u_Texture, v_TexCoordinate); \n"
+"if(decal==1){if(col.r<=0.25 && col.g<=0.25 && col.b<=0.25)discard;} \n"
+"if(decal==2){if(col.r<=0.05 && col.g<=0.05 && col.b<=0.05)discard;} \n"
/* Generate shadow map - write fragment depth. */
+"float value = 10.0 - v_v4TexCoord.z; \n"
+"float v = floor(value); \n"
+"float f = value - v; \n"
+"float vn = v * 0.1; \n"
+"gl_FragColor = vec4(vn, f, 0.0, 1.0); \n"
//+"gl_FragColor=vec4(1.0,1.0,1.0,1.0); \n"
+"} \n";
fragmentShaderHandle =compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
MyGLRenderer.mPerVertexProgramHandleShadow = createAndLinkProgram(MyGLRenderer.vertexShaderHandleShadow, fragmentShaderHandle,
new String[] {"a_Position", "a_Color", "a_Normal", "a_TexCoordinate"});
}
And ideas? Thanks
Here is a snapshot.

cannot see textures from inside a sphere opengl-es

I am learning opengl es 2, and I have a sphere with a texture. I have no problems to see it from outside, but if i put the camera inside, all I see is dark. I tried to solve this with:
GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK);
But I still see a black screen. It is due to light? what can I do to see the texture from inside the sphere?
These are the shaders:
final String vertexShader =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "varying vec2 vTexCoord; \n"
+ "attribute vec2 vTexCoord0; \n"
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
+ " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position.
+ " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in
+ " vTexCoord = vTexCoord0; \n"
+ "} \n"; // normalized screen coordinates.
final String fragmentShader =
"precision mediump float; \n"
+ "varying vec2 vTexCoord; \n"
+ "uniform sampler2D sTexture; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( sTexture, vTexCoord );\n"
+ "}
GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK);
tells it to cull (not show) both front and back-facing tris. You shouldn't see anything from either inside or outside with that setting. Try "NONE" instead.
GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK); means you want it to cull (i.e. not render) both the front AND back. It's hard to imagine a situation where anyone would ever want to do that.
To turn off culling in C, you'd need to do
glDisable(GL_CULL_FACE);
I presume for your Java binding the command looks like
GLES20.glDisable(GLES20.GL_CULL_FACE);

OpenGL ES 2.0 and glError 0x502 ? (using Vuforia)

Can someone please advise what's wrong with the following OpenGL ES 2.0 code? I'm using the Vuforia Augmented Reality SDK and I want to draw line with one end one colour, then fading into the colour of the other end.
GLES20.glUseProgram(shaderProgramID);
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT, false, 0, line_vertices_buffer);
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glVertexAttribPointer(colorHandle, 3, GLES20.GL_FLOAT, false, 0, line_colours_buffer);
GLES20.glEnableVertexAttribArray(colorHandle);
GLES20.glBindAttribLocation(shaderProgramID, colorHandle, "color");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures.get(2).mTextureID[0]);
Matrix.multiplyMM(modelViewProjection, 0, vuforiaAppSession.getProjectionMatrix().getData(), 0, modelViewMatrix, 0);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, modelViewProjection, 0);
GLES20.glUniform1i(colorHandle, 0);
GLES20.glLineWidth(30);
GLES20.glDrawArrays(GLES20.GL_LINES, 0, 2 + line_vertices_array.size());
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisableVertexAttribArray(vertexHandle);
GLES20.glDisableVertexAttribArray(colorHandle);
The gradient doesn't appear. Ubuntu Eclipse LogCat states the following error which is related to the glUniform1i(colorHandle, 0) command near the end of the code.
06-06 09:13:57.340: E/Vuforia_Sample_Applications(14175): After operation UserDefinedTargets renderFrame got glError 0x502
06-06 09:13:57.390: W/Adreno-ES20(14175): <__load_uniform_int:351>: GL_INVALID_OPERATION
Does anyone know how to fix this error?
The shaders are given by:
String frameVertexShader = " \n" + "attribute vec4 vertexPosition; \n"
+ "attribute vec2 vertexTexCoord; \n" + "\n"
+ "varying vec2 texCoord; \n" + "\n"
+ "uniform mat4 modelViewProjectionMatrix; \n" + "\n"
+ "void main() \n" + "{ \n"
+ "gl_Position = modelViewProjectionMatrix * vertexPosition; \n"
+ "texCoord = vertexTexCoord; \n" + "} \n";
String frameFragmentShader = " \n" + "precision mediump float; \n" + "\n"
+ "varying vec2 texCoord; \n" + "\n"
+ "uniform sampler2D texSampler2D; \n" + "uniform vec4 keyColor; \n"
+ "\n" + "void main() \n" + "{ \n"
+ "vec4 texColor = texture2D(texSampler2D, texCoord); \n"
+ "gl_FragColor = keyColor * texColor; \n" + "} \n" + "";
I tried changing "color" to "keyColor" in my main code, but still get the error, i.e.
GLES20.glBindAttribLocation(shaderProgramID, colorHandle, "color");
to
GLES20.glBindAttribLocation(shaderProgramID, colorHandle, "keyColor");
I also made sure my buffer has 4 floats for RGBA since the fragment shader seems to expect this in keyColor.
NB Vuforia does seem to use ByteBuffer even for the float array, and then we use putFloat into the ByteBuffer, e.g.
line_colours_buffer = ByteBuffer.allocateDirect(4 * 4 * (2 + line_vertices_array.size()));
line_colours_buffer.order(ByteOrder.LITTLE_ENDIAN);
line_colours_buffer.putFloat(1f); // colour for line start
line_colours_buffer.putFloat(0f);
line_colours_buffer.putFloat(0f);
line_colours_buffer.putFloat(0.5f);
line_colours_buffer.putFloat(0f); // colour for line start
line_colours_buffer.putFloat(1f);
line_colours_buffer.putFloat(0f);
line_colours_buffer.putFloat(0.5f);
... + other lines as required.

opengles offsetting texture co-ordinates in a shader

I'm using a texture altas and this vertex shader to render a texture on a quad:
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec4 a_Color;" +
"attribute vec2 a_texCoord;" +
"varying vec4 v_Color;" +
"varying vec2 v_texCoord;" +
"uniform vec4 u_newColor;" +
"void main() {" +
" float offset = 0.33;" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_texCoord.x = a_texCoord.x + offset;" +
" v_texCoord.y = a_texCoord.y + offset;" +
" v_Color = u_newColor;" +
"}";
Everything is working fine and I render a third in to the texture showing a middle tile of 9 in the atlas. Except I want 'offset' to be a variable i.e. I want to change it depending on which 'tile' I need in the texture atlas.
How would this be possible?
add a uniform and use that:
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec4 a_Color;" +
"attribute vec2 a_texCoord;" +
"varying vec4 v_Color;" +
"varying vec2 v_texCoord;" +
"uniform vec4 u_newColor;" +
"uniform vec2 u_offset ;" + //vec2 so there is a x and y component that you can set
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_texCoord = a_texCoord + u_offset;" +
" v_Color = u_newColor;" +
"}";
and you set the uniform with
glUniform2f(u_offset_location, xTile, yTile);

GLSL bypassing float array to uniform

setShaders
muOffsetHandle = getUniformLocation("offset");
muWeightHandle = getUniformLocation("weight");
useProgram
GLES20.glUniform1fv(muOffsetHandle, 1, mOffset, 0);
GLES20.glUniform1fv(muWeightHandle, 1, mWeight, 0);
vars
private int muOffsetHandle;
private int muWeightHandle;
protected float mOffset[] =new float[] {0.0f, 1.3f, 3.3f};
protected float mWeight[] =new float[] {0.2f, 0.3f, 0.3f};
FragmentShader
"uniform float offset[3];\n" +
"uniform float weight[3];\n" +
then trying to reach: weight[i]
I get this:
Shader log: 0:13: S0004: Member reference or swizzle attempted on non-structure and non-vector
line 13: tc += texture2D(uFrameBufferTexture, vTextureCoord[0].xy + vec2(0.0, offset[i])/uScreenHeight).rgb * weight[i];
(i = 0 to 2)
so my question: How to bypassing a float array to a uniform? float[3]
the code
protected static final String mFShader =
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform float uTime;\n" +
"uniform float uScreenWidth;\n" +
"uniform float uScreenHeight;\n" +
"uniform sampler2D uFrameBufferTexture;\n"+
"uniform float offset[3];\n" +
"uniform float weight[3];\n" +
"void main() {\n"+
" vec3 tc = vec3(1.0, 0.0, 0.0);\n"+
" if (vTextureCoord[0].x<(uTime-0.01)) {\n"+
" tc = texture2D(uFrameBufferTexture, vTextureCoord[0].xy).rgb * weight[0];\n"+
" for (int i=1; i<3; i++) {\n"+
" tc += texture2D(uFrameBufferTexture, vTextureCoord[0].xy + vec2(0.0, offset[i])/uScreenHeight).rgb * weight[i];\n"+
" tc += texture2D(uFrameBufferTexture, vTextureCoord[0].xy - vec2(0.0, offset[i])/uScreenHeight).rgb * weight[i];\n"+
" }\n"+
" }\n"+
" else if (vTextureCoord[0].x>=(uTime+0.01)) {\n"+
" tc = texture2D(uFrameBufferTexture, vTextureCoord[0].xy).rgb;\n"+
" }\n"+
" gl_FragColor = vec4(tc, 1.0);\n"+
"}\n";
The problem isn't actually with weight or offset. The compiler is complaining that you say vTextureCoord[0].xy, but you declared vTextureCoord as varying vec2 vTextureCoord;.
Either declare vTextureCoord as an array, or don't say [0].
You don't need to declare it as an array, but if you want you can simply use:
varying vec4 vTextureCoord[3]; // you can use anything you want between the brackets
Also, don't forget to modify the varying the the vertex shader too so that they will be identical.

Resources