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);
Related
I am writing a custom blur shader,
"#include <common>",
// blur samples
"const int SAMPLES = 10;",
"uniform float radius;",
"uniform sampler2D tDiffuse;",
"varying vec2 vUv;",
"void main() {",
// sample the source
" vec2 uv = vUv;",
" vec4 cTextureScreen = texture2D( tDiffuse, vUv );",
" vec3 res = vec3(0);",
" for(int i = 0; i < SAMPLES; ++i) {",
" res += cTextureScreen.a;",
" vec2 d = vec2(0.5) - uv;",
" uv += d * radius;",
" }",
" gl_FragColor = vec4(res/float(SAMPLES), 1.0);",
"}"
Which is a straight port of: https://www.shadertoy.com/view/ltVSRK
For use with the effect composer of THREE.
Unfortunately, it appears that tDiffuse is not packed as rgb, and I am pretty confused as to how I can achieve the desired effect or the conversion I need.
See also the following question for more details:
what do texture2D().r and texture2D().a mean?
I ended up solving my problems (and working around them):
THREE uses a linear colorspace for textures inside (effect composer) shaders.
It provides conversion utilities, such as LinearTosRGB.
My code above contains an error. The effect of the line vec4 cTextureScreen = texture2D( tDiffuse, vUv ); should be repeated inside the for loop in order to properly resample fragments while zooming outward.
I ended up using a more elaborate shader, drawn from the Wagner effects library: https://github.com/spite/Wagner/blob/master/fragment-shaders/zoom-blur-fs.glsl#L1
uniform sampler2D tInput;
uniform vec2 center;
uniform float strength;
uniform vec2 resolution;
varying vec2 vUv;
float random(vec3 scale,float seed){return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);}
void main(){
vec4 color=vec4(0.0);
float total=0.0;
vec2 toCenter=center-vUv*resolution;
float offset=random(vec3(12.9898,78.233,151.7182),0.0);
for(float t=0.0;t<=40.0;t++){
float percent=(t+offset)/40.0;
float weight=4.0*(percent-percent*percent);
vec4 sample=texture2D(tInput,vUv+toCenter*percent*strength/resolution);
sample.rgb*=sample.a;
color+=sample*weight;
total+=weight;
}
gl_FragColor=color/total;
gl_FragColor.rgb/=gl_FragColor.a+0.00001;
}
And I am also looking at fast and efficient implementations of Gaussian Blur (https://github.com/Jam3/glsl-fast-gaussian-blur) to further soften my current results.
All in all, my original issue was the result of both a bug in my own code, and of THREE using a linear colorspace for textures.
I want to add a very simply lighting effect in my models via shaders. I found out there a vertex and a fragment shaders that make the work on OpenGL:
static const char* vertSource = {
"uniform vec3 lightPosition;\n"
"varying vec3 normal, eyeVec, lightDir;\n"
"void main()\n"
"{\n"
" vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
" eyeVec = -vertexInEye.xyz;\n"
" lightDir = vec3(lightPosition - vertexInEye.xyz);\n"
" normal = gl_NormalMatrix * gl_Normal;\n"
" gl_Position = ftransform();\n"
"}\n"
};
static const char* fragSource = {
"uniform vec4 lightDiffuse;\n"
"uniform vec4 lightSpecular;\n"
"uniform float shininess;\n"
"varying vec3 normal, eyeVec, lightDir;\n"
"void main (void)\n"
"{\n"
" vec4 finalColor = gl_FrontLightModelProduct.sceneColor;\n"
" vec3 N = normalize(normal);\n"
" vec3 L = normalize(lightDir);\n"
" float lambert = dot(N,L);\n"
" if (lambert > 0.0)\n"
" {\n"
" finalColor += lightDiffuse * lambert;\n"
" vec3 E = normalize(eyeVec);\n"
" vec3 R = reflect(-L, N);\n"
" float specular = pow(max(dot(R, E), 0.0), shininess);\n"
" finalColor += lightSpecular * specular;\n"
" }\n"
" gl_FragColor = finalColor;\n"
"}\n"
};
The problem is that I am working in OpenGL ES2, because I am developing an Android app. And it seems that the in-built variable gl_FrontLightModelProduct is not available for GLES20, because I am having compilation fails in this line.
My question therefore is: How I can modify the above shaders to make them work in a OpenGL ES20 context?
gl_FrontLightModelProduct.sceneColor gives the Ambient colour of the scene which can be 0 if you want the area which is not affected by light to be fully black. You can replace that with a vec4(0.0, 0.0, 0.0, 1.0);
You should also remove these variables and send them as uniforms.
gl_ModelViewMatrix (send as uniform)
gl_Vertex (read this from attributes)
gl_NormalMatrix (send as uniform)
gl_Normal (read this from attributes)
Or instead of fighting in converting OpenGL shader, you can search for Simple OpenGL ES 2.0 shaders
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.
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);
I'm shadering a picture with GL20.GL_POINTS. One of the attribution of the points is variable('vKind'in the code). When the attribution changed I should change the Texture simultaneously. The follow is my method. But I got a low fps. What should I do? Any help thanks!
final String fragmentShader = "precision highp float;\n"
+ "uniform sampler2D u_texture0;\n" // diffuse texture for
+ "uniform sampler2D u_texture1;\n" // diffuse texture for
+ "uniform sampler2D u_texture2;\n" // diffuse texture for
+ "uniform sampler2D u_texture3;\n" // diffuse texture for
+ "uniform sampler2D u_texture4;\n" // diffuse texture for
+ "uniform sampler2D u_texture5;\n" // diffuse texture for
+ "uniform sampler2D u_texture6;\n" // diffuse texture for
+ "uniform sampler2D u_texture7;\n" // diffuse texture for
+ "varying float vRotation;\n"
+ "varying float vKind;\n"
+ "varying vec4 vColor;\n" // input color from vertex shader
+ "void main() {\n"
+ "highp vec2 center = vec2(0.5, 0.5);\n"
// Translate the center of the point the origin.
+ "highp vec2 centeredPoint = gl_PointCoord - center;\n"
// Create a rotation matrix using the provided angle
+ "highp mat2 rotation = mat2(cos(vRotation), sin(vRotation),\n"
+ "-sin(vRotation), cos(vRotation)); \n"
// Perform the rotation.
+ "centeredPoint = centeredPoint*rotation ;\n"
// Translate the point back to its original position and use
// that point
// to get your texture color.
+ "if(vKind==0.0)\n"
+ "gl_FragColor = texture2D(u_texture0, centeredPoint + center);\n"
+ "else if(vKind==1.0)\n"
+ "gl_FragColor = texture2D(u_texture1, centeredPoint + center);\n"
+ "else if(vKind==2.0)\n"
+ "gl_FragColor = texture2D(u_texture2, centeredPoint + center);\n"
+ "else if(vKind==3.0)\n"
+ "gl_FragColor = texture2D(u_texture3, centeredPoint + center);\n"
+ "else if(vKind==4.0)\n"
+ "gl_FragColor = texture2D(u_texture4, centeredPoint + center);\n"
+ "else if(vKind==5.0)\n"
+ "gl_FragColor = texture2D(u_texture5, centeredPoint + center);\n"
+ "else if(vKind==6.0)\n"
+ "gl_FragColor = texture2D(u_texture6, centeredPoint + center);\n"
+ "else\n"
+ "gl_FragColor = texture2D(u_texture7, centeredPoint + center);\n"
+ "gl_FragColor *= vColor;\n"
// +
// " gl_FragColor.a = (gl_FragColor.b >= 0.5) ? gl_FragColor.a : 0.0;\n"
+ "}\n";
First of all try to analyze the situation if the textures are indeed what holds you down: Comment out all but 1 texture and make all the if statements call the same texture. Then after you have confirmed consider 2 things:
Since you are drawing points do you really need a varying for vKind or is that an uniform. You can use 8 draw calls by separating your points into 8 arrays on the CPU depending on which texture should they use and then use only 1 texture in your fragment shader and bind the correct one before every one of the 8 draw calls.
If you truly need all of this texture data try looking into how to use atlas (merge multiple textures into one) and try to reduce the texture count as much as possible.