Пользовательский ssao в Three.js

Я пытаюсь закончить шейдер ssao из учебника: http://www.nutty.ca/?page_id=352&link=ssao Я использую многопроходный рендеринг в three.js. Есть аналогичный вопрос в stackoverflow артефакты SSAO в Three, и я считаю, что мы узнали из того же руководство. Я внимательно следую инструкциям, я не знаю, какую текстуру я визуализирую совершенно неправильно. У кого-нибудь есть идеи? спасибо! Следуя руководству, я сохраняю всю сцену в цветной текстуре tDiffusion: введите здесь описание изображения, сохраняйте представление -space position в текстуру 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 кажется неправильным. Сравнивая свою текстуру с туториалом, не нахожу, где не так. Из артефактов SSAO в Three, возможно, проблема в нормальном создании. Но я действительно генерирую нормальное пространство просмотра. только изображение Ao: введите здесь описание изображенияAo с цветной сценой: введите здесь описание изображения Шейдер 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")
}

person yongnan    schedule 07.06.2014    source источник
comment
В одном из ваших комментариев обсуждается масштабирование и смещение нормали, вычисленной в вершинном шейдере, но на самом деле этого никогда не происходит. Вы записываете нормаль пространства просмотра непосредственно в gl_FragColor, что, вероятно, не очень хорошая идея, если только вы не используете SNORM (не думаю, что WebGL поддерживает это) или текстуру с плавающей запятой.   -  person Andon M. Coleman    schedule 07.06.2014
comment
О, сначала я использую другой метод, а тот забыл удалить, извините за это. Я не масштабирую и не смещаю текстуру нормалей. Как вы думаете, может ли моя текстура пространства просмотра, текстура нормали, текстура глубины быть неправильной? Спасибо! Да, я записываю нормаль пространства просмотра непосредственно в gl_FragColor и использую THREE.js WebGLRenderer({preserveDrawingBuffer: true}), чтобы сохранить нормаль к текстуре для дальнейшего прохода. WebGL имеет расширение OES_texture_float, это расширение представляет собой текстуру с плавающей запятой.   -  person yongnan    schedule 07.06.2014
comment
Что ж, в пространстве обзора компоненты X и Y любой нормали могут быть отрицательными. Если вы не смещаете и не масштабируете нормаль перед записью в обычную текстуру (до сих пор не знаю, есть ли она у вас), то это означает, что значения зажимаются [0,1]. Вы теряете половину своего координатного пространства, потому что оно отбрасывает отрицательные значения.   -  person Andon M. Coleman    schedule 07.06.2014
comment
спасибо, я думаю, это может быть проблемой, я не считаю минус нормальным, я проверю.   -  person yongnan    schedule 07.06.2014