LZScene

Форк
0
/
GLBumpShader.pas 
935 строк · 29.1 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
   A shader that applies bump mapping.
6

7
   Notes:
8
   The normal map is expected to be the primary texture.
9

10
   The secondary texture is used for the diffuse texture,
11
   to enable set boDiffuseTexture2 in the BumpOptions property.
12

13
   The tertiary texture is used for the specular texture,
14
   to enable set boSpecularTexture3 in the BumpOptions property.
15
   The SpecularMode determines the specular highlight calculation
16
   (Blinn or Phong), smOff disables specular highlights in the
17
   shader.
18

19
   External tangent bump space expects tangent data under
20
   GL_TEXTURE1_ARB and binormal data under GL_TEXTURE2_ARB.
21

22
   The boUseSecondaryTexCoords bump option tells the shader to use
23
   the secondary texture coordinates for the diffuse and specular
24
   texture lookups.
25

26
    History :  
27
       23/08/10 - Yar - Upgraded program hadles
28
       22/04/10 - Yar - Fixes after GLState revision
29
       05/03/10 - DanB - More state added to TGLStateCache
30
       06/06/07 - DaStr - Added GLColor to uses (BugtrackerID = 1732211)
31
       31/03/07 - DaStr - Added $I GLScene.inc
32
       25/02/07 - DaStr - Moved registration to GLSceneRegister.pas
33
       15/04/05 - SG - Added parallax offset mapping for the BasicARBfp bump method (experimental)
34
                          Height data is expected in the normal map alpha channel.
35
       21/12/04 - SG - Added light attenutation support through the
36
                          boLightAttenutation option in the BumpOptions property.
37
       27/10/04 - SG - Added boUseSecondaryTexCoords option to BumpOptions
38
       11/10/04 - SG - Added SpecularMode to define the specular highlight equation,
39
                          Removed the boDisableSpecular bump option (depricated).
40
       06/10/04 - SG - Added special functions for generating the ARB programs
41
                          which replace the string constants.
42
       02/10/04 - SG - Changed render order a little, minimum texture units
43
                          is now 2 for dot3 texcombiner bump method.
44
                          Changed vertex programs to accept local program
45
                          params, now only 1 vertex and 1 fragment program is
46
                          required for all lights.
47
                          Vertex programs now apply the primary texture matrix.
48
       30/09/04 - SG - Added fragment program logic,
49
                          Added bmBasicARBFP bump method, bsTangentExternal
50
                          bump space and associated ARB programs,
51
                          Various name changes and fixes
52
       28/09/04 - SG - Vertex programs now use ARB_position_invariant option.
53
       29/06/04 - SG - Quaternion tangent space fix in tangent bump vertex
54
                          program.
55
       23/06/04 - SG - Added bsTangent option to TBumpSpace,
56
                          Added tangent space light vector vertex program.
57
       22/06/04 - SG - Creation.
58
    
59
}
60
unit GLBumpShader;
61

62
interface
63

64
{$I GLScene.inc}
65

66
uses
67
  Classes, SysUtils,
68
   
69
  GLMaterial, GLGraphics, GLUtils, GLVectorGeometry, OpenGLTokens,
70
  GLContext, GLVectorLists, GLColor, GLRenderContextInfo, GLState,
71
  GLTextureFormat;
72

73
type
74
  TBumpMethod = (bmDot3TexCombiner, bmBasicARBFP);
75

76
  TBumpSpace = (bsObject, bsTangentExternal, bsTangentQuaternion);
77

78
  TBumpOption = (boDiffuseTexture2, // Use secondary texture as diffuse
79
    boSpecularTexture3, // Use tertiary texture as specular
80
    boUseSecondaryTexCoords, // Pass through secondary texcoords
81
    boLightAttenuation, // Use light attenuation
82
    boParallaxMapping // Enable parallax offset mapping
83
    );
84
  TBumpOptions = set of TBumpOption;
85

86
  TSpecularMode = (smOff, smBlinn, smPhong);
87

88
  // TGLBumpShader
89
  //
90
  { A generic bump shader. }
91
  TGLBumpShader = class(TGLShader)
92
  private
93
    FVertexProgramHandle: TGLARBVertexProgramHandle;
94
    FFragmentProgramHandle: TGLARBFragmentProgramHandle;
95
    FLightIDs: TIntegerList;
96
    FLightsEnabled: Integer;
97
    FBumpMethod: TBumpMethod;
98
    FBumpSpace: TBumpSpace;
99
    FBumpOptions: TBumpOptions;
100
    FSpecularMode: TSpecularMode;
101
    FDesignTimeEnabled: Boolean;
102
    FAmbientPass: Boolean;
103
    FDiffusePass: Boolean;
104
    FVertexProgram: TStringList;
