Custom ssao in Three.js - three.js

I am trying to finish a ssao shader from a tutorial: http://www.nutty.ca/?page_id=352&link=ssao
I use multi-pass render in three.js.
There is a similar question in stackoverflow SSAO artefacts in Three, and I find we learned from the same tutorial.
I follow the tutorial in detail, I do not know which texture I render is totally wrong. Does anybody have some idea? thank you!
As following the tutorial,
I store the whole scene in a color tDiffusion texture:
,
store a view-space position to a tPosition texture:
,
store view-space linear depth to a tDepth texture:
,
the Shader are like this:
"custom_vsPosition" :{
uniforms:{
"cameraNear": { type: "f", value: 1.0 },
"cameraFar": { type: "f", value: 100.0 }
},
vertexShader:[
"varying vec4 mvPosition;", //View-space position
"void main() {",
// Calculate and include linear depth
" mvPosition = modelViewMatrix * vec4(position, 1.0);",
" gl_Position = projectionMatrix * mvPosition;",
"}"
].join("\n"),
fragmentShader:[
"uniform float cameraNear;",
"uniform float cameraFar;",
"varying vec4 mvPosition;", //View-space position
"void main() {",
" float linearDepth = length(mvPosition) / (cameraFar - cameraNear);",
" linearDepth = clamp(linearDepth, 0.0, 1.0);",
" gl_FragColor = vec4(mvPosition.xyz, linearDepth);",
"}"
].join("\n")
},
store view-space normal vector to a tNormal texture:
,
"custom_vsNormal" :{
uniforms:{
},
vertexShader:[
"varying vec3 vNormal ;",
"void main(void) {",
" vNormal = normalMatrix * normal ;", //transforming the normal vector into view
//space and then scaling and biasing the vector components
" gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
"}"
].join("\n"),
fragmentShader:[
"varying vec3 vNormal ;", //Normal transform
"void main() {",
" gl_FragColor = vec4(normalize( vNormal ).xyz, 1.0);",
"}"
].join("\n")
},
And then based on the tDepth, tPosition and tNormal to calculate the ao.
However, the Ao seems wrong. Comparing my texture to the turtorial, I do not find where is wrong. From SSAO artefacts in Three, Maybe there where problem in Normal generating. But I really generate the view-space normal.
only Ao picture:
Ao with color scene:
SSAO shader from the tutorial:
"custom_NVD_SSAOShader":
{
uniforms: {
"tDiffuse": { type: "t", value: null }, // Render texture
"tPosition": { type: "t", value: null }, // View space position data
"tNormal": { type: "t", value: null }, // View space normal vectors
"tNoise": { type: "t", value: null },// Normalmap to randomize the sampling kernel
"size": { type: "v2", value: new THREE.Vector2( 512, 512 ) },
"occluderBias": { type: "f", value: 0.005 }, // Occluder bias to minimize self-occlusion.
"samplingRadius": { type: "f", value: 20 }, // Specifies the size of the sampling radius.
"cAttenuation": { type: "v3", value: new THREE.Vector3( 1, 1.5, 0 ) },
"onlyAo": { type: "f", value: 0.0 },
"lumInfluence": { type: "f", value: 0.9 }
// Ambient occlusion attenuation values. These parameters control the amount of AO calculated based on distance to the occluders. You need to play with them to find the right balance.
// .x = constant attenuation. This is useful for removing self occlusion. When
// set to zero or a low value, you will start to notice edges or wireframes
// being shown. Typically use a value between 1.0 and 3.0.
// .y = linear attenuation. This provides a linear distance falloff.
// .z = quadratic attenuation. Smoother falloff, but is not used in this shader.
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"#define sampleCount 16",
"#define patternSize 4.0",
"varying vec2 vUv;",
"uniform sampler2D tDiffuse;",
"uniform sampler2D tPosition;",
"uniform sampler2D tNormal;",
"uniform sampler2D tNoise;", //input random noise for random sampling
"uniform vec2 size;",
"uniform float occluderBias;",
"uniform float samplingRadius;",
"uniform vec3 cAttenuation;",
"uniform float onlyAo;",
"uniform float lumInfluence;",
"const vec3 onlyAOColor = vec3( 1.0, 0.7, 0.5 );",
"float SamplePixels (vec3 srcPosition, vec3 srcNormal, vec2 uv)",
"{",
// Get the 3D position of the destination pixel
" vec3 dstPosition = texture2D(tPosition, uv).xyz;",
// Calculate ambient occlusion amount between these two points
// It is simular to diffuse lighting. Objects directly above the fragment cast
// the hardest shadow and objects closer to the horizon have minimal effect.
" vec3 positionVec = dstPosition - srcPosition;",
" float intensity = max(dot(normalize(positionVec), srcNormal)- occluderBias, 0.0);",
" float dist = length(positionVec);",
" float attenuation = 1.0 / (cAttenuation.x + (cAttenuation.y * dist));",
" return intensity * attenuation;",
"}",
"vec2 texelSize = vec2(0.5 , 0.5);",
/*
// These are the Poisson Disk Samples
"vec2 getPoisson16(int i){;",
"vec2 poisson16;",
"if(i==0)",
" poisson16 = vec2( -0.94201624, -0.39906216 );",
"else if(i==1)",
" poisson16 = vec2( 0.94558609, -0.76890725 );",
"else if(i==2)",
" poisson16 = vec2( -0.094184101, -0.92938870 );",
"else if(i==3)",
" poisson16 = vec2( 0.34495938, 0.29387760 );",
"else if(i==4)",
" poisson16 = vec2( -0.91588581, 0.45771432 );",
"else if(i==5)",
" poisson16 = vec2( -0.81544232, -0.87912464 );",
"else if(i==6)",
" poisson16 = vec2( -0.38277543, 0.27676845 );",
"else if(i==7)",
" poisson16 = vec2( 0.97484398, 0.75648379 );",
"else if(i==8)",
" poisson16 = vec2( 0.44323325, -0.97511554 );",
"else if(i==9)",
" poisson16 = vec2( 0.53742981, -0.47373420 );",
"else if(i==10)",
" poisson16 = vec2( -0.26496911, -0.41893023 );",
"else if(i==11)",
" poisson16 = vec2( 0.79197514, 0.19090188 );",
"else if(i==12)",
" poisson16 = vec2( -0.24188840, 0.99706507 );",
"else if(i==13)",
" poisson16 = vec2( -0.81409955, 0.91437590 );",
"else if(i==14)",
" poisson16 = vec2( 0.19984126, 0.78641367 );",
"else if(i==15)",
" poisson16 = vec2( 0.14383161, -0.14100790 );",
"return poisson16;",
"}",
*/
"void main ()",
"{",
// Get position and normal vector for this fragment
" vec3 srcPosition = texture2D(tPosition, vUv).xyz;",
" float srcDepth = texture2D(tPosition, vUv).w;",
" vec3 srcNormal = texture2D(tNormal, vUv).xyz;",
/*
" float ao = 0.0;",
" float kernelRadius = samplingRadius * (1.0 - srcDepth);",
" for(int i =0; i < sampleCount; ++i)",
" {",
" ao += SamplePixels(srcPosition, srcNormal, vUv + getPoisson16(i) * kernelRadius);",
" }",
" ao /= 16.0;",
" ao = clamp(ao, 0.0, 1.0);",
" ao = 1.0 - ao;",
*/
" vec2 randVec = normalize(texture2D(tNoise, vUv).xy * 2.0 - 1.0);",
" float kernelRadius = samplingRadius * (1.0 - srcDepth);",
" vec2 kernel[4];",
" kernel[0] = vec2(0.0, 1.0);", // top",
" kernel[1] = vec2(1.0, 0.0);", // right
" kernel[2] = vec2(0.0, -1.0);", // bottom
" kernel[3] = vec2(-1.0, 0.0);", // left
" const float Sin45 = 0.707107;", // 45 degrees = sin(PI / 4)
" float ao = 0.0;",
" for (int i = 0; i < 4; ++i)",
" {",
" vec2 k1 = reflect(kernel[i], randVec);",
" vec2 k2 = vec2(k1.x * Sin45 - k1.y * Sin45,",
" k1.x * Sin45 + k1.y * Sin45);",
" k1 *= texelSize;",
" k2 *= texelSize;",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k1 * kernelRadius);",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k2 * kernelRadius * 0.75);",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k1 * kernelRadius * 0.5);",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k2 * kernelRadius * 0.25);",
" }",
" ao /= 16.0;",
" ao = clamp(ao, 0.0, 1.0);",
" ao = 1.0 - ao;",
" vec3 color = texture2D( tDiffuse, vUv ).rgb;",
"if ( onlyAo == 1.0 )",
" gl_FragColor.xyz = vec3( ao, ao, ao );",
"else if ( onlyAo == 2.0 )",
" gl_FragColor.xyz = vec3( srcNormal.x, srcNormal.y, srcNormal.z );",
"else if ( onlyAo == 3.0 )",
" gl_FragColor.xyz = vec3( srcDepth, srcDepth, srcDepth );",
"else if ( onlyAo == 4.0 )",
" gl_FragColor.xyz = vec3( srcPosition.x, srcPosition.y, srcPosition.z );",
"else if ( onlyAo == 5.0 )",
" gl_FragColor.xyz = color;",
"else",
"{",
" gl_FragColor.xyz = color * ao;",
"}",
"gl_FragColor.w = 1.0;",
"}"
].join("\n")
}

