2
// This unit is part of the GLScene Engine https://github.com/glscene
5
ZBuffer retrieval and computations.
7
See readme.txt in the Demos/SpecialsFX/Shadows directory.
11
10/11/12 - PW - Added CPP compatibility: changed vector arrays to records
12
23/08/10 - Yar - Added OpenGLTokens to uses, replaced OpenGL1x functions to OpenGLAdapter
13
22/04/10 - Yar - Fixes after GLState revision
14
05/03/10 - DanB - More state added to TGLStateCache
15
29/05/08 - DaStr - Removed unused variables in TGLZShadows.CalcShadowTexture()
16
20/01/08 - DaStr - Bugfixed TGLZShadows.HardSet(Bugtracker ID = 1875708)
17
Removed some old commented out code
18
Removed TGLZShadows.Trnc() procedure - there is a
19
similar procedure in GLVectorGeometry.pas
20
28/03/07 - DaStr - Renamed parameters in some methods
21
(thanks Burkhard Carstens) (Bugtracker ID = 1678658)
22
24/03/07 - DaStr - Improved Cross-Platform compatibility
23
(thanks Burkhard Carstens) (Bugtracker ID = 1684432)
24
17/03/07 - DaStr - Dropped Kylix support in favor of FPC (BugTracekrID=1681585)
25
16/03/07 - DaStr - Added explicit pointer dereferencing
26
(thanks Burkhard Carstens) (Bugtracker ID = 1678644)
27
08/02/07 - Lin - LONG overdue bugfix: Now sets GL_BLEND to prevent black screen.(thanks Jurgen Linker)
28
08/03/06 - ur - Fixed warnigs for Delphi 2006
29
02/08/04 - LR, YHC - BCB corrections: use record instead array
30
03/07/04 - LR - Added ifdef for Linux
31
07/03/02 - Lin - Removed XRes/YRes properties - Shadow-res now always matches viewer-res.
32
21/02/02 - Lin - Now uses 1 Byte per pixel, instead of 4. Faster, and uses less Video Ram.
33
14/02/02 - Lin - Bugfix: No longer stalls the Cadencer + small speed improvements
34
12/02/02 - Lin - Bilinear filtering of soft shadow edges - much better quality
35
08/02/02 - Lin - Removed the material property (not used)
36
05/02/02 - Lin - Tolerance scaling - reduces shadow-creeping(far) and self-shadowing(near)
37
05/02/02 - Lin - A little more speed in 16in1 mode (but 9in1 is still the best quality)
38
05/02/02 - EG - Fixed glTex[Sub]Image calls
39
20/11/01 - EG - Removed warnings (axed out... hope I didn't broke anything)
40
17/10/01 - Lin - Added Xres and Yres...makes shadow texture size independent from viewer.
41
Calculations now use z-depth in stead of world distance
42
- more acurate, and 15% faster.
43
27/09/01 - Lin - Bypass the GLScene Material.texture.image, and send the shadow
44
texture directly to OpenGL. This increased speed by almost 20%
45
25/09/01 - Lin - Add Optimise property to specify faster rastering methods
46
07/09/01 - Lin - Restructure zBuffer code, to support the new TGLMemoryViewer
47
06/09/01 - Lin - Created TGLZShadows object, for casting shadows
48
30/08/01 - Lin - More speed + bugfixes
49
24/07/01 - Lin - Greatly improved speed
50
07/07/01 - Lin - Added PixelToWorld, WorldToPixel, and PixelToDistance
51
01/07/01 - Lin - Precalculate the corner vectors in GetDepthBuffer,
52
to speed up FastVectorToScreen and FastScreenToVector
53
28/06/01 - Lin - First operational code
54
26/06/01 - Lin - Creation of zBuffer class
58
//--------These formulas are the key to making use of the z-Buffer--------
60
// dst (d): world distance
61
// dov : depth of view (distance between Far-plane and Near-plane)
63
// fp : far plane (dov+np)
65
//------------------------
66
//dst:=(fp*np)/(fp-z*dov); //calc from z-buffer value to frustrum depth
67
//z :=(1-np/d)/(1-np/fp); //calc from frustrum depth to z-buffer value
68
//------------------------ z:=1-(fp/d-1)/(fp/np-1); //old FtoZ
69
//------------------------------------------------------------------------
80
GLScene, GLVectorGeometry, GLGraphics, GLObjects, GLContext, GLViewer,
81
GLColor, GLRenderContextInfo, GLState, GLTextureFormat,
82
OpenGLTokens, XOpenGL , GLVectorTypes;
86
EZBufferException = class(Exception);
88
TZArray = array[0..MaxInt shr 3] of Single;
90
TZArrayIdx = array of PZArray;
92
TAArray = array[0..MaxInt shr 3] of Byte;
94
TAArrayIdx = array of PAArray;
96
TOptimise = (opNone, op4in1, op9in1, op16in1);
98
TGLzBuffer = class(TPersistent)
101
FDataIdx, FDataInvIdx: TZArrayIdx;
102
FWidth, FHeight: Integer;
105
ang1, ang2, scal, c1, s1, c2, s2, vw, vh: single; //VectorToScreen variables;
106
lt, rt, lb, rb: TAffineVector; //ScreenToVector corner vectors;
107
UpVec, riVec: TAffineVector;
109
ltW, rtW, lbW, rbW: TAffineVector; //ScreenToVector corner vectors;(Warped)
110
UpVecW, riVecW: TAffineVector;
111
OrthInvDov, OrthAddX, OrthMulX, OrthAddY, OrthMulY: single;
113
dov, np, fp, NpFp, OneMinNp_Fp, invOneMinNp_Fp: single; //Calc Variables;
117
procedure DoCalcVectors;
120
procedure PrepareBufferMemory;
121
procedure SetWidth(val: Integer);
122
procedure SetHeight(const val: Integer);
125
SceneViewer: TGLSceneViewer;
126
MemoryViewer: TGLMemoryViewer;
127
Buffer: TGLSceneBuffer;
129
Normal: TAffineVector; //Absolute direction of camera
132
destructor Destroy; override;
134
procedure LinkToViewer(viewer: TGLSceneViewer); overload;
135
procedure LinkToViewer(viewer: TGLMemoryViewer); overload;
136
function GetDepthBuffer(CalcVectors: Boolean; ContextIsActive: boolean):
139
function GetPixelzDepth(x, y: integer): Single;
140
function PixelToDistance_OLD(x, y: integer): Single;
141
function PixelToDistance(x, y: integer): Single;
142
property Width: Integer read FWidth write SetWidth;
143
property Height: Integer read FHeight write SetHeight;
144
property DataSize: Integer read FDataSize;
145
property Data: PZArray read FData;
146
property DataIdx: TZArrayIdx read FDataIdx;
147
property DataInvIdx: TZArrayIdx read FDataIdx;
150
function FastScreenToVector(x, y: Integer): TAffineVector;
151
function FastVectorToScreen(vec: TAffineVector): TAffineVector;
153
function PixelToWorld(const x, y: Integer): TAffineVector;
154
function WorldToPixel(const aPoint: TAffineVector; out pixX, pixY: integer;
155
out pixZ: single): boolean;
156
function WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY: integer;
157
out pixZ: single): boolean; overload;
158
function WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY: single;
159
out pixZ: single): boolean; overload;
160
function OrthWorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY:
161
single; out pixZ: single): boolean;
166
TGLZShadows = class(TGLBaseSceneObject)
168
FViewer: TGLSceneViewer;
169
FCaster: TGLMemoryViewer;
171
FFrustShadow: Boolean;
173
FOptimise: TOptimise;
176
FDataIdx, FDataInvIdx: TAArrayIdx;
189
//stepX, stepY :single;
191
FTexturePrepared: Boolean;
193
FTexHandle: TGLTextureHandle;
196
procedure PrepareAlphaMemory;
198
function GetViewer: TGLSceneViewer;
199
procedure SetViewer(const val: TGLSceneViewer);
200
function GetCaster: TGLMemoryViewer;
201
procedure SetCaster(const val: TGLMemoryViewer);
202
procedure CalcShadowTexture(var rci: TGLRenderContextInfo);
203
function HardSet(const x, y: integer): Byte;
205
function SoftTest(const x, y: integer): Byte;
206
procedure SetWidth(const val: integer);
207
procedure SetHeight(const val: integer);
208
procedure SetXRes(const val: integer);
209
procedure SetYRes(const val: integer);
210
procedure SetSoft(const val: boolean);
212
procedure BindTexture;
214
ViewerZBuf: TGLzBuffer;
215
CasterZBuf: TGLzBuffer;
216
constructor Create(AOwner: TComponent); override;
217
destructor Destroy; override;
218
procedure DoRender(var ARci: TGLRenderContextInfo; ARenderSelf,
219
ARenderChildren: Boolean); override;
221
property Viewer: TGLSceneViewer read GetViewer write SetViewer;
222
property Caster: TGLMemoryViewer read GetCaster write SetCaster;
223
property FrustShadow: Boolean read FFrustShadow write FFrustShadow;
224
property SkyShadow: Boolean read FSkyShadow write FSkyShadow;
225
property Optimise: TOptimise read FOptimise write FOptimise;
226
property Width: integer read FWidth write SetWidth;
227
property Height: integer read FHeight write SetHeight;
228
property Color: TGLColor read FColor write FColor;
229
// property Xres :integer read FXRes write SetXRes;// default 64;
230
// property Yres :integer read FYRes write SetYRes;// default 64;
231
property Soft: Boolean read Fsoft write SetSoft;
232
property Tolerance: single read FTolerance write FTolerance;
233
// property Material;
234
property ObjectsSorting;
237
property DepthFade: Boolean read FDepthFade write FDepthFade;
238
function CastShadow: boolean;
243
constructor TGLzBuffer.Create;
251
self.SceneViewer := nil;
252
self.MemoryViewer := nil;
254
// self.DoCalcVectors;
257
procedure TGLzBuffer.LinkToViewer(viewer: TGLSceneViewer); // overload;
259
if ((FWidth <> Viewer.width) or (FHeight <> Viewer.height)) then
261
FWidth := Viewer.width;
262
FHeight := Viewer.height;
265
cam := Viewer.camera;
266
SceneViewer := Viewer;
267
Buffer := Viewer.Buffer;
271
procedure TGLzBuffer.LinkToViewer(viewer: TGLMemoryViewer); // overload;
273
if ((FWidth <> Viewer.width) or (FHeight <> Viewer.height)) then
275
FWidth := Viewer.width;
276
FHeight := Viewer.height;
279
cam := Viewer.camera;
280
MemoryViewer := Viewer;
281
Buffer := Viewer.Buffer;
287
destructor TGLzBuffer.Destroy;
293
procedure TGLzBuffer.PrepareBufferMemory;
297
FDataSize := FWidth * FHeight * 4;
298
ReallocMem(FData, FDataSize);
299
SetLength(FDataIdx, FHeight + 2);
300
SetLength(FDataInvIdx, FHeight + 2);
301
for i := 0 to FHeight - 1 do
303
FDataIdx[i] := @FData[i * FWidth]; // range: [0..height-1]
304
FDataInvIdx[i] := @FData[(FHeight - i - 1) * FWidth]; // range: [0..height-1]
306
FDataIdx[FHeight] := FDataIdx[FHeight - 1];
307
FDataInvIdx[FHeight] := FDataInvIdx[FHeight - 1];
312
procedure TGLzBuffer.SetWidth(val: Integer);
314
if val <> FWidth then
324
procedure TGLzBuffer.SetHeight(const val: Integer);
326
if val <> FHeight then
334
function TGLzBuffer.GetDepthBuffer(CalcVectors: Boolean; ContextIsActive:
337
if ContextIsActive = True then
339
GL.ReadPixels(0, 0, FWidth, FHeight, GL_DEPTH_COMPONENT, GL_FLOAT, FData);
343
Buffer.RenderingContext.Activate;
345
GL.ReadPixels(0, 0, FWidth, FHeight, GL_DEPTH_COMPONENT, GL_FLOAT, FData);
347
Buffer.RenderingContext.Deactivate;
351
if CalcVectors = True then
356
function TGLzBuffer.GetPixelzDepth(x, y: integer): Single;
358
if (Cardinal(x) < Cardinal(FWidth)) and (Cardinal(y) < Cardinal(FHeight)) then
359
Result := FDataInvIdx[y]^[x]
364
function TGLzBuffer.PixelToDistance_OLD(x, y: integer): Single;
366
z, dst, camAng, wrpdst: single;
369
if ((x < 0) or (x > FWidth) or (y < 0) or (y > FWidth)) then
373
z := FData^[x + (FHeight - y) * FWidth]; //fetch pixel z-depth
374
dst := (NpFp) / (fp - z * dov); //calc from z-buffer value to frustrum depth
375
vec := FastScreenToVector(x, y);
376
camAng := VectorAngleCosine(normal, vec);
377
wrpdst := dst / camAng; //compensate for flat frustrum face
382
function TGLzBuffer.PixelToDistance(x, y: integer): Single;
388
if ((x < 0) or (x >= FWidth) or (y < 0) or (y >= FHeight)) then
393
z := FData^[x + fy * FWidth]; //fetch pixel z-depth
396
dst := (NpFp) / (fp - z * dov);
397
//calc from z-buffer value to frustrum depth
398
xx := (lbW.V[0] + riVecW.V[0] * x + UpVecW.V[0] * fy);
399
yy := (lbW.V[1] + riVecW.V[1] * x + UpVecW.V[1] * fy);
400
zz := (lbW.V[2] + riVecW.V[2] * x + UpVecW.V[2] * fy);
401
result := sqrt(xx * xx + yy * yy + zz * zz) * dst;
408
procedure TGLzBuffer.Refresh;
410
if assigned(Buffer) then
411
GetDepthBuffer(True, False);
414
procedure TGLzBuffer.DoCalcVectors;
417
Hnorm, hcvec: TVector;
422
if not (assigned(Buffer) and Buffer.RCInstantiated) then
424
if not assigned(cam) then
425
raise EZBufferException.Create('No Camera!');
427
//-----------For ScreenToVector-------------
430
setVector(vec, 0, 0, 0);
431
lb := buffer.ScreenToVector(vec); // same as cvec...optimise?
432
setVector(vec, w, 0, 0);
433
rb := buffer.ScreenToVector(vec);
434
setVector(vec, 0, h, 0);
435
lt := buffer.ScreenToVector(vec);
436
setVector(vec, w, h, 0);
437
rt := buffer.ScreenToVector(vec);
438
//------------Set Camera values-------------
439
normal := VectorLerp(lb, rt, 0.5);
440
upVec := VectorSubtract(lt, lb);
441
riVec := VectorSubtract(rb, lb);
442
// cam:=viewer.Camera;
443
dov := Cam.DepthOfView;
445
fp := Cam.NearPlane + dov;
447
OneMinNp_Fp := 1 - np / fp;
448
invOneMinNp_Fp := 1 / OneMinNp_Fp;
449
//-----------For VectorToScreen-------------
451
cam :=Viewer.Camera.Position.AsAffineVector;
452
targ:=Viewer.Camera.TargetObject.Position.AsAffineVector;
453
norm:=VectorSubtract(targ,cam); //---Camera Normal vector---
454
MakeVector(hnorm,norm);
456
MakeVector(hnorm, normal);
458
MakeVector(hcVec, lb); //---Corner Vector---
459
ang1 := ArcTan2(Hnorm.V[0], Hnorm.V[2]);
460
SetVector(axs, 0, 1, 0);
461
RotateVector(hnorm, axs, ang1);
462
RotateVector(hcvec, axs, ang1);
464
ang2 := ArcTan2(Hnorm.V[1], Hnorm.V[2]);
465
SetVector(axs, 1, 0, 0);
466
RotateVector(hcvec, axs, -ang2);
468
hcvec.V[0] := hcvec.V[0] / hcvec.V[2];
471
scal := vw / hcvec.V[0];
472
SinCos(-ang1, s1, c1);
473
SinCos(-ang2, s2, c2);
474
//------------------------------------------
475
//--------------------2-----------------
476
vec := self.FastScreenToVector(0, 1);
477
wrp := VectorAngleCosine(normal, vec);
478
ltW := VectorNormalize(lt);
479
rtW := VectorNormalize(rt);
480
lbW := VectorNormalize(lb);
481
rbW := VectorNormalize(rb);
482
ltW := VectorScale(ltW, 1 / wrp);
483
rtW := VectorScale(rtW, 1 / wrp);
484
lbW := VectorScale(lbW, 1 / wrp);
485
rbW := VectorScale(rbW, 1 / wrp);
486
upVecW := VectorSubtract(ltW, lbW);
487
upVecW := VectorScale(upVecW, 1 / Fheight);
488
riVecW := VectorSubtract(rbW, lbW);
489
riVecW := VectorScale(riVecW, 1 / Fwidth);
491
// UpVecW[0]:=-UpVecW[0];
492
// UpVecW[1]:=-UpVecW[1];
493
// UpVecW[2]:=-UpVecW[2];
495
//--------------------------------------
496
//-------orth---------
501
OrthMulX := FWidth / (OrthAddX * 2);
503
OrthMulY := FHeight / (OrthAddY * 2);
504
OrthInvDov := 1 / dov;
506
//--------------------
509
function TGLzBuffer.FastScreenToVector(x, y: integer): TAffineVector;
512
Rlerp, Ulerp: single;
517
Ulerp := (h - y) / h;
518
result.V[0] := lb.V[0] + riVec.V[0] * Rlerp + UpVec.V[0] * Ulerp;
519
result.V[1] := lb.V[1] + riVec.V[1] * Rlerp + UpVec.V[1] * Ulerp;
520
result.V[2] := lb.V[2] + riVec.V[2] * Rlerp + UpVec.V[2] * Ulerp;
523
function TGLzBuffer.FastVectorToScreen(Vec: TAffineVector): TAffineVector;
525
v0, v1, x, y, z: Single;
531
x := c1 * v0 + s1 * z;
532
z := c1 * z - s1 * v0; //Rotate around Y-axis
534
y := c2 * v1 + s2 * z;
535
z := c2 * z - s2 * v1; //Rotate around X-axis
536
Result.V[0] := Round(-x / z * scal + vw);
537
Result.V[1] := Round(y / z * scal + vh);
541
function TGLzBuffer.PixelToWorld(const x, y: Integer): TAffineVector;
547
// if (Cardinal(x)<Cardinal(FWidth)) and (Cardinal(y)<Cardinal(FWidth)) then begin //xres,yres?
548
if (x < FWidth) and (y < FHeight) then
550
z := FDataInvIdx[y]^[x];
551
dst := (NpFp) / (fp - z * dov); //calc from z-buffer value to frustrum depth
552
camvec := cam.AbsolutePosition;
554
result.V[0] := (lbW.V[0] + riVecW.V[0] * x + UpVecW.V[0] * fy) * dst + camvec.V[0];
555
result.V[1] := (lbW.V[1] + riVecW.V[1] * x + UpVecW.V[1] * fy) * dst + camvec.V[1];
556
result.V[2] := (lbW.V[2] + riVecW.V[2] * x + UpVecW.V[2] * fy) * dst + camvec.V[2];
566
function TGLzBuffer.WorldToPixel(const aPoint: TAffineVector; out pixX, pixY:
567
integer; out pixZ: single): boolean;
570
x, y, z, v0, v1, zscal: single;
572
//---Takes x,y,z world coordinate.
573
//---Result is true if pixel lies within view frustrum
574
//---returns canvas pixel x,y coordinate, and the world distance
576
campos := cam.AbsolutePosition;
577
x := apoint.V[0] - camPos.V[0];
578
y := apoint.V[1] - camPos.V[1];
579
z := apoint.V[2] - camPos.V[2]; //get vector from camera to world point
581
x := c1 * v0 + s1 * z;
582
z := c1 * z - s1 * v0; //Rotate around Y-axis
584
y := c2 * v1 + s2 * z;
585
z := c2 * z - s2 * v1; //Rotate around X-axis
589
pixX := Round(-x * zscal + vw);
590
pixY := Round(y * zscal + vh);
591
pixZ := sqrt(x * x + y * y + z * z);
592
if (pixX >= 0) and (pixX < FWidth) and (pixY >= 0) and (pixY < FHeight) then
596
begin //ignore anything that is behind the camera
603
function TGLzBuffer.WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY:
604
integer; out pixZ: single): boolean; //OVERLOAD
607
x, y, z, v0, v1, zscal: single;
609
//---Takes x,y,z world coordinate.
610
//---Result is true if pixel lies within view frustrum
611
//---returns canvas pixel x,y coordinate, and CALCULATES the z-buffer distance
612
campos := cam.AbsolutePosition;
613
x := apoint.V[0] - camPos.V[0];
614
y := apoint.V[1] - camPos.V[1];
615
z := apoint.V[2] - camPos.V[2]; //get vector from camera to world point
617
x := c1 * v0 + s1 * z;
618
z := c1 * z - s1 * v0; //Rotate around Y-axis
620
y := c2 * v1 + s2 * z;
621
z := c2 * z - s2 * v1; //Rotate around X-axis
625
pixX := Round(-x * zscal + vw);
626
pixY := Round(y * zscal + vh);
627
//------z:=(1-np/z)/(1-np/fp);------
628
// pixZ:=(1-np/z)/(1-np/fp);
629
pixZ := (1 - np / z) * invOneMinNp_Fp;
630
Result := (Cardinal(pixX) < Cardinal(FWidth)) and (Cardinal(pixY) <
634
begin //ignore anything that is behind the camera
642
function TGLzBuffer.WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY:
643
single; out pixZ: single): boolean; //OVERLOAD
646
x, y, z, invZ, v0, v1, zscal: single;
648
//---Takes x,y,z world coordinate. (aPoint)
649
//---Result is true if pixel lies within view frustrum
650
//---returns canvas pixel x,y coordinate, and CALCULATES the z-buffer distance
651
campos := cam.AbsolutePosition;
652
x := apoint.V[0] - camPos.V[0];
653
y := apoint.V[1] - camPos.V[1];
654
z := apoint.V[2] - camPos.V[2]; //get vector from camera to world point
656
x := c1 * v0 + s1 * z;
657
z := c1 * z - s1 * v0; //Rotate around Y-axis
659
y := c2 * v1 + s2 * z;
660
z := c2 * z - s2 * v1; //Rotate around X-axis
664
zscal := scal * invZ;
665
pixX := vw - x * zscal;
666
pixY := vh + y * zscal;
667
//------z:=(1-np/z)/(1-np/fp);------
668
// pixZ:=(1-np/z)/(1-np/fp);
669
pixZ := (1 - np * invZ) * invOneMinNp_Fp;
670
Result := (pixX >= 0) and (pixX < FWidth) and (pixY >= 0) and (pixY <
674
begin //ignore anything that is behind the camera
682
function TGLzBuffer.OrthWorldToPixelZ(const aPoint: TAffineVector; out pixX,
683
pixY: single; out pixZ: single): boolean;
688
campos := cam.AbsolutePosition;
689
x := apoint.V[0] - camPos.V[0];
690
y := apoint.V[1] - camPos.V[1];
691
z := apoint.V[2] - camPos.V[2]; //get vector from camera to world point
693
pixX := (x + OrthAddX) * OrthMulX;
694
pixY := (z + OrthAddY) * OrthMulY;
695
pixZ := (-y - np) * OrthInvDov; //(-y-np)/dov
696
Result := (pixX >= 0) and (pixX < FWidth) and (pixY >= 0) and (pixY <
701
// ------------------ TGLZShadows ------------------
707
constructor TGLZShadows.Create(AOwner: TComponent);
710
ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
711
FColor := TGLColor.Create(Self);
715
self.Tolerance := 0.015;
716
FTexHandle := TGLTextureHandle.Create;
721
destructor TGLZShadows.Destroy;
734
procedure TGLZShadows.BindTexture;
736
if FTexHandle.Handle = 0 then
740
with RenderingContext.GLStates do
742
TextureBinding[0, ttTexture2D] := Handle;
744
GL.Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_Fastest);
745
UnpackAlignment := 1;
746
UnpackRowLength := 0;
748
UnpackSkipPixels := 0;
750
GL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
751
GL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
753
ActiveTextureEnabled[ttTexture2D] := True;
754
SetBlendFunc(bfSRCALPHA, bfONEMINUSSRCALPHA);
755
GL.TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
763
RenderingContext.GLStates.TextureBinding[0, ttTexture2D] := Handle;
766
procedure TGLZShadows.PrepareAlphaMemory;
770
// ShowMessage(IntToStr(FWidth)+' '+IntToStr(FXRes));
771
FDataSize := FXRes * FYRes * 1;
772
ReallocMem(FData, FDataSize);
773
SetLength(FDataIdx, FYRes);
774
SetLength(FDataInvIdx, FYRes);
775
for i := 0 to FYres - 1 do
777
FDataIdx[i] := @FData[i * FXRes]; // range: [0..height-1]
778
FDataInvIdx[i] := @FData[(FYRes - i - 1) * FXRes]; // range: [0..height-1]
785
procedure TGLZShadows.DoRender(var ARci: TGLRenderContextInfo;
786
ARenderSelf, ARenderChildren: Boolean);
788
vx, vy, vx1, vy1: Single;
791
if not assigned(FViewer) then
793
if not assigned(FCaster) then
795
if not assigned(CasterZBuf) then
796
exit; //only render if a shadow has been cast
797
//only render in view-camera
798
if TGLSceneBuffer(ARci.buffer).Camera <> FViewer.Camera then
800
if not assigned(ViewerZBuf) then
801
begin //Create viewer zbuffer
802
ViewerZBuf := TGLZBuffer.Create;
803
ViewerZBuf.LinkToViewer(FViewer);
805
FTexturePrepared := False;
809
ARci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
810
ARci.GLStates.Enable(stBlend);
811
ARci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
813
if FWidth > ARci.viewPortSize.cx then
814
Fwidth := ARci.viewPortSize.cx;
815
if FHeight > ARci.viewPortSize.cy then
816
FHeight := ARci.viewPortSize.cy;
818
//-----------------------
819
CalcShadowTexture(ARci);
820
//-----------------------
821
ARci.GLStates.TextureBinding[0, ttTexture2D] := FTexHandle.Handle;
823
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
825
GL.Color3f(SCol.r, SCol.g, SCol.b);
827
if not FTexturePrepared then
829
GL.TexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, FXRes, FYRes, 0, GL_ALPHA,
830
GL_UNSIGNED_BYTE, @FData[0]);
831
FTexturePrepared := True;
834
GL.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, FXRes, FYRes, GL_ALPHA,
835
GL_UNSIGNED_BYTE, @FData[0]);
837
// NotifyChange(Self);
838
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
841
GL.MatrixMode(GL_MODELVIEW);
843
GL.LoadMatrixf(@TGLSceneBuffer(ARci.buffer).BaseProjectionMatrix);
844
GL.Scalef(2 / ARci.viewPortSize.cx, 2 / ARci.viewPortSize.cy, 1);
845
GL.Translatef(Position.X - ARci.viewPortSize.cx * 0.5,
846
ARci.viewPortSize.cy * 0.5 - Position.Y, Position.Z);
848
GL.MatrixMode(GL_PROJECTION);
851
ARci.GLStates.Disable(stDepthTest);
852
ARci.GLStates.Disable(stLighting);
859
Xtex := FWidth / FXres; //1
860
Ytex := 1 - (FHeight / FYres); //0
864
GL.Normal3fv(@YVector);
865
GL.TexCoord2f(0, ytex);
866
GL.Vertex2f(vx, vy1);
867
GL.TexCoord2f(xtex, ytex);
868
GL.Vertex2f(vx1, vy1);
869
GL.TexCoord2f(xtex, 1);
870
GL.Vertex2f(vx1, vy);
876
GL.MatrixMode(GL_MODELVIEW);
880
Self.RenderChildren(0, Count - 1, ARci);
883
procedure TGLZShadows.CalcShadowTexture(var rci: TGLRenderContextInfo);
885
pix, p0, p1, p2, p3, p4: Byte;
895
SCol.r := Round(FColor.Red * 255);
896
SCol.g := Round(FColor.green * 255);
897
SCol.b := Round(FColor.Blue * 255);
898
SCol.a := Round(FColor.Alpha * 255);
900
//-----------No optimising-----------
901
if FOptimise = opNone then
918
if FOptimise = op4in1 then
920
for x := 0 to fXres - 1 do
922
for x := 0 to fXres - 1 do
923
HardSet(x, fYres - 1);
924
for y := 1 to fYres - 1 do
926
for y := 1 to fYres - 1 do
927
HardSet(fXres - 1, y);
932
p1 := HardSet(x - 1, y - 2);
933
HardSet(x - 1, y - 1);
934
p0 := HardSet(x - 1, y);
937
pix := HardSet(x, y);
938
if (pix = p1) and (pix = p0) then
940
FDataInvIdx[y]^[x - 1] := pix;
941
FDataInvIdx[y - 1]^[x - 1] := pix;
946
HardSet(x - 1, y - 1);
948
p2 := SoftTest(x + 1, y - 2);
951
FDataInvIdx[y - 1]^[x] := pix
963
if FOptimise = op9in1 then
965
for x := 0 to fXres - 1 do
967
for x := 0 to fXres - 1 do
968
HardSet(x, fYres - 1);
969
for y := 0 to fYres - 1 do
970
HardSet(fXres - 1, y);
971
// for y:=1 to fYres-1 do HardSet(fXres-2,y);
977
p1 := HardSet(x - 3, y - 3);
978
// p2:=HardSet(x ,y-3);
979
p3 := HardSet(x - 3, y);
982
p2 := SoftTest(x, y - 3);
984
if ((p1 = p2) and (p3 = p4) and (p2 = p4)) then
986
xy := x + (fYres - (y - 3) - 1) * fXres;
989
xy := xy - w; //xy:=x+(fYres-(y-2)-1)*fXres;
993
xy := xy - w; //xy:=x+(fYres-(y-1)-1)*fXres;
1000
HardSet(x - 2, y - 3);
1001
HardSet(x - 1, y - 3);
1002
HardSet(x - 3, y - 2);
1003
HardSet(x - 2, y - 2);
1004
HardSet(x - 1, y - 2);
1005
HardSet(x - 3, y - 1);
1006
HardSet(x - 2, y - 1);
1007
HardSet(x - 1, y - 1);
1020
if FOptimise = op16in1 then
1024
while (y <> FHeight + 3) do
1026
if y >= FHeight then
1030
p1 := HardSet(x - 4, y - 4);
1031
// HardSet(x ,y-4); //p2
1032
p3 := HardSet(x - 4, y);
1033
while (x <> fWidth + 3) do
1038
p2 := SoftTest(x, y - 4);
1039
p4 := HardSet(x, y);
1041
if ((p1 = p2) and (p3 = p4) and (p2 = p4)) then
1043
xy := x + (h - (y - 4) - 1) * w;
1044
pixa^[xy - 3] := p4;
1045
pixa^[xy - 2] := p4;
1046
pixa^[xy - 1] := p4;
1048
pixa^[xy - 4] := p4;
1049
pixa^[xy - 3] := p4;
1050
pixa^[xy - 2] := p4;
1051
pixa^[xy - 1] := p4;
1053
pixa^[xy - 4] := p4;
1054
pixa^[xy - 3] := p4;
1055
pixa^[xy - 2] := p4;
1056
pixa^[xy - 1] := p4;
1058
pixa^[xy - 4] := p4;
1059
pixa^[xy - 3] := p4;
1060
pixa^[xy - 2] := p4;
1061
pixa^[xy - 1] := p4;
1065
//--------------------------------------------
1066
pM := HardSet(x - 2, y - 2);
1067
pL := HardSet(x - 4, y - 2);
1068
pT := HardSet(x - 2, y - 4);
1070
xy := x + (h - (y - 4) - 1) * w;
1074
HardSet(x - 3, y - 4);
1078
HardSet(x - 1, y - 4);
1079
xy := xy - w; //down
1083
HardSet(x - 4, y - 3);
1087
HardSet(x - 3, y - 3);
1091
HardSet(x - 1, y - 3); //p2m
1095
HardSet(x - 2, y - 3);
1096
xy := xy - w; //down
1100
HardSet(x - 3, y - 2);
1101
xy := xy - w; //down
1105
HardSet(x - 4, y - 1);
1109
HardSet(x - 3, y - 1); //p3m
1112
pixa^[xy - 1] := pM;
1114
pixa^[xy + w - 1] := pM
1116
HardSet(x - 1, y - 2);
1120
HardSet(x - 2, y - 1);
1124
HardSet(x - 1, y - 1); //p4m
1125
HardSet(x - 1, y - 2);
1126
HardSet(x - 2, y - 1);
1135
until y > (FHeight - 2);
1137
for x := 0 to FWidth - 1 do
1138
FDataIdx[0][x] := FDataIdx[1][x];
1139
for y := 0 to FHeight - 1 do
1140
FDataIdx[y][FWidth - 1] := FDataIdx[y][FWidth - 2];
1144
function TGLZShadows.HardSet(const x, y: integer): Byte;
1148
coord: TAffineVector;
1150
ipixX, ipixY: integer;
1160
d2, d4, d5, d6, d8: single;
1161
shad2, shad4, shad5, shad6, shad8: single;
1163
function ComputeIlum: Integer;
1166
if FDepthFade = True then
1168
Result := Round(SCol.a * (pixZ * 10 - 9));
1171
//if ilum>255 then ilum:=255;
1172
if Result > SCol.a then
1180
//---test pixel for shadow---
1181
if ViewerZBuf.GetPixelzDepth(x, y) < 1 then
1183
coord := ViewerZBuf.PixelToWorld(x, y);
1184
IsInFrust := CasterZBuf.WorldToPixelZ(coord, pixX, pixY, pixZ);
1185
//if caster.Camera.CameraStyle=csOrthogonal then IsInFrust:=CasterZBuf.OrthWorldToPixelZ(coord,pixX,pixY,pixZ);
1186
//--- Tolerance scaling - reduces shadow-creeping at long-range and self-shadowing at short-range ---
1187
tol := FTolerance * (1.0 - pixZ);
1188
//--- ilum=light ------ SCol.a=shade ------
1189
if not isInFrust then
1191
if FFrustShadow then
1192
pix := SCol.a //dark outside frustrum
1194
pix := ComputeIlum; //light outside frustrum
1198
ipixX := Trunc(pixX);
1199
ipixY := Trunc(pixY);
1200
if (FSoft = True) and (ipixY > 0) then
1201
begin //---soft shadows---
1203
//extract the fraction part only - used to interpolate soft shadow edges
1207
d4 := CasterZBuf.DataIdx[ipixY]^[ipixX - 1]
1209
d4 := CasterZBuf.DataIdx[ipixY]^[0];
1211
d5 := CasterZBuf.DataIdx[ipixY]^[ipixX];
1212
d6 := CasterZBuf.DataIdx[ipixY]^[ipixX + 1];
1213
d8 := CasterZBuf.DataIdx[ipixY + 1]^[ipixX];
1214
// if ipixY<1 then d2:=d5 else
1215
d2 := CasterZBuf.DataIdx[ipixY - 1]^[ipixX];
1216
ilum := ComputeIlum;
1218
if ((pixZ - d2) > Tol) then
1222
if ((pixZ - d4) > Tol) then
1226
if ((pixZ - d5) > Tol) then
1230
if ((pixZ - d6) > Tol) then
1234
if ((pixZ - d8) > Tol) then
1238
shad := shad2 + (shad8 - shad2) * mody +
1239
shad4 + (shad6 - shad4) * modx + shad5;
1240
pix := Round(Shad / 3);
1244
begin //---hard shadows---
1245
if pixZ - Tol > CasterZBuf.DataIdx[ipixY]^[ipixX] then
1246
pix := SCol.a //dark
1248
pix := ComputeIlum; //light
1253
begin // if z=1 ... i.e. nothing was drawn at this pixel (sky)
1255
pix := SCol.a // dark
1257
pix := 0; //ComputeIlum; // light
1259
FDataInvIdx[y]^[x] := pix; //Write pixel
1263
function TGLZShadows.SoftTest(const x, y: integer): Byte;
1265
result := FDataInvIdx[y]^[x];
1268
function TGLZShadows.GetViewer: TGLSceneViewer;
1273
procedure TGLZShadows.SetViewer(const val: TGLSceneViewer);
1276
Width := FViewer.Width;
1277
Height := FViewer.Height;
1280
function TGLZShadows.GetCaster: TGLMemoryViewer;
1285
procedure TGLZShadows.SetCaster(const val: TGLMemoryViewer);
1290
function TGLZShadows.CastShadow: Boolean;
1292
if Caster <> nil then
1294
if not assigned(CasterZBuf) then
1296
CasterZBuf := TGLZBuffer.Create;
1297
CasterZBuf.LinkToViewer(FCaster);
1300
if FCaster.Camera.CameraStyle = csOrthogonal then
1302
if assigned(FCaster.Camera.TargetObject) then
1304
FCaster.Camera.Position.x := FCaster.Camera.TargetObject.Position.x;
1305
FCaster.Camera.Position.z := FCaster.Camera.TargetObject.Position.z;
1307
with FCaster.Camera.direction do
1318
Caster := nil; // prevents further attempts
1329
procedure TGLZShadows.SetWidth(const val: integer);
1335
procedure TGLZShadows.SetHeight(const val: integer);
1341
procedure TGLZShadows.SetXRes(const val: integer);
1348
FXRes := i; //calculate the closest power of 2, smaller than val
1349
FTexturePrepared := False;
1353
procedure TGLZShadows.SetYRes(const val: integer);
1360
FYRes := i; //calculate the closest power of 2, larger than val
1361
FTexturePrepared := False;
1365
procedure TGLZShadows.SetSoft(const val: boolean);
1371
// ------------------------------------------------------------------
1372
// ------------------------------------------------------------------
1373
// ------------------------------------------------------------------
1375
// ------------------------------------------------------------------
1376
// ------------------------------------------------------------------
1377
// ------------------------------------------------------------------
1379
// class registrations
1380
RegisterClasses([TGLZShadows]);