105
    FFragmentProgram: TStringList;
106
    FParallaxOffset: Single;
107

108
    function GenerateVertexProgram: string;
109
    function GenerateFragmentProgram: string;
110
    procedure DoLightPass(var rci: TGLRenderContextInfo; lightID: Cardinal);
111

112
  protected
113
    procedure SetBumpMethod(const Value: TBumpMethod);
114
    procedure SetBumpSpace(const Value: TBumpSpace);
115
    procedure SetBumpOptions(const Value: TBumpOptions);
116
    procedure SetSpecularMode(const Value: TSpecularMode);
117
    procedure SetDesignTimeEnabled(const Value: Boolean);
118
    procedure SetParallaxOffset(const Value: Single);
119
    procedure Loaded; override;
120
    procedure DeleteVertexPrograms;
121
    procedure DeleteFragmentPrograms;
122

123
  public
124
    constructor Create(AOwner: TComponent); override;
125
    destructor Destroy; override;
126

127
    procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
128
    function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
129

130
  published
131
    property BumpMethod: TBumpMethod read FBumpMethod write SetBumpMethod;
132
    property BumpSpace: TBumpSpace read FBumpSpace write SetBumpSpace;
133
    property BumpOptions: TBumpOptions read FBumpOptions write SetBumpOptions;
134
    property SpecularMode: TSpecularMode read FSpecularMode write
135
      SetSpecularMode;
136
    property DesignTimeEnabled: Boolean read FDesignTimeEnabled write
137
      SetDesignTimeEnabled;
138
    property ParallaxOffset: Single read FParallaxOffset write
139
      SetParallaxOffset;
140

141
  end;
142

143
  // ------------------------------------------------------------------
144
  // ------------------------------------------------------------------
145
  // ------------------------------------------------------------------
146
implementation
147
// ------------------------------------------------------------------
148
// ------------------------------------------------------------------
149
// ------------------------------------------------------------------
150

151
// ------------------
152
// ------------------ TGLBumpShader ------------------
153
// ------------------
154

155
// Create
156
//
157

158
constructor TGLBumpShader.Create(AOwner: TComponent);
159
begin
160
  inherited;
161
  FLightIDs := TIntegerList.Create;
162
  FBumpMethod := bmDot3TexCombiner;
163
  FBumpSpace := bsObject;
164
  FBumpOptions := [];
165
  FSpecularMode := smOff;
166
  ShaderStyle := ssLowLevel;
167
  FParallaxOffset := 0.04;
168

169
  FVertexProgram := TStringList.Create;
170
  FFragmentProgram := TStringList.Create;
171
end;
172

173
// Destroy
174
//
175

176
destructor TGLBumpShader.Destroy;
177
begin
178
  DeleteVertexPrograms;
179
  DeleteFragmentPrograms;
180
  FLightIDs.Free;
181
  FVertexProgram.Free;
182
  FFragmentProgram.Free;
183
  inherited;
184
end;
185

186
// Loaded
187
//
188

189
procedure TGLBumpShader.Loaded;
190
begin
191
  inherited;
192
end;
193

194
// GenerateVertexProgram
195
//
196

197
function TGLBumpShader.GenerateVertexProgram: string;
198
var
199
  VP: TStringList;
200
  DoTangent, DoSpecular, DoParallaxOffset: Boolean;
201
  texcoord: Integer;
202
begin
203
  DoSpecular := (BumpMethod = bmBasicARBFP) and not (SpecularMode = smOff);
204
  DoTangent := (BumpSpace = bsTangentExternal) or (BumpSpace =
205
    bsTangentQuaternion);
206
  DoParallaxOffset := (BumpMethod = bmBasicARBFP) and (boParallaxMapping in
207
    BumpOptions) and DoTangent;
208

209
  VP := TStringList.Create;
210

211
  VP.Add('!!ARBvp1.0');
212
  VP.Add('OPTION ARB_position_invariant;');
213

214
  VP.Add('PARAM mv[4] = { state.matrix.modelview };');
215
  VP.Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
216
  VP.Add('PARAM mvit[4] = { state.matrix.modelview.invtrans };');
217
  VP.Add('PARAM tex[4] = { state.matrix.texture[0] };');
218
  if boUseSecondaryTexCoords in BumpOptions then
219
    VP.Add('PARAM tex2[4] = { state.matrix.texture[1] };');
220
  VP.Add('PARAM lightPos = program.local[0];');
221
  VP.Add('PARAM lightAtten = program.local[1];');
222
  if BumpSpace = bsTangentExternal then
223
  begin
224
    VP.Add('ATTRIB tangent = vertex.texcoord[1];');
225
    VP.Add('ATTRIB binormal = vertex.texcoord[2];');
226
    VP.Add('ATTRIB normal = vertex.normal;');