Related

Vertex and Fragment shaders for lighting effect in OpenGL ES20

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

THREE.js custom shader with predefined lights

I have following BlendShader made based on THREE.BlendShader and AlteredQualia JupiterShader. I am struggling with adding Directional Light to the material with this shader. I have read this tutorial but it still does render fully lit object, without taking directional light into consideration. I probably do something wrong at last row when defining the gl_FragColor but can't figure out what it is. Please help. Thank you.
FragmentShader :
"#if NUM_DIR_LIGHTS > 0",
"uniform vec3 directionalLightColor[NUM_DIR_LIGHTS];",
"uniform vec3 directionalLightDirection[NUM_DIR_LIGHTS];",
"#endif",
"uniform float opacity;",
"uniform float mixRatio;",
"uniform float staticRatio;",
"uniform sampler2D tDiffuse1;",
"uniform sampler2D tDiffuse2;",
"uniform sampler2D tDiffuse3;",
"varying vec2 vUv;", // = uv
// vNormal is worldNormal calculated in vertex shader as follows:
// "vec3 worldNormal = mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal ;",
// "vNormal = normalize( worldNormal );",
"varying vec3 vNormal;",
"void main() {",
"vec4 texel1 = texture2D( tDiffuse1, vUv );", // frame i
"vec4 texel2 = texture2D( tDiffuse2, vUv );", // frame i + 1
"vec4 texel3 = texture2D( tDiffuse3, vUv );", //static texture
"texel1.xyz = pow( texel1.xyz, vec3( 1.7 ) );", // gamma correction
"texel2.xyz = pow( texel2.xyz, vec3( 1.7 ) );", // gamma correction
"float m = 1.0;",
"float m1 = smoothstep( 0.23, 0.3, vUv.y );", //
"float m2 = 1.0 - smoothstep( 0.75, 0.82, vUv.y );",
"m = m1 * m2;",
"vec4 dynamic = mix( texel1, texel2, mixRatio );", // mixing two frames
//directional light
"vec4 sumDirLights = vec4(0.0, 0.0, 0.0, 1.0);",
"#if NUM_DIR_LIGHTS > 0",
"for( int i = 0; i < NUM_DIR_LIGHTS; i++ ) {",
"vec3 dir = directionalLightDirection[i];",
"sumDirLights.rgb += clamp( dot( -dir, vNormal ), 0.0, 1.0 ) * directionalLightColor[i];",
"}",
"#endif",
"gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * sumDirLights + ( opacity * mix( texel3, dynamic, staticRatio * m ) ) ;",
"}"

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

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