チュートリアルから ssao シェーダーを完成させようとしています: http://www.nutty.ca/?page_id=352&link=ssao 私は three.js でマルチパス レンダーを使用します。Threeのstackoverflow SSAOアーティファクトにも同様の質問があり、同じチュートリアルから学んだことがわかりました。チュートリアルに詳しく従いますが、レンダリングするテクスチャが完全に間違っているかわかりません。誰かアイデアがありますか?ありがとう!チュートリアルに従って、シーン全体をカラー tDiffusion テクスチャ に保存します: 、ビュー空間の位置を tPosition テクスチャ に保存します: 、ビュー空間の線形深度を tDepth テクスチャに保存します: 、シェーダーは次のようになります。
"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")
},
ビュー空間の法線ベクトルを tNormal テクスチャに保存: ,
"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")
},
次に、tDepth、tPosition、および tNormal に基づいて ao を計算します。
しかし、青は間違っているようです。私のテクスチャをチュートリアルと比較すると、どこが間違っているのかわかりません。Three の SSAO アーティファクトから、通常の生成に問題がある可能性があります。しかし、実際にはビュー空間法線を生成します。Ao 画像のみ: Ao with color scene: チュートリアルの SSAO シェーダー: "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")
}