227
  end;
228
  VP.Add('TEMP temp, temp2, light, eye, atten;');
229

230
  if (boLightAttenuation in BumpOptions) then
231
  begin
232

233
    VP.Add('   DP4 temp.x, mv[0], vertex.position;');
234
    VP.Add('   DP4 temp.y, mv[1], vertex.position;');
235
    VP.Add('   DP4 temp.z, mv[2], vertex.position;');
236
    VP.Add('   ADD light, lightPos, -temp;');
237

238
    VP.Add('   DP3 atten.y, light, light;');
239
    VP.Add('   RSQ atten.y, atten.y;');
240
    if BumpMethod = bmDot3TexCombiner then
241
    begin
242
      VP.Add('   RCP atten.y, atten.y;');
243
      VP.Add('   MUL atten.z, atten.y, atten.y;');
244
      VP.Add('   MAD atten.x, lightAtten.y, atten.y, lightAtten.x;');
245
      VP.Add('   MAD atten.x, lightAtten.z, atten.z, atten.x;');
246
      VP.Add('   RCP atten.x, atten.x;');
247
    end
248
    else if BumpMethod = bmBasicARBFP then
249
    begin
250
      // Store the distance in atten.x for ARBFP,
251
      // fragment program will calculate attenutation
252
      VP.Add('   RCP atten.x, atten.y;');
253
    end;
254

255
    VP.Add('   DP3 temp.x, mvinv[0], light;');
256
    VP.Add('   DP3 temp.y, mvinv[1], light;');
257
    VP.Add('   DP3 temp.z, mvinv[2], light;');
258
    VP.Add('   MOV light, temp;');
259
  end
260
  else
261
  begin
262
    VP.Add('   DP4 light.x, mvinv[0], lightPos;');
263
    VP.Add('   DP4 light.y, mvinv[1], lightPos;');
264
    VP.Add('   DP4 light.z, mvinv[2], lightPos;');
265
    VP.Add('   ADD light, light, -vertex.position;');
266
  end;
267

268
  if DoSpecular or DoParallaxOffset then
269
    VP.Add('   ADD eye, mvit[3], -vertex.position;');
270

271
  if DoTangent then
272
  begin
273
    if BumpSpace = bsTangentExternal then
274
    begin
275

276
      VP.Add('   DP3 temp.x, light, tangent;');
277
      VP.Add('   DP3 temp.y, light, binormal;');
278
      VP.Add('   DP3 temp.z, light, normal;');
279
      VP.Add('   MOV light, temp;');
280
      if DoSpecular or DoParallaxOffset then
281
      begin
282
        VP.Add('   DP3 temp.x, eye, tangent;');
283
        VP.Add('   DP3 temp.y, eye, binormal;');
284
        VP.Add('   DP3 temp.z, eye, normal;');
285
        VP.Add('   MOV eye, temp;');
286
      end;
287

288
    end
289
    else if BumpSpace = bsTangentQuaternion then
290
    begin
291

292
      VP.Add('   DP3 temp.x, light, light;');
293
      VP.Add('   RSQ temp.x, temp.x;');
294
      VP.Add('   MUL light, temp.x, light;');
295

296
      VP.Add('   MOV temp2.x, vertex.normal.y;');
297
      VP.Add('   ADD temp2.y, 0.0, -vertex.normal.x;');
298
      VP.Add('   MOV temp2.z, 0.0;');
299

300
      VP.Add('   DP3 temp.x, temp2, light;');
301
      VP.Add('   MUL temp.x, temp2.y, light.z;');
302
      VP.Add('   MAD temp.y, vertex.normal.z, light.x, temp.x;');
303
      VP.Add('   MUL temp.x, vertex.normal.y, light.z;');
304
      VP.Add('   MAD temp.z, vertex.normal.z, light.y, -temp.x;');
305
      VP.Add('   MUL temp.x, vertex.normal.y, light.y;');
306
      VP.Add('   MAD temp.x, vertex.normal.z, light.z, temp.x;');
307
      VP.Add('   MAD temp.w, -temp2.y, light.x, temp.x;');
308
      VP.Add('   MOV light, temp.yzwy;');
309

310
      if DoSpecular or DoParallaxOffset then
311
      begin
312
        VP.Add('   DP3 temp.x, temp2, eye;');
313
        VP.Add('   MUL temp.x, temp2.y, eye.z;');
314
        VP.Add('   MAD temp.y, vertex.normal.z, eye.x, temp.x;');
315
        VP.Add('   MUL temp.x, vertex.normal.y, eye.z;');
316
        VP.Add('   MAD temp.z, vertex.normal.z, eye.y, -temp.x;');
317
        VP.Add('   MUL temp.x, vertex.normal.y, eye.y;');
