我有以下片段着色器:
#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;
}
目的是根据高度图投射阴影。非常漂亮,结果看起来不错。
但是,与垂直相比,阴影在水平时显得更长。如果我使窗口大小不同,窗口高于宽,我会得到相反的效果。即,阴影在较长的维度上投射更长。
这告诉我这与我踩到上面着色器的方式有关,但我不能说出问题。
为了说明,这里是uSunAzimuth
导致水平投射阴影:
以下是与垂直阴影uSunAzimuth
完全相同的代码:
在这些低分辨率图像中并不是很明显,但在较大的分辨率下,效果会更加夸张。实质上;当你测量它在360度方位角上投射的方式时,阴影会清除椭圆而不是圆形。
答案 0 :(得分:1)
我只需稍微调整方向。
float aspectCorrection = textureD.x / textureD.y;
...
vec3 direction = normalize(vec3(texelCoords,height) - sunPosition);
direction.y *= aspectCorrection;
答案 1 :(得分:1)
阴影片段着色器在视口的“快照”上运行。渲染场景并生成此“快照”时,顶点位置将由投影矩阵变换。投影矩阵描述了从场景的3D点到视口的2D点的映射,并考虑了视口的纵横比。
(见Both depth buffer and triangle face orientation are reversed in OpenGL,
和Transform the modelMatrix)。
这会导致高地图(uTextureHeightmap
)表示矩形视野,具体取决于纵横比。
但是,用于访问高度图的纹理坐标描述了范围(0,0)到(1,1)范围内的四边形。
必须通过缩放宽高比来平衡这种不匹配。
vec3 direction = ....;
float aspectRatio = textureD.x / textureD.y;
direction.xy *= vec2( 1.0/aspectRatio, 1.0 );