Opengl es 三件SSAO工艺品

Opengl es 三件SSAO工艺品,opengl-es,three.js,glsl,ssao,Opengl Es,Three.js,Glsl,Ssao,我真的很难用我的SSAO着色器修复一个问题,可能需要一些帮助。基本上,着色器似乎在某些对象上工作,但在其他对象上看起来非常糟糕。从下面可以看到球体看起来是正确的,但立方体似乎在法线上进行遮挡,而它不应该这样做。以下是一个屏幕截图: 我的着色器基于本教程: 在我的渲染链中,我渲染了2个渲染目标,它们将在稍后的一些后期处理效果中使用。其中一个存储位置和深度。另一个存储法线。两个目标都是浮动纹理 下面是每个步骤的屏幕截图 这是我的位置/深度着色器: uniform sampler2D tDiff

我真的很难用我的SSAO着色器修复一个问题,可能需要一些帮助。基本上,着色器似乎在某些对象上工作,但在其他对象上看起来非常糟糕。从下面可以看到球体看起来是正确的,但立方体似乎在法线上进行遮挡,而它不应该这样做。以下是一个屏幕截图:

我的着色器基于本教程:

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

下面是每个步骤的屏幕截图

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

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;

}
顶点着色器:

varying vec4 vPosition;
.....
vPosition = mvPosition;
varying vec3 vNormal;
...
vec3 transformedNormal = normalMatrix * objectNormal;
vNormal = transformedNormal;
Frag着色器:

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);
这是普通着色器:

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;

}
顶点着色器:

varying vec4 vPosition;
.....
vPosition = mvPosition;
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;

}
uniform sampler 2d tDiffuse;//原始场景纹理
均匀采样2D t位置;//查看空间位置数据
均匀采样2D t正常值;//视图空间法向量
均匀采样2d t噪声;//Normalmap以随机化采样内核
均匀vec2纹理;
///封堵器偏差,以最大限度地减少自遮挡。
均匀浮动闭塞偏倚;
///指定采样半径的大小。
均匀浮动采样梯度;
均匀浮动;
/// 
///环境遮挡衰减值。
///这些参数控制基于距离计算的AO量
///到封堵器。你需要和他们一起玩才能找到正确的平衡。
///
///.x=恒定衰减。这对于移除自遮挡非常有用。什么时候
///设置为零或低值时,您将开始注意边或线框
///正在放映。通常使用介于1.0和3.0之间的值。
///
///.y=线性衰减。这将提供线性距离衰减。
///.z=二次衰减。平滑衰减,但不在此着色器中使用。
/// 
均匀vec2衰减;
/// 
///可变变量。
/// 
可变vec2 vUv;
/// 
///在以下UV坐标处对环境光遮挡进行采样。
/// 
///正在测试的源像素的3D位置。
///正在测试的源像素的法线。
///UV坐标用于环境遮挡的采样/测试。
///环境遮挡量。
浮点采样像素(vec3 srcPosition、vec3 srcNormal、vec2 uv)
{
//获取目标像素的三维位置
vec3 dstPosition=纹理2d(tPositions,uv).xyz;
//计算这两点之间的环境光遮挡量
//它类似于漫射光。碎片正上方的物体投射
//最硬的阴影和靠近地平线的对象的效果最小。
vec3位置VEC=dstPosition-srcPosition;
浮动强度=最大值(点(归一化(位置向量),SRCENORMAL)-遮挡偏差,0.0);
//衰减遮挡,类似于衰减光源的方式。
//点之间的距离越远,AO对碎片的影响越小。
浮动距离=长度(位置向量);
浮动衰减=1.0/(衰减.x+(衰减.y*dist));
回波强度*衰减;
}
/// 
///片段着色器条目。
/// 
空干管()
{
//获取此片段的位置和法向量
vec3 srcPosition=texture2D(tPositions,vUv).xyz;
vec3 srchnormal=texture2D(tNormals,vUv).xyz;
vec2 randVec=规格化(纹理2d(tNoise,vUv).xy*2.0-1.0);
浮动深度=纹理2d(t位置,vUv).w;
//下面的变量指定了我们在每次扫描后跳过的像素数
//环境光遮挡循环中的迭代。我们无法对其中的每个像素进行采样
//因为这太慢了,我们只需要取样
//附近的一些随机像素接近解决方案。
//
//距离较远的像素不会像距离较近的像素那样采样。
浮点核半径=采样梯度*(1.0-深度);
//采样相邻像素
vec2内核[4];
内核[0]=vec2(0.0,1.0);//顶部
内核[1]=vec2(1.0,0.0);//对
内核[2]=vec2(0.0,-1.0);//底部
内核[3]=vec2(-1.0,0.0);//左
常数浮点Sin45=0.707107;//45度=sin(π/4)
//从16个像素中采样,这应该足以接近结果
//从更多像素采样,但这是以性能为代价的。
浮动闭塞=0.0;
对于(int i=0;i<4;++i)
{
vec2 k1=反射(内核[i],randVec);
vec2 k2=vec2(k1.x*Sin45-k1.y*Sin45,
k1.x*Sin45+k1.y*Sin45);
k1*=纺织尺寸;
k2*=纺织尺寸;
遮挡+=采样像素(srcPosition、SRCPnormal、vUv+k1*核半径);
遮挡+=采样像素(srcPosition、SRCPnormal、vUv+k2*核半径*0.75);
遮挡+=采样像素(srcPosition、SRCPnormal、vUv+k1*核半径*0.5);
遮挡+=采样像素(srcPosition、SRCPnormal、vUv+k2*核半径*0.25);
}
//平均和钳制环境遮挡
闭塞/=16.0;
闭塞=钳夹(闭塞,0.0,1.0);
//混合两者
vec3颜色=纹理2d(扩散,vUv).xyz;
//颜色=夹具(颜色-闭塞,0.0,1.0);
闭塞=1.0-闭塞;
//gl_FragColor.xyz=功率(颜色,vec3(1.0/2.2));
if(onlyAO==1.0)
gl_FragColor.xyz=vec3(遮挡,遮挡,遮挡);
否则如果(仅限==2.0)
gl_FragColor.xyz=vec3(srchnormal.x,srchnormal.y,srchnormal.z);
否则如果(仅限==3.0)
gl_FragColor.xyz=vec3(srcDepth,srcDepth,srcDepth);
其他的
{
////混合两者
//颜色=夹具(颜色-闭塞,0.0,1.0);
////应用伽马校正
//gl_FragColor.xyz=功率(颜色,vec3(1.0/2.2));
//gl_FragColor.w=1.0;
gl_FragColor.xyz=颜色*遮挡;
}
gl_FragColor.w=1.0;
}

看起来法线与立方体表面不垂直,这可能会导致