318
        VP.Add('   MAD temp.x, vertex.normal.z, eye.z, temp.x;');
319
        VP.Add('   MAD temp.w, -temp2.y, eye.x, temp.x;');
320
        VP.Add('   MOV eye, temp.yzwy;');
321
      end;
322

323
    end;
324
  end;
325

326
  if BumpMethod = bmDot3TexCombiner then
327
  begin
328

329
    if BumpSpace <> bsTangentQuaternion then
330
    begin
331
      VP.Add('   DP3 temp.x, light, light;');
332
      VP.Add('   RSQ temp, temp.x;');
333
      VP.Add('   MUL light, temp.x, light;');
334
    end;
335

336
    if boLightAttenuation in BumpOptions then
337
      VP.Add('   MUL light, atten.x, light;');
338

339
    VP.Add('   MAD result.color, light, 0.5, 0.5;');
340
    VP.Add('   MOV result.color.w, 1.0;');
341

342
  end
343
  else if BumpMethod = bmBasicARBFP then
344
  begin
345

346
    if boLightAttenuation in BumpOptions then
347
      VP.Add('   MOV light.w, atten.x;')
348
    else
349
      VP.Add('   MOV light.w, 0.0;');
350
    if DoSpecular or DoParallaxOffset then
351
      VP.Add('   MOV eye.w, 0.0;');
352

353
  end;
354

355
  texcoord := 0;
356

357
  VP.Add('   DP4 temp.x, vertex.texcoord[0], tex[0];');
358
  VP.Add('   DP4 temp.y, vertex.texcoord[0], tex[1];');
359
  VP.Add('   DP4 temp.z, vertex.texcoord[0], tex[2];');
360
  VP.Add('   DP4 temp.w, vertex.texcoord[0], tex[3];');
361
  VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
362
  Inc(texcoord);
363

364
  if boUseSecondaryTexCoords in BumpOptions then
365
  begin
366
    VP.Add('   DP4 temp.x, vertex.texcoord[1], tex2[0];');
367
    VP.Add('   DP4 temp.y, vertex.texcoord[1], tex2[1];');
368
    VP.Add('   DP4 temp.z, vertex.texcoord[1], tex2[2];');
369
    VP.Add('   DP4 temp.w, vertex.texcoord[1], tex2[3];');
370
    VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
371
    Inc(texcoord);
372
  end;
373

374
  if BumpMethod = bmDot3TexCombiner then
375
  begin
376
    if (boDiffuseTexture2 in BumpOptions)
377
      and not (boUseSecondaryTexCoords in BumpOptions) then
378
      VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
379
  end
380
  else
381
  begin
382
    VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], light;');
383
    Inc(texcoord);
384
    if DoSpecular then
385
      VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], eye;');
386
  end;
387

388
  VP.Add('END');
389

390
  FVertexProgram.Assign(VP);
391
  Result := VP.Text;
392
  VP.Free;
393
end;
394

395
// GenerateFragmentProgram
396
//
397

398
function TGLBumpShader.GenerateFragmentProgram: string;
399
var
400
  FP: TStringList;
401
  DoSpecular,
402
    DoTangent,
403
    DoParallaxOffset: Boolean;
404
  texcoord,
405
    normalTexCoords,
406
    diffTexCoords,
407
    specTexCoords,
408
    lightTexCoords,
409
    eyeTexCoords: Integer;
410
begin
411
  DoSpecular := not (SpecularMode = smOff);
412
  DoTangent := (BumpSpace = bsTangentExternal) or (BumpSpace =
413
    bsTangentQuaternion);
414
  DoParallaxOffset := (boParallaxMapping in BumpOptions) and DoTangent;
415

416
  texcoord := 0;
417
  normalTexCoords := texcoord;
418
  if boUseSecondaryTexCoords in BumpOptions then
419
    Inc(texcoord);
420
  diffTexCoords := texcoord;
421
  specTexCoords := texcoord;
422
  Inc(texcoord);
423
  lightTexCoords := texcoord;
424
  Inc(texcoord);
425
  eyeTexCoords := texcoord;
426

427
  FP := TStringList.Create;
428

429
  FP.Add('!!ARBfp1.0');
430

431
  FP.Add('PARAM lightDiffuse = program.local[0];');
432
  FP.Add('PARAM lightSpecular = program.local[1];');
433
  FP.Add('PARAM lightAtten = program.local[2];');
434
  FP.Add('PARAM materialDiffuse = state.material.diffuse;');
435
  FP.Add('PARAM materialSpecular = state.material.specular;');
436
  FP.Add('PARAM shininess = state.material.shininess;');
437
  FP.Add('TEMP temp, tex, light, eye, normal, col, diff, spec;');
438
  FP.Add('TEMP textureColor, reflect, atten, offset, texcoord;');
439

