GLSL - 计算片段的法线

时间:2011-05-23 09:03:02

标签: opengl glsl shader terrain

我正在尝试创建一个显示地形地球的程序,并在GPU上执行所有Lat / Long / Alt到XYZ(ECEF)。

我已经编写了一个工作顶点着色器,它将表示经度,纬度和海拔高度(分别)的XYZ平移到正确的XYZ(使用ECEF)。

我无法做到的是照明。

只要没有地形数据,我就设法使用定向灯正确点亮每个顶点。地形数据没有正确点亮,我无法获得不同的斜率以获得正确的阴影。

这是我正在使用的顶点着色器:

const float a = 6378137.0;
const float f = 0.003352810664747480719845528618;

varying vec3 Normal;
varying vec3 ecPos;

vec3 LatLonAltToEcef(in vec3 latLonAlt)
{
    vec3 v = latLonAlt;

    float cosLat = cos(radians(v.y));
    float sinLat = sin(radians(v.y));
    float nfs = (1.0 - f) * (1.0 - f);

    float C = 1.0 / (sqrt(cosLat * cosLat + nfs * sinLat * sinLat));
    float S = nfs * C;

    float lon = radians(v.x);
    float h = v.z;

    v.x = (a * C + h) * cosLat * cos(lon) / a;
    v.y = (a * C + h) * cosLat * sin(lon) / a;
    v.z = (a * S + h) * sinLat / a;

    return v;
}

vec4 LatLonAltToEcef(in vec4 latLonAlt)
{
    vec3 ecef = LatLonAltToEcef(latLonAlt.xyz);
    return vec4(ecef.x, ecef.y, ecef.z, latLonAlt.w);
}

void main(void)
{
    vec4 v = LatLonAltToEcef(gl_Vertex); //x=lon, y=lat, z=alt
    ecPos = vec3(gl_ModelViewMatrix * v);

    Normal = normalize(gl_NormalMatrix * v.xyz);
    vec4 lightPos = LatLonAltToEcef(gl_LightSource[0].position);
    vec3 lightDir = normalize(gl_NormalMatrix * lightPos.xyz);
    float NdotL = max(dot(Normal, lightDir), 0.0);
    vec4 diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;

    gl_FrontColor =  NdotL * diffuse;
    gl_Position = gl_ModelViewProjectionMatrix * v;
}

为了绘制地球网格,这是需要做的事情:

for (float lat = -90; lat < 90; lat += 5)
{
    glBegin(GL_LINE_LOOP);
    for (float lon = -180; lon < 180; lon += 5)
        glVertex3f(lon, lat, 0);
    glEnd();
}

for (float lon = -180; lat < 180; lon += 5)
{
    glBegin(GL_LINE_LOOP);
    for (float lat = -90; lon < 90; lon += 5)
        glVertex3f(lon, lat, 0);
    glEnd();
}

任何人都可以指导我如何正确遮蔽地形吗?

2 个答案:

答案 0 :(得分:5)

我觉得你需要学习更多的计算机图形,因为你对计算机渲染几何的基本知识似乎存在一些差距。

反正:

如果您从一开始就没有坡度信息,那么在任何一点获得正常(地面方向)通常需要查看周围环境。

其次,您可能想要绘制三角形而不是线条。

三角形有一个表面。表面有法线。法线是向量,可以与其他向量成角度。光方向是矢量。点积是你的朋友。 :)

因此,拥有一组连接顶点的三角形将帮助您到达某个地方。

此外,避免在着色器中计算可以在任何渲染之前一次性计算的东西。

答案 1 :(得分:4)

你的问题在这里:

Normal = normalize(gl_NormalMatrix * v.xyz);

幸运的是,您发现了一种罕见的情况,即使用顶点的位置也会给出法线:球体(但由于地球不是球体,因此您的光照不是100%正确)

当你添加山脉时,这不再是真的了。法线垂直于地面,所以在山上,它是弯曲的。

你需要这样的一行:

Normal = normalize(gl_NormalMatrix * gl_Normal.xyz);

gl_Normal是通过调用glNormal3f给出的,就在glVertex3f之前。但是你没有说你如何提供地形数据所以你必须自己找到glNormal3f的参数。它们必须在模型空间中表示(即,不是lon / lat,而是相对于地球中心的XYZ,在笛卡尔空间中。再次:笛卡尔空间。)