- unit u_Lightmap;
- interface
- uses
- Windows, Graphics, Math, Geometry, dglOpenGl;
- type
- TRay = record
- Origin, Direction : TVertex
- end;
- type
- TNormalMap = Array of Array[0..2] of ShortInt;
- function RayIntersected(Ray : TRay; HM : TBitMap; HeightMapScale : Single):Boolean;
- procedure CreateLightMap(HM : TBitMap; HeightMapScale : Single;NormalMap : TNormalMap; Sun : TVertex;
- LightMap : TBitMap; LightAmbient, LightDiffuse : Single; Raytracing : Boolean);
- procedure PrecacheHeightmap(HM : TBitmap);
- procedure CreateNormalMap(HM : TBitMap; HeightScale : Single; var NormalMap : TNormalMap);
- procedure LightingCreate;
- var LightMapTex : TBitmap;
- HeightMapData : Array of Array of byte;
- implementation
- uses u_PerlinNoise;
- function RayIntersected(Ray : TRay; HM : TBitMap; HeightMapScale : Single):Boolean;
- var Position : TVertex;
- Vor : TVertex;
- begin
- Result := False;
- Position := Ray.Origin;
- Vor := VectorNormalize(Ray.Direction);
- Position := VectorAdd(Position, Vor);
- while (Position[0] > 0) and (Position[0] < HM.Width - 1) and (Position[2] > 0) and (Position[2] < HM.Height - 1) do
- begin
- if HeightMapData[Trunc(Position[0]), Trunc(Position[2])]*HeightMapScale >= Position[1] then
- begin
- Result := True;
- Break;
- end;
- Position := VectorAdd(Position, Vor);
- end;
- end;
- procedure CreateLightMap(HM : TBitMap; HeightMapScale : Single;NormalMap : TNormalMap; Sun : TVertex;
- LightMap : TBitMap; LightAmbient, LightDiffuse : Single; Raytracing : Boolean);
- var X,Z : LongInt;
- Ray : TRay;
- n : TVertex;
- f : Single;
- begin
- PrecacheHeightmap(HM);
- Ray.Direction := VectorNormalize(Sun);
- for Z := 0 to HM.Height - 1 do
- begin
- for X := 0 to HM.Width - 1 do
- begin
- Ray.Origin[0] := X;
- Ray.Origin[1] := HM.Canvas.Pixels[X,Z]/clWhite*255*HeightMapScale;
- Ray.Origin[2] := Z;
- if RayIntersected(Ray, HM, HeightMapScale) then f := LightAmbient
- else
- begin
- n[0] := NormalMap[Z*(HM.Height) + X][0];
- n[1] := NormalMap[Z*(HM.Height) + X][1];
- n[2] := NormalMap[Z*(HM.Height) + X][2];
- f := LightAmbient+ LightDiffuse*(VectorDotProduct(VectorNormalize(n),VectorNormalize(Ray.Direction)));
- if f > 1.0 then f := 1.0;
- if f < 0.0 then f := 0.0;
- end;
- LightMap.Canvas.Pixels[X,Z] := RGB(Trunc(f*255), Trunc(f*255), Trunc(f*255));
- end;
- end;
- end;
- procedure PrecacheHeightmap(HM : TBitmap);
- var X,Z : LongInt;
- begin
- SetLength(HeightMapData, HM.Width);
- for X := 0 to Length(HeightMapData) -1 do SetLength(HeightMapData[X], HM.Height);
- for Z := 0 to HM.Height - 1 do
- for X := 0 to HM.Width - 1 do HeightMapData[X,Z] := Trunc(HM.Canvas.Pixels[X,Z]/clWhite * 255);
- end;
- procedure CreateNormalMap(HM : TBitMap; HeightScale : Single; var NormalMap : TNormalMap);
- const VertexPoss : Array[0..8] of Array[0..1] of ShortInt = ((0,0),(1,-1),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1));
- Faces : Array[0..7] of Array[0..2] of Byte = ((0,1,8),(0,2,1),(0,4,2),(4,3,2),(0,5,4),(0,6,5),(0,8,6),(8,7,6));
- var X,Z : LongInt;
- I : LongInt;
- VertexPosMultiply : LongInt;
- Vertieces : Array[0..8] of TVertex;
- Normals : Array[0..7] of TVertex;
- Normale : TVertex;
- begin
- SetLength(NormalMap, HM.Width*HM.Height);
- FillChar(Vertieces[0,0], SizeOf(Vertieces), 0);
- for Z := 0 to HM.Height - 1 do
- begin
- for X := 0 to HM.Width - 1 do
- begin
- Normale[0] := 0;
- Normale[1] := 0;
- Normale[2] := 0;
- VertexPosMultiply := 64;
- for I := 0 to 8 do
- begin
- Vertieces[I][0] := X + VertexPoss[I][0]*VertexPosMultiply;
- Vertieces[I][2] := Z + VertexPoss[I][1]*VertexPosMultiply;
- Vertieces[I][1] := HM.Canvas.Pixels[X + VertexPoss[I][0]*VertexPosMultiply,
- Z + VertexPoss[I][1]*VertexPosMultiply]/clWhite*255*HeightScale;
- end;
- for I := 0 to 7 do
- begin
- Normals[I] := VectorCrossProduct(VectorNormalize(VectorSubtract(Vertieces[Faces[I][0]],
- Vertieces[Faces[I][1]])),VectorNormalize(VectorSubtract(Vertieces[Faces[I][1]],
- Vertieces[Faces[I][2]])));
- Normals[I] := VectorNormalize(Normals[I]);
- end;
- for I := 0 to 7 do Normale := VectorAdd(Normale, Normals[I]);
- NormalizeVector(Normale);
- Normale := VectorScale(Normale,127.0);
- NormalMap[Z*(HM.Height) + X][0] := Trunc(Normale[0]);
- NormalMap[Z*(HM.Height) + X][1] := Trunc(Normale[1]);
- NormalMap[Z*(HM.Height) + X][2] := Trunc(Normale[2]);
- end;
- end;
- end;
- procedure LightingCreate;
- var Sun : TVertex;
- HeightMapScale : Single;
- NormalMap : TNormalMap;
- Value : SmallInt;
- HM : TBitmap;
- begin
- Value := Trunc(Random(180)*Pi)+180;
- HM := u_PerlinNoise.Heightmap; //Heightmap einer anderen Unit die hier übergeben wird
- Sun[0] := Cos(Value/180);
- Sun[1] := Value/100;
- Sun[2] := Sin(Value/180);
- HeightMapScale := 512;
- LightMapTex.Width := 512; //LightMapTex wird im OnCreate der Form in u_Main erzeugt
- LightMapTex.Height := 512;
- CreateNormalMap(HM, HeightMapScale, NormalMap);
- CreateLightMap(HM, HeightMapScale, NormalMap, Sun, LightMapTex, Random(100)/100, Random(100)/100, true);
- end;
- end.