440
  if DoSpecular or DoParallaxOffset then
441
  begin
442
    // Get the eye vector
443
    FP.Add('   DP3 eye, fragment.texcoord[' + IntToStr(eyeTexCoords) +
444
      '], fragment.texcoord[' + IntToStr(eyeTexCoords) + '];');
445
    FP.Add('   RSQ eye, eye.x;');
446
    FP.Add('   MUL eye, fragment.texcoord[' + IntToStr(eyeTexCoords) +
447
      '], eye.x;');
448
  end;
449

450
  if DoParallaxOffset then
451
  begin
452
    // Get the parallax offset
453
    FP.Add('   TEX textureColor, fragment.texcoord[' + IntToStr(normalTexCoords)
454
      + '], texture[0], 2D;');
455
    FP.Add(Format('   MAD offset.x, textureColor.a, %f, %f;', [FParallaxOffset,
456
      -0.5 * FParallaxOffset]));
457
    FP.Add('   MUL offset, eye, offset.x;');
458
    FP.Add('   ADD texcoord, fragment.texcoord[' + IntToStr(normalTexCoords) +
459
      '], offset;');
460
  end
461
  else
462
    FP.Add('   MOV texcoord, fragment.texcoord[' + IntToStr(normalTexCoords) +
463
      '];');
464

465
  // Get the normalized normal vector
466
  FP.Add('   TEX textureColor, texcoord, texture[0], 2D;');
467
  FP.Add('   ADD normal, textureColor, -0.5;');
468
  FP.Add('   DP3 temp, normal, normal;');
469
  FP.Add('   RSQ temp, temp.x;');
470
  FP.Add('   MUL normal, normal, temp.x;');
471

472
  // Get the normalized light vector
473
  FP.Add('   MOV light, fragment.texcoord[' + IntToStr(lightTexCoords) + '];');
474
  if boLightAttenuation in BumpOptions then
475
    FP.Add('   MOV atten.x, light.w;');
476
  FP.Add('   DP3 light, light, light;');
477
  FP.Add('   RSQ light, light.x;');
478
  FP.Add('   MUL light, fragment.texcoord[' + IntToStr(lightTexCoords) +
479
    '], light.x;');
480

481
  // Calculate the diffuse color
482
  FP.Add('   DP3 diff, normal, light;');
483
  FP.Add('   MUL diff, diff, lightDiffuse;');
484
  FP.Add('   MUL diff, diff, materialDiffuse;');
485
  if boDiffuseTexture2 in BumpOptions then
486
  begin
487
    if DoParallaxOffset then
488
    begin
489
      FP.Add('   ADD temp, fragment.texcoord[' + IntToStr(diffTexCoords) +
490
        '], offset;');
491
      FP.Add('   TEX textureColor, temp, texture[1], 2D;');
492
    end
493
    else
494
      FP.Add('   TEX textureColor, fragment.texcoord[' + IntToStr(diffTexCoords)
495
        + '], texture[1], 2D;');
496
    FP.Add('   MUL diff, diff, textureColor;');
497
  end;
498

499
  if DoSpecular then
500
  begin
501
    case SpecularMode of
502
      smBlinn:
503
        begin
504
          FP.Add('   ADD eye, eye, light;');
505
          FP.Add('   DP3 temp, eye, eye;');
506
          FP.Add('   RSQ temp, temp.x;');
507
          FP.Add('   MUL eye, eye, temp.x;');
508
          FP.Add('   DP3_SAT spec, normal, eye;');
509
        end;
510
      smPhong:
511
        begin
512
          FP.Add('   DP3 reflect, normal, light;');
513
          FP.Add('   MUL reflect, reflect.x, normal;');
514
          FP.Add('   MUL reflect, 2.0, reflect;');
515
          FP.Add('   ADD reflect, reflect, -light;');
516
          FP.Add('   DP3_SAT spec, reflect, eye;');
517
        end;
518
    else
519
      Assert(False, 'Invalid specular mode!');
520
    end;
521

522
    FP.Add('   POW spec, spec.x, shininess.x;');
523
    FP.Add('   MUL spec, spec, materialSpecular;');
524
    FP.Add('   MUL spec, spec, lightSpecular;');
525
    if boSpecularTexture3 in BumpOptions then
526
    begin
527
      if DoParallaxOffset then
528
      begin
529
        FP.Add('   ADD temp, fragment.texcoord[' + IntToStr(specTexCoords) +
530
          '], offset;');
531
        FP.Add('   TEX textureColor, temp, texture[2], 2D;');
532
      end
533
      else
534
        FP.Add('   TEX textureColor, fragment.texcoord[' +
535
          IntToStr(specTexCoords) + '], texture[2], 2D;');
536
      FP.Add('   MUL spec, spec, textureColor;');
537
    end;
