【问题标题】:Weird lighting effect using a point light on a skydome在天穹上使用点光源的奇怪照明效果
【发布时间】:2014-10-05 02:13:08
【问题描述】:

我的照明有问题。当灯光越过顶点或线时,灯光会出现这种奇怪的外观。 (它应该是圆形的。)我一直在尝试各种事情,但我不知道为什么会这样。

我创建了一个天穹并标准化它的位置

double deltaLatitude = XM_PI / segments;
double deltaLongitude = XM_PI * 2.0 / segments;
int index = 0;
D3DXCOLOR bottomColor = D3DXCOLOR(0.529f, 0.807f, 0.821f, 1.0f);
D3DXCOLOR topColor = D3DXCOLOR(0.179f, 0.557f, 1.0f, 1.0f);

for (int i = 1; i < segments; i++)
{
    double r0 = sin(i * deltaLatitude);
    double y0 = cos(i * deltaLatitude);

    for (int j = 0; j < segments; j++)
    {
        double x0 = r0 * sin(j * deltaLongitude);
        double z0 = r0 * cos(j * deltaLongitude);

        D3DXVECTOR3 v = D3DXVECTOR3(x0, y0, z0);//create normal based on possition (-1 <> 1)
        D3DXVec3Normalize(&v, &v);//normalize
        vertPos.push_back(Vertex(x0, y0, z0, lerp(bottomColor, topColor, y0), v));
    }
}

vertPos.push_back(Vertex(0, 1, 0, lerp(bottomColor, topColor, 1), D3DXVECTOR3(0.0f, 1.0f, 0.0f)));
vertPos.push_back(Vertex(0, -1, 0, lerp(bottomColor, topColor, -1), D3DXVECTOR3(0.0f, -1.0f, 0.0f)));

for (int i = 0; i < segments - 2; i++)
{
    for (int j = 0; j < segments; j++)
    {
        indices.push_back(segments * i + j);
        indices.push_back(segments * i + (j + 1) % segments);
        indices.push_back(segments * (i + 1) + (j + 1) % segments);
        indices.push_back(segments * i + j);
        indices.push_back(segments * (i + 1) + (j + 1) % segments);
        indices.push_back(segments * (i + 1) + j);
    }
}

// create the faces of the top of the dome
for (int i = 0; i < segments; i++)
{
    indices.push_back(segments * (segments - 1));
    indices.push_back((i + 1) % segments);
    indices.push_back(i);
}

// create the faces of the bottom of the dome
for (int i = 0; i < segments; i++)
{
    indices.push_back(segments * (segments - 1) + 1);
    indices.push_back(segments * (segments - 2) + i);
    indices.push_back(segments * (segments - 2) + (i + 1) % segments);
}

顶点着色器:

VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float4 inColor : COLOR, float3 normal : NORMAL)
{
    VS_OUTPUT output;
    output.Pos = mul(inPos, WVP);

    output.worldPos = mul(inPos, World);
    output.normal = mul(normal, World);

    output.Color = inColor;

    return output;
}

这是像素着色器:

float4 PS(VS_OUTPUT input) : SV_TARGET
{
    input.normal = normalize(input.normal);

    float4 diffuse = input.Color;
    float skyColor = light.spos.a;
    float4 sunColor = float4(500.0f, 100.0f, 100.0f, 1.0f);

    float3 finalColor = float3(0.0f, 0.0f, 0.0f);
    float3 finalAmbient = diffuse * skyColor;

    float sunRange = 1000.0f;

    float3 lightToPixelVec = light.spos - input.worldPos;

    float d = length(lightToPixelVec);

    if( d > sunRange ){
        return float4(finalAmbient, diffuse.a);
    }

    //Turn lightToPixelVec into a unit length vector describing
    //the pixels direction from the lights position
    lightToPixelVec /= d;

    //Calculate how much light the pixel gets by the angle
    //in which the light strikes the pixels surface
    float howMuchLight = dot(lightToPixelVec, input.normal);

    //If light is striking the front side of the pixel
    if( howMuchLight > 0.0f )
    {   
        //Add light to the finalColor of the pixel
        finalColor += howMuchLight * finalAmbient * sunColor;

        //Calculate Light's Falloff factor
        finalColor /= 10.0f + (0.01 * d) + (0.01 * (d*d));
    }   
    finalColor = saturate(finalColor + finalAmbient);

    return float4(finalColor, diffuse.a);
}

【问题讨论】:

    标签: c++ opengl directx shader lighting


    【解决方案1】:

    您无需考虑面即可获得顶点的法线。它只是一个半球,对,所以法线只是从球体中心(我猜是原点)到顶点的向量,但是你应该将它标准化为长度为 1。所以顶点的法线很简单其坐标已标准化。

    【讨论】:

    • 感谢它让它更快了一点,但它仍然为照明创造了相同的效果。有什么想法会导致这种情况吗?
    • 某些东西没有正确插值,这通常是由于顶点着色器中的某些东西,所以我能看到吗?另外,我不明白衰减因子的东西,所以我想看看去掉那个的结果,对于那个 d > sunRange 的东西也是如此。
    • 衰减因子是这个点光源在特定 d(距离)处发出的光量,这意味着像素离太阳位置越远,添加的光就越少。 d > sunRange 只是为了检查当我删除它时像素是否在 1000.0f 的范围内,我的天空会是黑色的。我已经为你添加了顶点着色器。
    • 听起来你的太阳非常接近 - AFAICT 你的半径是 1。那么图片就有意义了。如果太阳在 (5,10,5),它看起来如何?
    • 抱歉,回复晚了,这确实是问题所在。我使用的太阳坐标与球体完全相同(中间还有几个点:double deltaLatitude = XM_PI / 180; double deltaLongitude = XM_PI * 2.0 / 180;)所有我修复它的方法是编辑太阳位置的比例与天穹的比例
    【解决方案2】:

    传统的 OpenGL 固定函数管道照明仅在顶点处进行计算并在其间进行插值。根据网格的拓扑结构,您可能会出现由 OpenGL 在顶点之间插值的方式导致的光栅化拓扑不连续性。

    解决方案:使用每个片段照明,在片段着色器中实现。

    顺便说一句:你为​​什么要首先对天穹应用照明?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-27
      • 1970-01-01
      • 1970-01-01
      • 2011-09-20
      • 2019-02-25
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      相关资源
      最近更新 更多