2017-09-20 47 views
0

我正在基于其他纹理中的值投射阴影。我的阴影中的条纹

我的“深度”的质感,它不是真正的深度,这是为高采样只是颜色值,如下所示:

enter image description here

我们可以说,红色通道是我的高度图。

我就用下面的frag着色器全屏四画这个旁边一个草质地:

#version 400 

layout(location=0) out vec4 frag_colour; 

in vec2 texelCoords; 

uniform sampler2D uTexture; 
uniform sampler2D uTextureHeightmap; 
uniform float uSunDistance = -10000000.0; 
uniform float uSunInclination; 
uniform float uSunAzimuth; 
uniform float uQuality; 

void main() 
{ 
    vec4 c = texture(uTexture,texelCoords); 

    vec2 textureD = textureSize(uTexture,0); 
    float d = max(textureD.x,textureD.y); 
    float aspectCorrection = textureD.x/textureD.y; 

    vec3 sunPosition = vec3(textureD.x/2,textureD.y/2,0) + vec3( uSunDistance*sin(uSunInclination)*cos(uSunAzimuth), 
                    uSunDistance*sin(uSunInclination)*sin(uSunAzimuth), 
                    uSunDistance*cos(uSunInclination) ); 

    vec4 heights = texture(uTextureHeightmap, texelCoords); 
    float height = max(max(heights.r,heights.g),heights.b); 
    vec3 direction = normalize(vec3(texelCoords,height) - sunPosition); 
    direction.y *= aspectCorrection; 

    float sampleDistance = 0; 

    float samples = d*uQuality; 

    float stepSize = 1.0/((samples/d) * d); 

    for(int i = 0; i < samples; i++) 
    { 
     sampleDistance += stepSize; 

     vec3 newPoint = vec3(texelCoords,height) + direction * sampleDistance; 
     if(newPoint.z > 1.0) 
      break; 

     vec4 h = texture(uTextureHeightmap,newPoint.xy); 
     float base = h.r; 
     float middle = h.g; 
     float top = h.b; 

     if(newPoint.z < base) 
     { 
      c *= 0.5; 
      break; 
     } 
     if(newPoint.z >= middle && newPoint.z <= top) 
     { 
      c *= 0.5; 
      break; 
     } 
    } 

    frag_colour = c; 
} 

输出的样本是:

enter image description here

的条纹不想要的。我可以用更清晰的“边缘”代替平滑轮廓的相同方法,并且一切看起来都很棒。像这样的梯度会导致问题。

+0

你能解释你想要达到什么样的着色器吗?在没有任何提示的情况下搞清楚是非常困难的。 –

+0

@NicoSchertler着色器正沿着朝向太阳的方向前进;确定该步骤中的下一个像素是高于还是低于原始像素。如果它在上面,它表示原始像素必须处于阴影中,并将其设置为稍暗的颜色。 期望的效果是阴影 – NeomerArcana

+0

您是不是正在远离太阳(“方向”从太阳指向texel位置)?步长不应该依赖于'direction.z'(你想'样本'步骤导致最大高度)?您的纹理是否协调世界位置的x/y分量?地图高度是否直接代表世界高度(没有任何缩放比例)? –

回答

1

为了提高算法的质量,当然可以增加样本的数量。通过限制步伐距离,也可以实现质量改进。

步长的最小有意义距离由高度图的分辨率决定,因为对高度图的相同高度进行两次测试是没有意义的。

float d = max(textureD.x,textureD.y); 
float minStepSize = 1.0/d; 

如果光束从地面到太阳位置的距离达到1.0的高度,则达到最大有效距离。

heightmap maximum distance

一个步骤的距离给出,由样本的数目除以最大距离,但它应该至少由所述高度图的分辨率给定的最小距离:

float minStepSize = 1.0/d; 
float maxDist  = (1.0 - height) * length(direction.xy)/abs(direction.z); 
float stepSize = max(minStepSize, maxDist/samples); 
float shadow  = 1.0; 
vec3 startPoint = vec3(texelCoords, height); 
for (float sampleDist = stepSize; sampleDist <= maxDist; sampleDist += stepSize) 
{ 
    vec3 samplePoint = startPoint + direction * sampleDist; 
    vec4 sampleHeight = texture(uTextureHeightmap, samplePoint.xy); 
    if (samplePoint.z < sampleHeight.r) 
    { 
     shadow *= 0.5; 
     break; 
    } 
} 
frag_colour = vec4(c.rgb * shadow, c.a); 


对于软阴影算法,必须区分全阴影和阴影转换。为此,必须调查光束到高度图的距离。
如果有大的距离,那么该片段是在充满阴影:

heightmap full shadow

但在一个很小的距离的情况下,有一个阴影过渡:

heightmap shadow transition

阴影强度的指示是光束与高度图高度之间的最大距离。该距离可以通过采样点与高度图的最大高度差来计算。平滑阴影转换可以通过GLSL函数smoothstep来计算。

vec3 startPoint = vec3(texelCoords, height); 
float maxHeight = 0.0; 
for (float sampleDist = stepSize; sampleDist <= maxDist; sampleDist += stepSize) 
{ 
    vec3 samplePoint = startPoint + direction * sampleDist; 
    vec4 sampleHeight = texture(uTextureHeightmap, samplePoint.xy); 
    maxHeight   = max(maxHeight, sampleHeight.r - samplePoint.z); 
} 
const float minShadow  = 0.5; 
const float transitionHeight = 0.05; 
shadow = smoothstep(1.0, minShadow, clamp(maxHeight/transitionHeight, 0.0, 1.0)); 
fragColor = vec4(height, height * shadow, height, 1.0); 

在上面的代码中,变量maxHeight包含的最大距离,光束和高度图的高度之间。如果它大于0。0并且小于transitionHeight,则存在阴影过渡。如果它大于transitionHeight,则有完整的阴影。全影的强度由minShadow设置。

+0

感谢所有的信息@ Rabbid76,但它并没有真正解决条纹问题 – NeomerArcana