538
  end;
539

540
  // Output
541
  if DoSpecular then
542
    FP.Add('   ADD temp, diff, spec;')
543
  else
544
    FP.Add('   MOV temp, diff;');
545

546
  if boLightAttenuation in BumpOptions then
547
  begin
548
    FP.Add('   MUL atten.y, atten.x, atten.x;');
549
    FP.Add('   MAD atten.x, lightAtten.y, atten.x, lightAtten.x;');
550
    FP.Add('   MAD atten.x, lightAtten.z, atten.y, atten.x;');
551
    FP.Add('   RCP atten.x, atten.x;');
552
    FP.Add('   MUL temp, temp, atten.x;');
553
  end;
554

555
  FP.Add('   MOV_SAT result.color, temp;');
556
  FP.Add('   MOV result.color.w, 1.0;');
557

558
  FP.Add('END');
559

560
  FFragmentProgram.Assign(FP);
561
  Result := FP.Text;
562
  FP.Free;
563
end;
564

565
// DoLightPass
566
//
567

568
procedure TGLBumpShader.DoLightPass(var rci: TGLRenderContextInfo;
569
  lightID: Cardinal);
570
var
571
  dummyHandle, tempHandle: Integer;
572
  lightPos, lightAtten,
573
    materialDiffuse, lightDiffuse, lightSpecular: TVector;
574
begin
575
  FVertexProgramHandle.Enable;
576
  FVertexProgramHandle.Bind;
577

578
  // Set the light position to program.local[0]
579
  GL.GetLightfv(GL_LIGHT0 + FLightIDs[0], GL_POSITION, @lightPos.V[0]);
580
  GL.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 0, @lightPos.V[0]);
581

582
  // Set the light attenutation to program.local[1]
583
  lightAtten.V[0] := rci.GLStates.LightConstantAtten[FLightIDs[0]];
584
  lightAtten.V[1] := rci.GLStates.LightLinearAtten[FLightIDs[0]];
585
  lightAtten.V[2] := rci.GLStates.LightQuadraticAtten[FLightIDs[0]];
586
  GL.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 1, @lightAtten.V[0]);
587

588
  case FBumpMethod of
589
    bmDot3TexCombiner:
590
      begin
591
        rci.GLStates.ActiveTexture := 0;
592
        dummyHandle := rci.GLStates.TextureBinding[0, ttTexture2D];
593
        GL.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
594
        GL.TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
595
        GL.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE0_ARB);
596
        GL.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
597

598
        rci.GLStates.ActiveTexture := 1;
599
        rci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
600
        tempHandle := rci.GLStates.TextureBinding[1, ttTexture2D];
601
        if tempHandle = 0 then
602
          rci.GLStates.TextureBinding[1, ttTexture2D] := dummyHandle;
603
        lightDiffuse := rci.GLStates.LightDiffuse[FLightIDs[0]];
604
        GL.GetMaterialfv(GL_FRONT, GL_DIFFUSE, @materialDiffuse);
605
        lightDiffuse.V[0] := lightDiffuse.V[0] * materialDiffuse.V[0];
606
        lightDiffuse.V[1] := lightDiffuse.V[1] * materialDiffuse.V[1];
607
        lightDiffuse.V[2] := lightDiffuse.V[2] * materialDiffuse.V[2];
608
        lightDiffuse.V[3] := lightDiffuse.V[3] * materialDiffuse.V[3];
609
        GL.TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, @lightDiffuse);
610
        GL.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
611
        GL.TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
612
        GL.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
613
        GL.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_COLOR_ARB);
614

615
        with rci.GLStates do
616
        begin
617
          ActiveTexture := 2;
618
          ActiveTextureEnabled[ttTexture2D] := False;
619
          ActiveTexture := 0;
620
        end;
621
      end;
622

623
    bmBasicARBFP:
624
      begin
625
        FFragmentProgramHandle.Enable;
626
        FFragmentProgramHandle.Bind;
627
        lightDiffuse := rci.GLStates.LightDiffuse[FLightIDs[0]];
628
        lightSpecular := rci.GLStates.LightSpecular[FLightIDs[0]];
629
        lightAtten.V[0] := rci.GLStates.LightConstantAtten[FLightIDs[0]];
630

631
        GL.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 0,
632
          @lightDiffuse.V[0]);
633
        GL.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 1,
634
          @lightSpecular.V[0]);
635
        GL.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 2,
636
          @lightAtten.V[0]);
637
      end;
638

639
  else
640
    Assert(False, 'Invalid bump method!');
641
  end;
642
end;
643

644
// DoApply
645
//
646

647
procedure TGLBumpShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
648
var
649
  maxTextures, i: Integer;
650
  ambient, LMaterialAmbient: TColorVector;
651
  success: Boolean;
