Vertex and Fragment shaders for lighting effect in OpenGL ES20 - opengl-es

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

Related

How to use RGB for tDiffuse in customer fragment shader with THREE.js

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.

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);

Convert a shader to OpenGL 2.x?

I have some OpenGL 2.x code on which I want to run these shaders:
static const char* YUYV_VS = ""
"#version 150\n"
"uniform mat4 u_pm;"
"uniform mat4 u_mm;"
"in vec4 a_pos;"
"in vec2 a_tex;"
"out vec2 v_tex;"
"void main() {"
" gl_Position = u_pm * u_mm * a_pos; "
" v_tex = a_tex;"
"}"
"";
static const char* YUYV_FS = ""
"#version 150\n"
"uniform sampler2D u_tex;"
"out vec4 outcol;"
"in vec2 v_tex;"
"const vec3 R_cf = vec3(1.164383, 0.000000, 1.596027);"
"const vec3 G_cf = vec3(1.164383, -0.391762, -0.812968);"
"const vec3 B_cf = vec3(1.164383, 2.017232, 0.000000);"
"const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
"void main() {"
" vec3 tc = texture( u_tex, v_tex ).rgb;"
" vec3 yuv = vec3(tc.g, tc.b, tc.r);"
" yuv += offset;"
" outcol.r = dot(yuv, R_cf);"
" outcol.g = dot(yuv, G_cf);"
" outcol.b = dot(yuv, B_cf);"
" outcol.a = 1.0;"
"}"
"";
Trouble is, OpenGL 2.x doesn't support shaders of version 150. Does anyone have an idea how I would back-convert the shaders to 2.x?
Use this procedure except start at GLSL 1.50 spec instead of the 1.30 one.
File shader.vsh
uniform mat4 u_pm;
uniform mat4 u_mm;
attribute vec4 a_pos;
attribute vec2 v_tex;
varying vec2 fragmentTextureCoordinates;
void main() {
gl_Position = u_pm * u_mm * a_pos;
fragmentTextureCoordinates = v_tex;
}
File shader.fsh
uniform sampler2D u_tex;
varying vec2 fragmentTextureCoordinates;
const vec3 R_cf = vec3(1.164383, 0.000000, 1.596027);
const vec3 G_cf = vec3(1.164383, -0.391762, -0.812968);
const vec3 B_cf = vec3(1.164383, 2.017232, 0.000000);
const vec3 offset = vec3(-0.0625, -0.5, -0.5);
void main() {
vec3 tc = texture2D(u_tex, fragmentTextureCoordinates).rgb;
vec3 yuv = vec3(tc.g, tc.b, tc.r);
yuv += offset;
gl_FragColor.r = dot(yuv, R_cf);
gl_FragColor.g = dot(yuv, G_cf);
gl_FragColor.b = dot(yuv, B_cf);
gl_FragColor.a = 1.0;
}
Would that work? You may have to adapt the variables you pass to your program/technique/shaders.

multi textures in fragment shader. I got a low fps

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.

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