GXSL.PhongShader.pas 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXSL.PhongShader;
  5. (* An ARBvp1.0 + ARBfp1.0 shader that implements phong shading *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Winapi.OpenGLext,
  11. System.Classes,
  12. System.SysUtils,
  13. Stage.VectorTypes,
  14. GXS.Texture,
  15. Stage.VectorGeometry,
  16. GXS.VectorLists,
  17. GXS.Context,
  18. GXS.RenderContextInfo,
  19. GXSL.AsmShader,
  20. GXSL.CustomShader,
  21. GXS.State;
  22. type
  23. TgxPhongShader = class(TgxCustomAsmShader)
  24. private
  25. FLightIDs: TgxIntegerList;
  26. FDesignTimeEnabled: Boolean;
  27. FAmbientPass: Boolean;
  28. procedure SetDesignTimeEnabled(const Value: Boolean);
  29. protected
  30. procedure DoLightPass(lightID: Cardinal); virtual;
  31. procedure DoAmbientPass(var rci: TgxRenderContextInfo); virtual;
  32. procedure UnApplyLights(var rci: TgxRenderContextInfo); virtual;
  33. procedure DoApply(var rci: TgxRenderContextInfo; Sender: TObject); override;
  34. function DoUnApply(var rci: TgxRenderContextInfo): Boolean; override;
  35. procedure DoInitialize(var rci : TgxRenderContextInfo; Sender : TObject); override;
  36. public
  37. constructor Create(AOwner: TComponent); override;
  38. destructor Destroy; override;
  39. function ShaderSupported: Boolean; override;
  40. published
  41. property DesignTimeEnabled: Boolean read FDesignTimeEnabled write SetDesignTimeEnabled default False;
  42. end;
  43. //------------------------------------------------------------------------
  44. implementation
  45. //------------------------------------------------------------------------
  46. procedure TgxPhongShader.DoApply(var rci: TgxRenderContextInfo; Sender: TObject);
  47. begin
  48. if (csDesigning in ComponentState) and not DesignTimeEnabled then Exit;
  49. GetActiveLightsList(FLightIDs);
  50. FAmbientPass := False;
  51. if FLightIDs.Count > 0 then
  52. begin
  53. rci.gxStates.DepthFunc := cfLEqual;
  54. rci.gxStates.Disable(stBlend);
  55. DoLightPass(FLightIDs[0]);
  56. FLightIDs.Delete(0);
  57. end
  58. else
  59. begin
  60. DoAmbientPass(rci);
  61. FAmbientPass := True;
  62. end;
  63. end;
  64. function TgxPhongShader.DoUnApply(var rci: TgxRenderContextInfo): Boolean;
  65. begin
  66. Result := False;
  67. if (csDesigning in ComponentState) and not DesignTimeEnabled then Exit;
  68. if FLightIDs.Count > 0 then
  69. begin
  70. UnApplyLights(rci);
  71. Result := True;
  72. Exit;
  73. end
  74. else
  75. if not FAmbientPass then
  76. begin
  77. Self.UnApplyShaderPrograms();
  78. rci.gxStates.Enable(stBlend);
  79. rci.gxStates.SetBlendFunc(bfOne, bfOne);
  80. DoAmbientPass(rci);
  81. FAmbientPass := True;
  82. Result := True;
  83. Exit;
  84. end;
  85. rci.gxStates.DepthFunc := cfLEqual;
  86. end;
  87. procedure TgxPhongShader.DoInitialize(var rci : TgxRenderContextInfo; Sender : TObject);
  88. begin
  89. if (csDesigning in ComponentState) and not DesignTimeEnabled then Exit;
  90. inherited;
  91. end;
  92. procedure TgxPhongShader.SetDesignTimeEnabled(const Value: Boolean);
  93. begin
  94. if Value <> FDesignTimeEnabled then
  95. begin
  96. FDesignTimeEnabled := Value;
  97. NotifyChange(Self);
  98. end;
  99. end;
  100. constructor TgxPhongShader.Create(AOwner: TComponent);
  101. begin
  102. inherited;
  103. with VertexProgram.Code do
  104. begin
  105. Add('!!ARBvp1.0');
  106. Add('OPTION ARB_position_invariant;');
  107. Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
  108. Add('PARAM mvit[4] = { state.matrix.modelview.invtrans };');
  109. Add('PARAM lightPos = program.local[0];');
  110. Add('TEMP light, normal, eye;');
  111. Add(' ADD eye, mvit[3], -vertex.position;');
  112. Add(' MOV eye.w, 0.0;');
  113. Add(' DP4 light.x, mvinv[0], lightPos;');
  114. Add(' DP4 light.y, mvinv[1], lightPos;');
  115. Add(' DP4 light.z, mvinv[2], lightPos;');
  116. Add(' ADD light, light, -vertex.position;');
  117. Add(' MOV light.w, 0.0;');
  118. Add(' MOV result.texcoord[0], vertex.normal;');
  119. Add(' MOV result.texcoord[1], light;');
  120. Add(' MOV result.texcoord[2], eye;');
  121. Add('END');
  122. end;
  123. with FragmentProgram.Code do
  124. begin
  125. Add('!!ARBfp1.0');
  126. Add('PARAM lightDiff = program.local[0];');
  127. Add('PARAM lightSpec = program.local[1];');
  128. Add('PARAM materialDiff = state.material.diffuse;');
  129. Add('PARAM materialSpec = state.material.specular;');
  130. Add('PARAM shininess = state.material.shininess;');
  131. Add('TEMP temp, light, normal, eye, R, diff, spec;');
  132. Add(' DP3 temp, fragment.texcoord[0], fragment.texcoord[0];');
  133. Add(' RSQ temp, temp.x;');
  134. Add(' MUL normal, temp.x, fragment.texcoord[0];');
  135. Add(' DP3 temp, fragment.texcoord[1], fragment.texcoord[1];');
  136. Add(' RSQ temp, temp.x;');
  137. Add(' MUL light, temp.x, fragment.texcoord[1];');
  138. Add(' DP3 temp, fragment.texcoord[2], fragment.texcoord[2];');
  139. Add(' RSQ temp, temp.x;');
  140. Add(' MUL eye, temp.x, fragment.texcoord[2];');
  141. Add(' DP3_SAT diff, normal, light;');
  142. Add(' MUL diff, diff, lightDiff;');
  143. Add(' MUL diff, diff, materialDiff;');
  144. Add(' DP3 R, normal, light;');
  145. Add(' MUL R, R.x, normal;');
  146. Add(' MUL R, 2.0, R;');
  147. Add(' ADD R, R, -light;');
  148. Add(' DP3_SAT spec, R, eye;');
  149. Add(' POW spec, spec.x, shininess.x;');
  150. Add(' MUL spec, spec, lightDiff;');
  151. Add(' MUL spec, spec, materialDiff;');
  152. Add(' ADD_SAT result.color, diff, spec;');
  153. Add(' MOV result.color.w, 1.0;');
  154. Add('END');
  155. end;
  156. FLightIDs := TgxIntegerList.Create;
  157. end;
  158. function TgxPhongShader.ShaderSupported: Boolean;
  159. var
  160. MaxTextures: Integer;
  161. begin
  162. Result := inherited ShaderSupported;
  163. glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, @MaxTextures);
  164. Result := Result and (maxTextures > 2);
  165. end;
  166. procedure TgxPhongShader.UnApplyLights(var rci: TgxRenderContextInfo);
  167. begin
  168. rci.gxStates.DepthFunc := cfLEqual;
  169. rci.gxStates.Enable(stBlend);
  170. rci.gxStates.SetBlendFunc(bfOne, bfOne);
  171. DoLightPass(FLightIDs[0]);
  172. FLightIDs.Delete(0);
  173. end;
  174. destructor TgxPhongShader.Destroy;
  175. begin
  176. FLightIDs.Free;
  177. inherited;
  178. end;
  179. procedure TgxPhongShader.DoAmbientPass(var rci: TgxRenderContextInfo);
  180. var
  181. ambient, materialAmbient: TVector4f;
  182. begin
  183. rci.gxStates.Disable(stLighting);
  184. glGetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
  185. glGetMaterialfv(GL_FRONT, GL_AMBIENT, @materialAmbient);
  186. ScaleVector(ambient, materialAmbient);
  187. glColor3fv(@ambient);
  188. end;
  189. procedure TgxPhongShader.DoLightPass(lightID: Cardinal);
  190. var
  191. LightParam: TVector4f;
  192. begin
  193. Self.ApplyShaderPrograms();
  194. with CurrentContext.gxStates do
  195. begin
  196. glGetLightfv(GL_LIGHT0+lightID, GL_POSITION, @LightParam);
  197. LightParam := LightParam;
  198. glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, 0, @LightParam);
  199. LightParam := LightDiffuse[lightID];
  200. glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, @LightParam);
  201. LightParam := LightSpecular[lightID];
  202. glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, @LightParam);
  203. end;
  204. end;
  205. initialization
  206. RegisterClasses([TgxPhongShader]);
  207. end.