652
begin
653
  if (csDesigning in ComponentState) and not DesignTimeEnabled then
654
    exit;
655
  if not Enabled then
656
    exit;
657

658
  GL.GetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, @maxTextures);
659

660
  success := False;
661
  try
662
    if not GL.ARB_multitexture then
663
      raise Exception.Create('This shader requires GL_ARB_multitexture.');
664
    if (maxTextures < 3)
665
      and ((BumpMethod <> bmDot3TexCombiner) or (BumpSpace = bsTangentExternal)) then
666
      raise
667
        Exception.Create('The current shader settings require 3 or more texture units.');
668
    if (maxTextures < 4)
669
      and (BumpMethod <> bmDot3TexCombiner)
670
      and (boUseSecondaryTexCoords in BumpOptions)
671
      and (SpecularMode <> smOff) then
672
      raise
673
        Exception.Create('The current shader settings require 4 or more texture units.');
674

675
    if not Assigned(FVertexProgramHandle) then
676
    begin
677
      FVertexProgramHandle := TGLARBVertexProgramHandle.CreateAndAllocate;
678
      FVertexProgramHandle.LoadARBProgram(GenerateVertexProgram);
679
    end;
680

681
    if not Assigned(FFragmentProgramHandle) then
682
      if FBumpMethod = bmBasicARBFP then
683
      begin
684
        FFragmentProgramHandle := TGLARBFragmentProgramHandle.CreateAndAllocate;
685
        FFragmentProgramHandle.LoadARBProgram(GenerateFragmentProgram);
686
      end;
687

688
    success := True;
689

690
  finally
691
    if not success then
692
    begin
693
      Enabled := False;
694
      DesignTimeEnabled := False;
695
    end;
696
  end;
697

698
  FLightIDs.Clear;
699
  rci.GLStates.ActiveTexture := 0;
700
  if rci.GLStates.ActiveTextureEnabled[ttTexture2D] then
701
    for i := 0 to rci.GLStates.MaxLights - 1 do
702
    begin
703
      if rci.GLStates.LightEnabling[i] then
704
        FLightIDs.Add(i);
705
    end;
706
  FLightsEnabled := FLightIDs.Count;
707

708
  FAmbientPass := False;
709
  FDiffusePass := False;
710

711
  if FLightIDs.Count > 0 then
712
  begin
713

714
    rci.GLStates.DepthFunc := cfLEqual;
715
    rci.GLStates.Disable(stBlend);
716
    DoLightPass(rci, FLightIDs[0]);
717
    FLightIDs.Delete(0);
718

719
  end
720
  else
721
    with rci.GLStates do
722
    begin
723
      Disable(stLighting);
724
      ActiveTexture := 0;
725
      ActiveTextureEnabled[ttTexture2D] := False;
726
      ActiveTexture := 1;
727
      ActiveTextureEnabled[ttTexture2D] := False;
728
      ActiveTexture := 2;
729
      ActiveTextureEnabled[ttTexture2D] := False;
730
      ActiveTexture := 0;
731

732
      GL.GetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
733
      GL.GetMaterialfv(GL_FRONT, GL_AMBIENT, @LMaterialAmbient);
734
      ambient.V[0] := ambient.V[0] * LMaterialAmbient.V[0];
735
      ambient.V[1] := ambient.V[1] * LMaterialAmbient.V[1];
736
      ambient.V[2] := ambient.V[2] * LMaterialAmbient.V[2];
737
      GL.Color3fv(@ambient);
738

739
      FAmbientPass := True;
740

741
    end;
742
end;
743

744
// DoUnApply
745
//
746

747
function TGLBumpShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
748
var
749
  ambient, LMaterialAmbient: TVector;
750
begin
751
  Result := False;
752
  if (csDesigning in ComponentState) and not DesignTimeEnabled then
753
    exit;
754
  if not Enabled then
755
    exit;
756

757
  if FLightIDs.Count > 0 then
758
    with rci.GLStates do
759
    begin
760

761
      DepthFunc := cfLEqual;
762
      Enable(stBlend);
763
      SetBlendFunc(bfOne, bfOne);
764

765
      DoLightPass(rci, FLightIDs[0]);
766
      FLightIDs.Delete(0);
767
      Result := True;
768
      Exit;
769

770
    end
771
  else if not FDiffusePass and (FLightsEnabled <> 0)
772
    and (boDiffuseTexture2 in BumpOptions)
773
    and (BumpMethod = bmDot3TexCombiner) then
774
    with rci.GLStates do
775
    begin
776

777
      Enable(stBlend);
778
      SetBlendFunc(bfDstColor, bfZero);
779

780
      ActiveTexture := 0;
781
      ActiveTextureEnabled[ttTexture2D] := False;
782
      ActiveTexture := 1;
