forked from gbegreg/GBE3D
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGBEPlaneExtend.pas
230 lines (195 loc) · 8.16 KB
/
GBEPlaneExtend.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
unit GBEPlaneExtend; // Om: GBEPlaneExtend implements a rectangular mesh with oe source of sin wave
//------------------//
// Om: Extended TWaveRec to calc amplitude and pitch
// Om: added excessive comments to help understanding Gregorys code
interface
uses
System.SysUtils, System.Classes, FMX.Types, FMX.Controls3D, FMX.Objects3D, System.Math.Vectors, FMX.Types3D, generics.Collections,
System.Threading, FMX.MaterialSources;
type
TWaveRec = record // calculates sin() wave amplitude at a given P (x,y)
P, // wave origin
D : TPoint3D; // wave params D = Point3D( MaxAmplitude, WaveLenght, WaveSpeed )
function Wave(aSum, aX, aY, aT : single):Single;
function calcWaveAmplitudeAndPitch(aCap, aX, aY, aT : single; var aSumAmplitude,aSumDerivative:Single):boolean;
end;
TGBEPlaneExtend = class( TPlane )
private
fAmplitude, fLongueur, fVitesse : single; //wave 1
fOrigine: TPoint3D;
{ Déclarations privées }
procedure CalcWaves(D : TPoint3D); // D = Point3D(fAmplitude, fLongueur, fVitesse)
protected
fTime:Single; //Om: movd stuff to protected
fNbMesh : integer; // number of tiles in the mesh
fActiveWaves, fShowlines, fUseTasks : boolean;
fMaterialLignes: TColorMaterialSource;
fCenter : TPoint3D;
{ Déclarations protégées }
public
{ Déclarations publiques }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Render; override;
// Property Data; //om: publica
function Altura(P:TPoint3d):Single; //Om: calc wave amplitude on a point
published
{ Déclarations publiées }
property ActiveWaves : boolean read fActiveWaves write fActiveWaves;
property Origine : TPoint3D read fOrigine write fOrigine;
property Amplitude : single read fAmplitude write fAmplitude;
property Longueur : single read fLongueur write fLongueur;
property Vitesse : single read fVitesse write fVitesse;
property ShowLines: boolean read fShowlines write fShowLines;
property UseTasks : boolean read fUseTasks write fUseTasks;
property MaterialLines : TColorMaterialSource read fMaterialLignes write fMaterialLignes;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('GBE3D', [TGBEPlaneExtend]);
end;
{ TWaveRec }
// wave world is x,y . z is the wave height ( amplitude )
// /y
// +---------/---------+
// / ^ ^ / ^ ^ /
// /---------+---------+----x
// / ^ / ^ /
// +---------/---------+
//
function TWaveRec.Wave(aSum, aX, aY, aT: single): Single; // sums. Here aX,aY are in div units ( not m )
var L,Ph:single;
begin
L := P.Distance( Point3d(aX,aY,0) ); // L= dist to sin wave origin
Result := aSum; // start w/ previous sum, so we add wave amplitudes of different waves
// D.x = MaxAmplitude in div ?
// D.y = WaveLenght in div
// D.z = WaveSpeed in div/s
if (D.Y>0) and (D.x>0) then // ignore if wave length<=0 Om: ..or Amplitude=0 ( which produces no effect )
begin
Ph := L/D.y - D.z*aT; // calc wave phase at the point
Result := Result + D.x * sin(Ph)*0.001; // sum sin() wave amplitude / 1000 ( result inside +- MaxAmplitude*0.001 )
end;
end;
// here wave world is in x,y z is the wave height ( amplitude )
function TWaveRec.calcWaveAmplitudeAndPitch(aCap, aX, aY, aT : single; var aSumAmplitude,aSumDerivative:Single):boolean;
var L,L0,L1,Ph,Ph0,Ph1,aAng,aAmp,aAmp0,aAmp1,aDeriv,DzaT:single;
aP,P0,P1,DP:TPoint3D;
begin
Result := true; // always
aP := Point3d(aX,aY,0); // requested coordinate
L := P.Distance( aP ); // L= dist to sin wave origin P
if (D.Y>0) and (D.x>0) then // ignore if wave length D.Y <= 0 or Amplitude D.x <=0
begin
Result := true;
DzaT := D.z*aT; // memoise speed*DT (=wave displacement)
Ph := L/D.y - DzaT; // calc wave phase at the point P
aAmp := D.x * sin(Ph) * 0.001; // add sin() wave amplitude / 1000 ( result inside +- MaxAmplitude*0.001 )
// P.z := aAmp; //dont do that !
// calc directional derivative
aAng := -aCap*Pi/180; // cap to radians
DP := Point3d(sin(aAng), cos(aAng), 0)/2; // semi displacement vector in boat direction dir
// P0=pt 1/2 div before
P0 := aP - DP; // move .5 unit in -cap direction
L0 := P.Distance( P0 ); // calc amplitude for P0
Ph0 := L0/D.y - DzaT;
aAmp0 := D.x * sin(Ph0) * 0.001; // add sin() wave amplitude / 1000 ( result inside +- MaxAmplitude*0.001 )
// P1=pt 1/2 div after
P1 := aP + DP/2; // move 0.5 unit in cap direction
L1 := P.Distance( P1 ); //calc amplitude for P1
Ph1 := L1/D.y - DzaT;
aAmp1 := D.x * sin(Ph1) * 0.001;
// derivative calculated from -0.5 to +0.5 div
aDeriv := (aAmp1-aAmp0); // directional derivative calculated in P0-P1
// add amplitude to sum
aSumAmplitude := aSumAmplitude + aAmp; // accumulate
aSumDerivative := aSumDerivative + aDeriv; // derivative of sum = sum of derivatives
end;
end;
{ TGBEPlaneExtend }
procedure TGBEPlaneExtend.CalcWaves(D : TPoint3D); // D = Point3D(Amplitude, Longueur, Vitesse)
var
M:TMeshData;
x,y : integer;
somme: single;
front, back : PPoint3D;
waveRec : TWaveRec;
begin
M := self.Data;
// init waveRec
waveRec.P := Point3d( SubdivisionsWidth, SubdivisionsHeight, 0)*0.5 + fOrigine*fCenter;
waveRec.D := D;
for y := 0 to SubdivisionsHeight do // 0..30 ( 30 divisions )
for x := 0 to SubdivisionsWidth do
begin
front := M.VertexBuffer.VerticesPtr[X + (Y * (SubdivisionsWidth+1))];
back := M.VertexBuffer.VerticesPtr[fNbMesh + X + (Y * (SubdivisionsWidth+1))];
somme := 0;
somme := waveRec.Wave(somme, x, y, fTime);
somme := somme * 100;
Front^.Z := somme;
Back^.Z := somme;
end;
M.CalcTangentBinormals;
fTime := fTime + 0.01; // adv wave time by 0.01 seg. Should be 0.2s ? ( the animation speed )
end;
function TGBEPlaneExtend.Altura(P:TPoint3d):Single; //Om:
var
M:TMeshData;
x,y : integer;
front, back : PPoint3D;
begin
M := self.Data;
x := Round( P.x );
y := Round( P.y );
if (x>=0) and (x<SubdivisionsWidth) and (y>0) and (y<SubdivisionsHeight) then
begin
front := M.VertexBuffer.VerticesPtr[X + (Y * (SubdivisionsWidth+1))];
back := M.VertexBuffer.VerticesPtr[fNbMesh + X + (Y * (SubdivisionsWidth+1))];
Result := (front^.Z+back^.Z)/2; //??
end
else Result := 0;
end;
constructor TGBEPlaneExtend.Create(AOwner: TComponent);
begin
inherited;
fTime := 0; // wave time
fAmplitude := 1; // wave params
fLongueur := 1; // Om: only 1 ?
fVitesse := 5; //
self.SubdivisionsHeight := 30; // plane subdivisions
self.SubdivisionsWidth := 30;
fOrigine := Point3D(self.SubdivisionsWidth / self.Width, self.SubdivisionsHeight / self.Height, 2);
fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
// fCenter = SubD / width ( unit div/m )
fCenter := Point3D( SubdivisionsWidth / self.Width, SubdivisionsHeight / self.Height, 0);
fUseTasks := true; //default= using tasks
end;
destructor TGBEPlaneExtend.Destroy;
begin
inherited;
end;
procedure TGBEPlaneExtend.Render;
var W1:TPoint3D;
begin
inherited;
if fActiveWaves then
begin
W1 := Point3D(fAmplitude, fLongueur, fVitesse);
if fUseTasks then
begin
TTask.Create( procedure
begin
CalcWaves(W1); // recalc mesh
end).start;
end
else begin
CalcWaves(W1);
end;
end;
if ShowLines then
Context.DrawLines(self.Data.VertexBuffer, self.Data.IndexBuffer, TMaterialSource.ValidMaterial(fMaterialLignes), 1);
end;
end.