質問

I have read this answer, and i have tried it:

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;
        }
    }
}

and this is the result: Game Lighting

As you can see, my problem is that the lighting isn't realistic, the function goes through the columns and absorb the light by 0.05F if the current tile is a block, if it is not a block it will be reset to 0 (which is the full brightness).

The tree mainly get in my eye's and the lighting isn't that good.. how should i improve it?

thanks.

役に立ちましたか?

解決

The most important phenomenon in this scenario is light scattering. Light scattering takes place in every direction, not only downwards as you modelled it. You can calculate the lighting with a big linear system of equations, but this is potentially slow (see radiosity). Here is an approximative alternative:

The basic idea is that a block distributes its light to all neighbouring blocks. We start with a 1 for unfilled blocks and 0 for filled blocks (note that I use 0 for "no light" and 1 for "full light"; this seems to be more intuitive"). After we have initialized all blocks with their respective values, we can start the following distribution pass (I omitted range checks; that's up to you):

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

Now we have illuminated all blocks that are adjacent to a light block. You might need to adjust the weights for the distribution.

We can repeat this pass to create a more realistic lighting. The more often the pass is executed, the deeper the light will scatter. Note that each pass will brighten up the entire scene because unfilled blocks have basically an infinite light intensity.

Another approach, which should be faster but slightly more imprecise, is to calculate the distance of each block to the nearest unblocked tile and use this as a coefficient for the lighting. There are very efficient algorithms to calculate the distance (see distance transform). Calculating the block distance (Manhattan distance) is quite simple and should suffice in your case:

Initialize filled blocks with infinity or a very big number and unfilled blocks with zero. Then do four passes:

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)

After those four passes you have the block distance to the nearest free block in the distances array.

他のヒント

Your scene shows a sectional image of the mountains. The objects on the surface cannot cast shadows to the section (i.e. into the inside of the mountain). Sunlight can only hit the surface, i.e. the grass, the trees and the avatar.

I would let the light come from top left and brighten up the top left part of the first objects it hits. Because of the 2D appearance of your scene it is difficult to get natural shadows, as those always imply a 3rd dimension.

enter image description here

You could even darken the bottom right parts of the objects.

enter image description here

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top