更真实的照明

时间:2014-05-10 13:08:38

标签: c# xna

我已阅读this回答,我已尝试过:

for (int i = 0; i < mapArray.GetLength(0); i++)
{
    for (int j = 0; j < mapArray.GetLength(1); j++)
    {
        if (mapArray[i, j] == null)
            CurrentLight = 0f;
        else
        {
            mapArray[i, j].Light = CurrentLight;
            CurrentLight += Tiles.Absorb;
        }
    }
}

这就是结果:Game Lighting

正如你所看到的,我的问题是光线不真实,如果当前图块是一个块,函数会通过列并吸收0.05F的光,如果它不是块,它将被重置为0(这是全亮度)。

树主要在我眼中,而且光线不是那么好......我应该如何改进它?

感谢。

2 个答案:

答案 0 :(得分:1)

这种情况下最重要的现象是光散射。光散射发生在每个方向,而不仅仅是在建模时向下。您可以使用大型线性方程组计算光照,但这可能很慢(参见光能传递)。这是一个近似的替代方案:

基本思想是块将光分配给所有相邻块。我们从未填充块的1和填充块的0开始(请注意,我使用0表示“不亮”,1表示“全光”;这似乎更直观的“)。在我们用各自的值初始化所有块之后,我们可以开始以下的分配传递(我省略了范围检查;这取决于你):

float[, ] incomingLight; // should have the same size as the map 
                         // and saves the additional light for each block
for each i,j in the map
    float myLight = (map[i, j] == null ? 1 : map[i, j].Light)       
    incomingLight[i - 1, j    ] += 0.10f * myLight //Add light to the left neighbour
    incomingLight[i - 1, j - 1] += 0.07f * myLight //top left neighbour
    incomingLight[i    , j - 1] += 0.10f * myLight //top neighbour
    //do the same for all remaining neighbours

    incomingLight[i, j] -= (sumOfWeights) * myLight //preserve overall light intensity
    // ...
next
for each i,j in the map
    if(map[i, j] != null)
        map[i, j].Light = min(1, map[i, j].Light + incomingLight[i, j])
    incomingLight[i, j] = 0
next

现在我们已经照亮了与光块相邻的所有块。您可能需要调整分配的权重。

我们可以重复此过程以创建更逼真的灯光。通过执行越频繁,光线就会越深散。请注意,每个过程都会使整个场景变亮,因为未填充的块基本上具有无限的光强度。

另一种应该更快但稍微不精确的方法是计算每个块到最近的未阻挡区块的距离,并将其用作照明系数。有非常有效的算法来计算距离(见距离变换)。计算块距离(曼哈顿距离)非常简单,在您的情况下应该足够了:

使用无穷大或非常大的数字初始化填充块,使用零填充未填充的块。然后做四遍:

float [,] distances //initialized with 0 or infinity

//from top left corner
for y from 0 to height - 1
    for x from 0 to width - 1
        distances[x, y] = min(distances[x, y], distances[x - 1, y] + 1, distances[x, y - 1] + 1)

//from top right corner
for y from 0 to height - 1
    for x width - 1 to 0
        distances[x, y] = min(distances[x, y], distances[x + 1, y] + 1, distances[x, y - 1] + 1)

//from bottom left corner
for y from height - 1 to 0
    for x 0 to width - 1
        distances[x, y] = min(distances[x, y], distances[x - 1, y] + 1, distances[x, y + 1] + 1)

//from bottom rightcorner
for y from height - 1 to 0
    for x width - 1 to 0
        distances[x, y] = min(distances[x, y], distances[x + 1, y] + 1, distances[x, y + 1] + 1)

在这四次通过之后,您与distances数组中最近的空闲区块有距离。

答案 1 :(得分:1)

您的场景显示了山脉的剖面图。表面上的物体不能将阴影投射到该部分(即进入山的内部)。阳光只能击中表面,即草地,树木和化身。

我会让光线从左上角开始,并照亮它击中的第一个物体的左上角部分。由于场景的2D外观很难获得自然阴影,因为它们总是意味着第三维。

enter image description here

你甚至可以使对象的右下部分变暗。

enter image description here