为什么我的片段着色器水平投射长阴影而垂直投射短阴影?
Why is my frag shader casting long shadows horizontally and short shadows vertically?
我有以下片段着色器:
#version 330
layout(location=0) out vec4 frag_colour;
in vec2 texelCoords;
uniform sampler2D uTexture; // the color
uniform sampler2D uTextureHeightmap; // the heightmap
uniform float uSunDistance = -10000000.0; // really far away vertically
uniform float uSunInclination; // height from the heightmap plane
uniform float uSunAzimuth; // clockwise rotation point
uniform float uQuality; // used to determine number of steps and steps size
void main()
{
vec4 c = texture(uTexture,texelCoords);
vec2 textureD = textureSize(uTexture,0);
float d = max(textureD.x,textureD.y); // use the largest dimension to determine stepsize etc
// position the sun in the centre of the screen and convert from spherical to cartesian coordinates
vec3 sunPosition = vec3(textureD.x/2,textureD.y/2,0) + vec3( uSunDistance*sin(uSunInclination)*cos(uSunAzimuth),
uSunDistance*sin(uSunInclination)*sin(uSunAzimuth),
uSunDistance*cos(uSunInclination) );
float height = texture2D(uTextureHeightmap, texelCoords).r; // starting height
vec3 direction = normalize(vec3(texelCoords,height) - sunPosition); // sunlight direction
float sampleDistance = 0;
float samples = d*uQuality;
float stepSize = 1.0 / ((samples/d) * d);
for(int i = 0; i < samples; i++)
{
sampleDistance += stepSize; // increase the sample distance
vec3 newPoint = vec3(texelCoords,height) + direction * sampleDistance; // get the coord for the next sample point
float newHeight = texture2D(uTextureHeightmap,newPoint.xy).r; // get the height of that sample point
// put it in shadow if we hit something that is higher than our starting point AND is heigher than the ray we're casting
if(newHeight > height && newHeight > newPoint.z)
{
c *= 0.5;
break;
}
}
frag_colour = c;
}
目的是根据高度图投射阴影。非常漂亮,结果看起来不错。
但是,存在一个问题,即阴影在水平方向比垂直方向显得更长。如果我使 window 尺寸不同,window 高比宽,我会得到相反的效果。即,阴影在更长的维度上投射的时间更长。
这告诉我这与我在上述着色器中的步进方式有关,但我不能说出问题。
为了说明,这里有一个 uSunAzimuth
会产生水平投射的阴影:
下面是完全相同的代码,其中 uSunAzimuth
用于垂直阴影:
它在这些低分辨率图像中不是很明显,但在较大的分辨率中效果会变得更加夸张。本质上;当您测量它如何在所有 360 度方位角上投射时,阴影会清除椭圆而不是圆形。
我只是需要稍微调整一下方向。
float aspectCorrection = textureD.x / textureD.y;
...
vec3 direction = normalize(vec3(texelCoords,height) - sunPosition);
direction.y *= aspectCorrection;
阴影片段着色器在视口的 "snapshot" 上运行。渲染场景并生成此 "snapshot" 时,顶点位置将由投影矩阵转换。投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射,并考虑了视口的纵横比。
(参见 、
和 ).
这会导致高图 (uTextureHeightmap
) 表示一个矩形视场,具体取决于纵横比。
但是用于访问高度贴图的纹理坐标描述了范围为 (0, 0) 到 (1, 1) 的四边形。
这种不匹配必须通过缩放纵横比来平衡。
vec3 direction = ....;
float aspectRatio = textureD.x / textureD.y;
direction.xy *= vec2( 1.0/aspectRatio, 1.0 );
我有以下片段着色器:
#version 330
layout(location=0) out vec4 frag_colour;
in vec2 texelCoords;
uniform sampler2D uTexture; // the color
uniform sampler2D uTextureHeightmap; // the heightmap
uniform float uSunDistance = -10000000.0; // really far away vertically
uniform float uSunInclination; // height from the heightmap plane
uniform float uSunAzimuth; // clockwise rotation point
uniform float uQuality; // used to determine number of steps and steps size
void main()
{
vec4 c = texture(uTexture,texelCoords);
vec2 textureD = textureSize(uTexture,0);
float d = max(textureD.x,textureD.y); // use the largest dimension to determine stepsize etc
// position the sun in the centre of the screen and convert from spherical to cartesian coordinates
vec3 sunPosition = vec3(textureD.x/2,textureD.y/2,0) + vec3( uSunDistance*sin(uSunInclination)*cos(uSunAzimuth),
uSunDistance*sin(uSunInclination)*sin(uSunAzimuth),
uSunDistance*cos(uSunInclination) );
float height = texture2D(uTextureHeightmap, texelCoords).r; // starting height
vec3 direction = normalize(vec3(texelCoords,height) - sunPosition); // sunlight direction
float sampleDistance = 0;
float samples = d*uQuality;
float stepSize = 1.0 / ((samples/d) * d);
for(int i = 0; i < samples; i++)
{
sampleDistance += stepSize; // increase the sample distance
vec3 newPoint = vec3(texelCoords,height) + direction * sampleDistance; // get the coord for the next sample point
float newHeight = texture2D(uTextureHeightmap,newPoint.xy).r; // get the height of that sample point
// put it in shadow if we hit something that is higher than our starting point AND is heigher than the ray we're casting
if(newHeight > height && newHeight > newPoint.z)
{
c *= 0.5;
break;
}
}
frag_colour = c;
}
目的是根据高度图投射阴影。非常漂亮,结果看起来不错。
但是,存在一个问题,即阴影在水平方向比垂直方向显得更长。如果我使 window 尺寸不同,window 高比宽,我会得到相反的效果。即,阴影在更长的维度上投射的时间更长。
这告诉我这与我在上述着色器中的步进方式有关,但我不能说出问题。
为了说明,这里有一个 uSunAzimuth
会产生水平投射的阴影:
下面是完全相同的代码,其中 uSunAzimuth
用于垂直阴影:
它在这些低分辨率图像中不是很明显,但在较大的分辨率中效果会变得更加夸张。本质上;当您测量它如何在所有 360 度方位角上投射时,阴影会清除椭圆而不是圆形。
我只是需要稍微调整一下方向。
float aspectCorrection = textureD.x / textureD.y;
...
vec3 direction = normalize(vec3(texelCoords,height) - sunPosition);
direction.y *= aspectCorrection;
阴影片段着色器在视口的 "snapshot" 上运行。渲染场景并生成此 "snapshot" 时,顶点位置将由投影矩阵转换。投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射,并考虑了视口的纵横比。
(参见
和
这会导致高图 (uTextureHeightmap
) 表示一个矩形视场,具体取决于纵横比。
但是用于访问高度贴图的纹理坐标描述了范围为 (0, 0) 到 (1, 1) 的四边形。
这种不匹配必须通过缩放纵横比来平衡。
vec3 direction = ....;
float aspectRatio = textureD.x / textureD.y;
direction.xy *= vec2( 1.0/aspectRatio, 1.0 );