Well i dont know if there has been posted a similar method alrdy...
i thought id post it and hope fo some comments and maybe help out others who also has problems with lighting terrain...
its pretty simple and this implementation works only for light along the x-axis
// Calculate horizons for each vertex. Does light reach it (1.0f), or not (0.0f).
// Works by calculating a ray from each point using tangent and if the terrain
// is higher than the ray at any point than the point is in shadow
void CTERRAIN::CalculateHorizonMap()
{
int Angle = 30;
int x, x1, z;
int MapSize = 256;
float TempHorizonMap[256][256];
for ( z = 0; z < MapSize; z++)
{
for (x = 0; x < MapSize; x++)
{
TempHorizonMap[x][z] = 1.0;
for (x1 = x+1; x1 < MapSize; x1++)
{
if ((float( x1-x ) * tan(Angle*3.14159/180) + GetScaledHeightAtPoint(x, z) ) < GetScaledHeightAtPoint(x1, z) )
{
TempHorizonMap[x][z] = 0;
x1 = MapSize;
}
}
}
}
//Blur the map with avarge values so that u dont get sharp shadow edges
for ( z = 0; z < MapSize; z++){
for (int x = 0; x < MapSize; x++){
if (true){
HorizonMap[x][z] = ( ( TempHorizonMap[x-1][z+1] + TempHorizonMap[x][z+1]
+ TempHorizonMap[x-1][z] + TempHorizonMap[x][z]
+ TempHorizonMap[x-1][z-1] + TempHorizonMap[x][z-1])/6 );
}
}
}
}
//Calculate mesh normals
void CTERRAIN::CalculateNormals( )
{
Vector A, B, C, D, E;
Vector CA, CB, CD, CE;
Vector AverageNormal;
Vector NormalACB,NormalBCE,NormalECD,NormalDCA;
for (int z = 1; z < 256; z++)
{
for (int x = 1; x < 256; x++)
{
A.Set( float(x ),GetScaledHeightAtPoint(x, z+1), float(z+1) );
B.Set( float(x-1),GetScaledHeightAtPoint(x-1, z) , float(z ) );
C.Set( float(x ),GetScaledHeightAtPoint(x, z) , float(z ) );
D.Set( float(x+1),GetScaledHeightAtPoint(x+1, z) , float(z ) );
E.Set( float(x ),GetScaledHeightAtPoint(x, z-1), float(z-1) );
CA = A - C;
CB = B - C;
CD = D - C;
CE = E - C;
NormalACB = CA.CrossVector(CB);
NormalBCE = CB.CrossVector(CE);
NormalECD = CE.CrossVector(CD);
NormalDCA = CD.CrossVector(CA);
NormalACB.NormalizeVector();
NormalBCE.NormalizeVector();
NormalECD.NormalizeVector();
NormalDCA.NormalizeVector();
AverageNormal.x=(NormalACB.x + NormalBCE.x + NormalECD.x + NormalDCA.x)/(float)4.0;
AverageNormal.y=(NormalACB.y + NormalBCE.y + NormalECD.y + NormalDCA.y)/(float)4.0;
AverageNormal.z=(NormalACB.z + NormalBCE.z + NormalECD.z + NormalDCA.z)/(float)4.0;
AverageNormal.NormalizeVector();
NormalMap[x][z] = AverageNormal;
}
}
}
void CTERRAIN::CalculateLighting()
{
int Angle = 30;
//Calcualte sun normal based on angle
float tempx = cos(Angle*3.14159/180);
float tempy = sin(Angle*3.14159/180);
float tempz = 0;
Vector SunNormal;
SunNormal.Set(-tempx, -tempy, 0.0);
//Set the suns color ( x = Red, y = Green, z = Blue)
Vector SunColor;
SunColor.Set(1.0, 0.8, 0.8);
for (int z = 1; z < 256; z++)
{
for (int x = 1; x < 256; x++)
{
// Get brightness of point by taking the dotproduct of
//the normalvector and sun vector
float sun = NormalMap[x][z].DotVector(SunNormal);
// Make sure we dont get to high or to low values
if ( sun > 1)
{
sun = 1;
}
if (sun < 0.0f)
{
sun = 0.0f;
}
// Multiple the brightness with the horizonmap and suns color
LightMap[x][z].x = HorizonMap[x][z]*sun*SunColor.x;
LightMap[x][z].y = HorizonMap[x][z]*sun*SunColor.y;
LightMap[x][z].z = HorizonMap[x][z]*sun*SunColor.z;
}
}
}
}
and here is the results:
http://img427.imageshack.us/img427/2701/method3mq.jpg
its pretty simple to add atmospheric lighting and indirect illumination using the horizonmap fnction.. u just have to calculate the horizonmap for all 180 angles... Maybe ill post this later..
for those who are intrested in the vetor class.. here it is..
#ifndef _3Dvector_H_
#define _3Dvector_H_
#include "math.h"
class Vector
{
private:
public:
float x, y,z ;
Vector(float ex = 0, float why = 0, float zee = 0)
{
x = ex; y = why; z = zee;
}
~Vector() {}
void comptopolar(int angle)
{
x = cos(angle*3.14159/180);
y = sin(angle*3.14159/180);
z = 0;
}
float GetMagnitude()
{
float value = x * x + y * y + z * z;
return sqrtf(value);
}
Vector operator*(float num) const
{
return Vector(x*num, y*num, z*num);
}
friend Vector operator*(float num, const Vector &vec)
{
return Vector(vec.x*num, vec.y*num, vec.z*num);
}
Vector operator+(const Vector &vec) const
{
return Vector(x+vec.x, y+vec.y, z+vec.z);
}
Vector operator-(const Vector &vec) const
{
return Vector(x-vec.x, y-vec.y, z-vec.z);
}
void NormalizeVector()
{
float mag = sqrtf(x*x+y*y+z*z);
x /= mag; y /= mag; z /= mag;
}
void NormalizeValues()
{
float max = 0;
if (x > max)
{
max = x;
}
if (y > max)
{
max = y;
}
if (z > max)
{
max = z;
}
x /= max; y /= max; z /= max;
}
float DotVector(const Vector &vec)
{
return x * vec.x + y*vec.y + z * vec.z;
}
Vector CrossVector(const Vector &vec)
{
return Vector(y*vec.z - z*vec.y, z*vec.x - x*vec.z, x*vec.y - y*vec.x);
}
void Set(float ex, float why, float zee)
{
x = ex; y = why; z = zee;
}
};
#endif
[Edited by - Dragon_Strike on June 9, 2006 6:03:45 PM]