783
      ActiveTextureEnabled[ttTexture2D] := True;
784
      GL.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
785
      ActiveTexture := 2;
786
      ActiveTextureEnabled[ttTexture2D] := False;
787
      ActiveTexture := 0;
788

789
      FDiffusePass := True;
790
      Result := True;
791
      Exit;
792

793
    end
794
  else if not FAmbientPass then
795
    with rci.GLStates do
796
    begin
797

798
      FVertexProgramHandle.Disable;
799
      if BumpMethod = bmBasicARBFP then
800
        FFragmentProgramHandle.Disable;
801

802
      Disable(stLighting);
803
      ActiveTexture := 0;
804
      ActiveTextureEnabled[ttTexture2D] := False;
805
      ActiveTexture := 1;
806
      ActiveTextureEnabled[ttTexture2D] := False;
807
      ActiveTexture := 2;
808
      ActiveTextureEnabled[ttTexture2D] := False;
809
      ActiveTexture := 0;
810

811
      DepthFunc := cfLEqual;
812
      Enable(stBlend);
813
      SetBlendFunc(bfOne, bfOne);
814

815
      GL.GetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
816
      GL.GetMaterialfv(GL_FRONT, GL_AMBIENT, @LMaterialAmbient);
817
      ambient.V[0] := ambient.V[0] * LMaterialAmbient.V[0];
818
      ambient.V[1] := ambient.V[1] * LMaterialAmbient.V[1];
819
      ambient.V[2] := ambient.V[2] * LMaterialAmbient.V[2];
820
      GL.Color3fv(@ambient);
821

822
      FAmbientPass := True;
823
      Result := True;
824
      Exit;
825

826
    end;
827

828
  FVertexProgramHandle.Disable;
829
  if BumpMethod = bmBasicARBFP then
830
    FFragmentProgramHandle.Disable;
831
end;
832

833
// DeleteVertexPrograms
834
//
835

836
procedure TGLBumpShader.DeleteVertexPrograms;
837
begin
838
  FVertexProgramHandle.Free;
839
  FVertexProgramHandle := nil;
840
  FVertexProgram.Clear;
841
end;
842

843
// DeleteFragmentPrograms
844
//
845

846
procedure TGLBumpShader.DeleteFragmentPrograms;
847
begin
848
  FFragmentProgramHandle.Free;
849
  FFragmentProgramHandle := nil;
850
  FFragmentProgram.Clear;
851
end;
852

853
// SetBumpMethod
854
//
855

856
procedure TGLBumpShader.SetBumpMethod(const Value: TBumpMethod);
857
begin
858
  if Value <> FBumpMethod then
859
  begin
860
    FBumpMethod := Value;
861
    DeleteVertexPrograms;
862
    DeleteFragmentPrograms;
863
    NotifyChange(Self);
864
  end;
865
end;
866

867
// SetBumpSpace
868
//
869

870
procedure TGLBumpShader.SetBumpSpace(const Value: TBumpSpace);
871
begin
872
  if Value <> FBumpSpace then
873
  begin
874
    FBumpSpace := Value;
875
    DeleteVertexPrograms;
876
    DeleteFragmentPrograms;
877
    NotifyChange(Self);
878
  end;
879
end;
880

881
// SetBumpOptions
882
//
883

884
procedure TGLBumpShader.SetBumpOptions(const Value: TBumpOptions);
885
begin
886
  if Value <> FBumpOptions then
887
  begin
888
    FBumpOptions := Value;
889
    DeleteVertexPrograms;
890
    DeleteFragmentPrograms;
891
    NotifyChange(Self);
892
  end;
893
end;
894

895
// SetSpecularMode
896
//
897

898
procedure TGLBumpShader.SetSpecularMode(const Value: TSpecularMode);
899
begin
900
  if Value <> FSpecularMode then
901
  begin
902
    FSpecularMode := Value;
903
    DeleteVertexPrograms;
904
    DeleteFragmentPrograms;
905
    NotifyChange(Self);
906
  end;
907
end;
908

909
// SetDesignTimeEnabled
910
//
911

912
procedure TGLBumpShader.SetDesignTimeEnabled(const Value: Boolean);
913
begin
914
  if Value <> FDesignTimeEnabled then
915
  begin
916
    FDesignTimeEnabled := Value;
917
    NotifyChange(Self);
918
  end;
919
end;
920

921
// SetParallaxOffset
922
//
923

924
procedure TGLBumpShader.SetParallaxOffset(const Value: Single);
925
begin
926
  if Value <> FParallaxOffset then
927
  begin
928
    FParallaxOffset := Value;
929
    DeleteVertexPrograms;
930
    DeleteFragmentPrograms;
931
    NotifyChange(Self);
932
  end;
933
end;
934

935
end.
936

937

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.