SSAO 文物三 [英] SSAO artefacts in Three

查看:15
本文介绍了SSAO 文物三的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的很难解决我的 SSAO 着色器的问题,并且可以拼命寻求帮助.基本上,着色器似乎适用于某些对象,但在其他对象上看起来非常糟糕.从下面您可以看到球体看起来是正确的,但立方体似乎在法线上进行了不应该遮挡的遮挡.截图如下:

I'm really struggling to fix an issue with my SSAO shader and could desperately use some help. Basically the shader seems to work on some objects, but looks really bad on others. From the below you can see the sphere looks correct, but the cube seems to be doing occlusion on normals that it shouldn't. Here is a screenshot:

我的着色器基于本教程:http://devmaster.net/posts/3095/shader-效果屏幕空间环境遮挡

I am basing my shaders off of this tutorial: http://devmaster.net/posts/3095/shader-effects-screen-space-ambient-occlusion

在我的渲染链中,我渲染了 2 个渲染目标,这些目标稍后会在一些后期处理效果中使用.其中之一存储位置和深度.另一个存储法线.两个目标都是浮动纹理.

In my render chain I render 2 render targets which get used in some post process effects later on. One of them stores the position and depth. The other stores the normals. Both targets are float textures.

这是每个步骤的屏幕截图.

Here is a screenshot of each of the steps.

这是我的位置/深度着色器:

顶点着色器:

varying vec4 vPosition;
.....
vPosition = mvPosition;

片段着色器:

uniform float linearDepth; //Cam far - cam near
varying vec4 vPosition;
...
float ld = length(vPosition) / linearDepth;
gl_FragColor = vec4(vPosition.x, vPosition.y, vPosition.z, ld);

这是普通的着色器:

顶点着色器:

varying vec3 vNormal;
...
vec3 transformedNormal = normalMatrix * objectNormal;
vNormal = transformedNormal;

片段着色器:

gl_FragColor = vec4( normalize( vNormal ).xyz, 1.0);

这是我的 SSAO 片段着色器:

uniform sampler2D tDiffuse;    // The original scene texture
uniform sampler2D tPositions;    // View space position data
uniform sampler2D tNormals;    // View space normal vectors
uniform sampler2D tNoise;    // Normalmap to randomize the sampling kernel
uniform vec2 texelSize;

/// Occluder bias to minimize self-occlusion.
uniform float occluderBias;

/// Specifies the size of the sampling radius.
uniform float samplingRadius;

uniform float onlyAO;

/// <summary>
/// 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.
/// <summary>
uniform vec2 attenuation;


/// <summary>
/// Varying variables.
/// <summary>
varying vec2 vUv;

/// <summary>
/// Sample the ambient occlusion at the following UV coordinate.
/// <summary>
/// <param name=srcPosition>3D position of the source pixel being tested.</param>
/// <param name=srcNormal>Normal of the source pixel being tested.</param>
/// <param name=uv>UV coordinate to sample/test for ambient occlusion.</param>
/// <returns>Ambient occlusion amount.</returns>
float SamplePixels (vec3 srcPosition, vec3 srcNormal, vec2 uv)
{
    // Get the 3D position of the destination pixel
    vec3 dstPosition = texture2D(tPositions, 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);

    // Attenuate the occlusion, similar to how you attenuate a light source.
    // The further the distance between points, the less effect AO has on the fragment.
    float dist = length(positionVec);
    float attenuation = 1.0 / (attenuation.x + (attenuation.y * dist));

    return intensity * attenuation;
}


/// <summary>
/// Fragment shader entry.
/// <summary>
void main ()
{
    // Get position and normal vector for this fragment
    vec3 srcPosition = texture2D(tPositions, vUv).xyz;
    vec3 srcNormal = texture2D(tNormals, vUv).xyz;
    vec2 randVec = normalize(texture2D(tNoise, vUv).xy * 2.0 - 1.0);
    float srcDepth = texture2D(tPositions, vUv).w;

    // The following variable specifies how many pixels we skip over after each
    // iteration in the ambient occlusion loop. We can't sample every pixel within
    // the sphere of influence because that's too slow. We only need to sample
    // some random pixels nearby to apprxomate the solution.
    //
    // Pixels far off in the distance will not sample as many pixels as those close up.
    float kernelRadius = samplingRadius * (1.0 - srcDepth);

    // Sample neighbouring pixels
    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)

    // Sample from 16 pixels, which should be enough to appromixate a result. You can
    // sample from more pixels, but it comes at the cost of performance.
    float occlusion = 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;

        occlusion += SamplePixels(srcPosition, srcNormal, vUv + k1 * kernelRadius);
        occlusion += SamplePixels(srcPosition, srcNormal, vUv + k2 * kernelRadius * 0.75);
        occlusion += SamplePixels(srcPosition, srcNormal, vUv + k1 * kernelRadius * 0.5);
        occlusion += SamplePixels(srcPosition, srcNormal, vUv + k2 * kernelRadius * 0.25);
    }

    // Average and clamp ambient occlusion
    occlusion /= 16.0;
    occlusion = clamp(occlusion, 0.0, 1.0);

// Blend the two 
vec3 colour =  texture2D(tDiffuse, vUv).xyz;
//colour = clamp(colour - occlusion, 0.0, 1.0);

occlusion = 1.0 - occlusion;

//gl_FragColor.xyz = pow(colour, vec3(1.0 / 2.2));
if ( onlyAO == 1.0 )
    gl_FragColor.xyz = vec3( occlusion, occlusion, occlusion );
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
{
    //// Blend the two 
    //colour = clamp(colour - occlusion, 0.0, 1.0); 

    //// Apply gamma correction 
    //gl_FragColor.xyz = pow(colour, vec3(1.0 / 2.2)); 
    //gl_FragColor.w = 1.0;

    gl_FragColor.xyz = colour * occlusion;
}

gl_FragColor.w = 1.0;

}

推荐答案

看起来法线不垂直于立方体的表面,这可能是来自 shading 参数的问题材料.

It looks like normals aren't perpendicular to the surface of the cube, that might be the issue coming from shading param of the material.

尝试为材质的 shading 选项设置 THREE.FlatShading 参数.

Try setting THREE.FlatShading param for shading option for material.

这篇关于SSAO 文物三的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