2
0

GLSL.ShaderGlass.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. // This unit is part of the GLScene Engine, http://glscene.org
  2. //
  3. unit GLSL.ShaderGlass;
  4. (*
  5. Glass shader : Environment mapping with an
  6. equirectangular 2D texture and refraction mapping
  7. with a background texture blended together using the Fresnel terms
  8. *)
  9. interface
  10. {$I GLScene.inc}
  11. uses
  12. Winapi.OpenGL,
  13. Winapi.OpenGLext,
  14. System.Classes,
  15. GLScene,
  16. GLBaseClasses,
  17. GLState,
  18. OpenGLTokens,
  19. GLContext,
  20. GLRenderContextInfo,
  21. GLVectorGeometry,
  22. GLCoordinates,
  23. GLTextureFormat,
  24. GLColor,
  25. GLTexture,
  26. GLMaterial,
  27. GLPersistentClasses,
  28. GLGraphics,
  29. GLSL.Shader,
  30. GLS.ShaderCustom;
  31. (* Custom class for GLSLGlassShader.
  32. Glass shader : Environment mapping and refraction mapping using the fresnel terms *)
  33. type
  34. TGLCustomGLSLGlassShader = class(TGLCustomGLSLShader)
  35. private
  36. FDiffuseColor: TGLColor;
  37. FDepth: Single;
  38. FMix: Single;
  39. FAlpha: Single;
  40. FMaterialLibrary: TGLAbstractMaterialLibrary;
  41. FMainTexture: TGLTexture; // EnvMap
  42. FMainTexName: TGLLibMaterialName;
  43. FRefractionTexture: TGLTexture;
  44. FRefractionTexName: TGLLibMaterialName;
  45. FOwnerObject: TGLBaseSceneObject;
  46. FBlendSrc: TGLBlendFunction;
  47. FBlendDst: TGLBlendFunction;
  48. function GetMaterialLibrary: TGLAbstractMaterialLibrary;
  49. procedure SetMainTexTexture(const Value: TGLTexture);
  50. function GetMainTexName: TGLLibMaterialName;
  51. procedure SetMainTexName(const Value: TGLLibMaterialName);
  52. procedure SetRefractionTexTexture(const Value: TGLTexture);
  53. function GetRefractionTexName: TGLLibMaterialName;
  54. procedure SetRefractionTexName(const Value: TGLLibMaterialName);
  55. procedure SetDiffuseColor(AValue: TGLColor);
  56. protected
  57. procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
  58. function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
  59. procedure SetMaterialLibrary(const Value
  60. : TGLAbstractMaterialLibrary); virtual;
  61. procedure Notification(AComponent: TComponent;
  62. Operation: TOperation); override;
  63. public
  64. constructor Create(AOwner: TComponent); override;
  65. destructor Destroy; override;
  66. property DiffuseColor: TGLColor read FDiffuseColor Write SetDiffuseColor;
  67. property Depth: Single read FDepth write FDepth;
  68. property Mix: Single read FMix write FMix;
  69. property Alpha: Single read FAlpha write FAlpha;
  70. property MaterialLibrary: TGLAbstractMaterialLibrary read GetMaterialLibrary
  71. write SetMaterialLibrary;
  72. property MainTexture: TGLTexture read FMainTexture write SetMainTexTexture;
  73. property MainTextureName: TGLLibMaterialName read GetMainTexName
  74. write SetMainTexName;
  75. property RefractionTexture: TGLTexture read FRefractionTexture
  76. write SetRefractionTexTexture;
  77. property RefractionTextureName: TGLLibMaterialName read GetRefractionTexName
  78. write SetRefractionTexName;
  79. property OwnerObject: TGLBaseSceneObject read FOwnerObject
  80. write FOwnerObject;
  81. property BlendSrc: TGLBlendFunction read FBlendSrc write FBlendSrc
  82. default bfSrcAlpha;
  83. property BlendDst: TGLBlendFunction read FBlendDst write FBlendDst
  84. default bfDstAlpha;
  85. end;
  86. TGLSLGlassShader = class(TGLCustomGLSLGlassShader)
  87. published
  88. property DiffuseColor;
  89. property Depth;
  90. property Mix;
  91. property Alpha;
  92. property MaterialLibrary;
  93. property MainTexture;
  94. property MainTextureName;
  95. property RefractionTexture;
  96. property RefractionTextureName;
  97. property OwnerObject;
  98. property BlendSrc;
  99. property BlendDst;
  100. end;
  101. //===============================================
  102. implementation
  103. //===============================================
  104. const
  105. fBuffSize: Integer = 512;
  106. constructor TGLCustomGLSLGlassShader.Create(AOwner: TComponent);
  107. begin
  108. inherited;
  109. with VertexProgram.Code do
  110. begin
  111. clear;
  112. Add('varying vec3 Normal; ');
  113. Add('varying vec3 EyeDir; ');
  114. Add('varying vec4 EyePos; ');
  115. Add('varying float LightIntensity; ');
  116. Add('void main(void) ');
  117. Add('{ ');
  118. Add(' gl_Position = ftransform(); ');
  119. Add(' vec3 LightPos = gl_LightSource[0].position.xyz;');
  120. Add(' Normal = normalize(gl_NormalMatrix * gl_Normal); ');
  121. Add(' vec4 pos = gl_ModelViewMatrix * gl_Vertex; ');
  122. Add(' EyeDir = -pos.xyz; ');
  123. Add(' EyePos = gl_ModelViewProjectionMatrix * gl_Vertex; ');
  124. Add(' LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0); ');
  125. Add('} ');
  126. end;
  127. With FragmentProgram.Code do
  128. begin
  129. clear;
  130. Add('const vec3 Xunitvec = vec3 (1.0, 0.0, 0.0); ');
  131. Add('const vec3 Yunitvec = vec3 (0.0, 1.0, 0.0); ');
  132. Add('uniform vec4 BaseColor; ');
  133. Add('uniform float Depth; ');
  134. Add('uniform float MixRatio; ');
  135. Add('uniform float AlphaIntensity; ');
  136. // need to scale our framebuffer - it has a fixed width/height of 2048
  137. Add('uniform float FrameWidth; ');
  138. Add('uniform float FrameHeight; ');
  139. Add('uniform sampler2D EnvMap; ');
  140. Add('uniform sampler2D RefractionMap; ');
  141. Add('varying vec3 Normal; ');
  142. Add('varying vec3 EyeDir; ');
  143. Add('varying vec4 EyePos; ');
  144. Add('varying float LightIntensity; ');
  145. Add('void main (void) ');
  146. Add('{ ');
  147. // Compute reflection vector
  148. Add(' vec3 reflectDir = reflect(EyeDir, Normal); ');
  149. // Compute altitude and azimuth angles
  150. Add(' vec2 index; ');
  151. Add(' index.y = dot(normalize(reflectDir), Yunitvec); ');
  152. Add(' reflectDir.y = 0.0; ');
  153. Add(' index.x = dot(normalize(reflectDir), Xunitvec) * 0.5; ');
  154. // Translate index values into proper range
  155. Add(' if (reflectDir.z >= 0.0) ');
  156. Add(' index = (index + 1.0) * 0.5; ');
  157. Add(' else ');
  158. Add(' { ');
  159. Add(' index.t = (index.t + 1.0) * 0.5; ');
  160. Add(' index.s = (-index.s) * 0.5 + 1.0; ');
  161. Add(' } ');
  162. // if reflectDir.z >= 0.0, s will go from 0.25 to 0.75
  163. // if reflectDir.z < 0.0, s will go from 0.75 to 1.25, and
  164. // that's OK, because we've set the texture to wrap.
  165. // Do a lookup into the environment map.
  166. Add(' vec4 envColor = texture2D(EnvMap, index); ');
  167. // calc fresnels term. This allows a view dependant blend of reflection/refraction
  168. Add(' float fresnel = abs(dot(normalize(EyeDir), Normal)); ');
  169. Add(' fresnel *= MixRatio; ');
  170. Add(' fresnel = clamp(fresnel, 0.1, 0.9); ');
  171. // calc refraction
  172. Add(' vec3 refractionDir = normalize(EyeDir) - normalize(Normal); ');
  173. // Scale the refraction so the z element is equal to depth
  174. Add(' float depthVal = Depth / -refractionDir.z; ');
  175. // perform the div by w
  176. Add(' float recipW = 1.0 / EyePos.w; ');
  177. Add(' vec2 eye = EyePos.xy * vec2(recipW); ');
  178. // calc the refraction lookup
  179. Add(' index.s = (eye.x + refractionDir.x * depthVal); ');
  180. Add(' index.t = (eye.y + refractionDir.y * depthVal); ');
  181. // scale and shift so we're in the range 0-1
  182. Add(' index.s = index.s / 2.0 + 0.5; ');
  183. Add(' index.t = index.t / 2.0 + 0.5; ');
  184. // as we're looking at the framebuffer, we want it clamping at the edge of the rendered scene, not the edge of the texture,
  185. // so we clamp before scaling to fit
  186. Add(' float recip1k = 1.0 / 2048.0; ');
  187. Add(' index.s = clamp(index.s, 0.0, 1.0 - recip1k); ');
  188. Add(' index.t = clamp(index.t, 0.0, 1.0 - recip1k); ');
  189. // scale the texture so we just see the rendered framebuffer
  190. Add(' index.s = index.s * FrameWidth * recip1k; ');
  191. Add(' index.t = index.t * FrameHeight * recip1k; ');
  192. Add(' vec4 RefractionColor = texture2D(RefractionMap, index.st); ');
  193. //Add(' RefractionColor.a = 0.9; ');
  194. // Add(' RefractionColor = RefractionColor+vec3(0.75,0.75,0.75); ');//
  195. // Add lighting to base color and mix
  196. // Add(' vec4 base = LightIntensity * BaseColor; ');
  197. Add(' envColor = mix(envColor, BaseColor,LightIntensity); ');
  198. Add(' envColor = mix(envColor, RefractionColor, fresnel); ');
  199. Add(' envColor.a = AlphaIntensity; ');
  200. Add(' gl_FragColor = envColor; //vec4 (envColor.rgb, 0.3); ');
  201. Add('} ');
  202. end;
  203. // FMainTexture := TGLTexture.Create(nil);
  204. // FMainTexture.Disabled := False;
  205. // FMainTexture.Enabled := True;
  206. //setup initial parameters
  207. FDiffuseColor := TGLColor.Create(Self);
  208. FDepth := 0.1;
  209. FMix:=1.0;
  210. FAlpha:=1.0;
  211. FDiffuseColor.SetColor(0.15, 0.15, 0.15, 1.0);
  212. FBlendSrc := bfSrcAlpha;
  213. FBlendDst := bfDstAlpha;
  214. end;
  215. destructor TGLCustomGLSLGlassShader.Destroy;
  216. begin
  217. FDiffuseColor.Destroy;
  218. inherited;
  219. end;
  220. procedure TGLCustomGLSLGlassShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
  221. begin
  222. // Auto Render EnvMap
  223. // capture and create material from framebuffer
  224. // I don't say why but We need to reset and reaffect our texture otherwise one of the texture is broken
  225. with FMainTexture do
  226. begin
  227. PrepareBuildList;
  228. gl.ActiveTexture(GL_TEXTURE0_ARB);
  229. gl.BindTexture(GL_TEXTURE_2D, Handle);
  230. gl.ActiveTexture(GL_TEXTURE0_ARB);
  231. end;
  232. with FRefractionTexture do
  233. begin
  234. PrepareBuildList;
  235. gl.ActiveTexture(GL_TEXTURE1_ARB);
  236. gl.BindTexture(GL_TEXTURE_2D, Handle);
  237. gl.ActiveTexture(GL_TEXTURE0_ARB);
  238. end;
  239. FOwnerObject.Visible := False;
  240. TGLSceneBuffer(rci.buffer).CopyToTexture(FMainTexture);
  241. FOwnerObject.Visible := True;
  242. GetGLSLProg.UseProgramObject;
  243. // GetGLSLProg.Uniform4f['BaseColor'] := FDiffuseColor.Color;
  244. // GetGLSLProg.Uniform1f['Depth'] := FDepth;
  245. // GetGLSLProg.Uniform1f['MixRatio'] := FMix; // 0 - 2
  246. // GetGLSLProg.Uniform1f['FrameWidth'] := fBuffSize * 3.125;
  247. // GetGLSLProg.Uniform1f['FrameHeight'] := fBuffSize * 3.125;
  248. // SetTex('EnvMap',FMainTexture); --> BUG
  249. // SetTex('RefractionMap',FRefractionTexture);
  250. param['BaseColor'].AsVector4f := FDiffuseColor.Color;
  251. param['Depth'].AsVector1f := FDepth; // 0 - 0.3
  252. param['MixRatio'].AsVector1f := FMix; // 0 - 2
  253. param['AlphaIntensity'].AsVector1f := FAlpha; // 0 - 2
  254. param['FrameWidth'].AsVector1f := fBuffSize * 3.75;
  255. param['FrameHeight'].AsVector1f := fBuffSize * 3.75;
  256. Param['EnvMap'].AsTexture2D[0] := FMainTexture;
  257. Param['RefractionMap'].AsTexture2D[1] :=FRefractionTexture ;
  258. gl.Enable(GL_BLEND);
  259. gl.BlendFunc(cGLBlendFunctionToGLEnum[FBlendSrc],cGLBlendFunctionToGLEnum[FBlendDst]);
  260. end;
  261. function TGLCustomGLSLGlassShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
  262. begin
  263. gl.Disable(GL_BLEND);
  264. GetGLSLProg.EndUseProgramObject;
  265. Result := False;
  266. end;
  267. function TGLCustomGLSLGlassShader.GetMaterialLibrary: TGLAbstractMaterialLibrary;
  268. begin
  269. Result := FMaterialLibrary;
  270. end;
  271. procedure TGLCustomGLSLGlassShader.SetMaterialLibrary(const Value: TGLAbstractMaterialLibrary);
  272. begin
  273. if FMaterialLibrary <> nil then FMaterialLibrary.RemoveFreeNotification(Self);
  274. FMaterialLibrary := Value;
  275. if (FMaterialLibrary <> nil)
  276. and (FMaterialLibrary is TGLAbstractMaterialLibrary) then
  277. FMaterialLibrary.FreeNotification(Self);
  278. end;
  279. procedure TGLCustomGLSLGlassShader.SetMainTexTexture(const Value: TGLTexture);
  280. begin
  281. if FMainTexture = Value then Exit;
  282. FMainTexture := Value;
  283. NotifyChange(Self)
  284. end;
  285. function TGLCustomGLSLGlassShader.GetMainTexName: TGLLibMaterialName;
  286. begin
  287. Result := TGLMaterialLibrary(FMaterialLibrary).GetNameOfTexture(FMainTexture);
  288. if Result = '' then Result := FMainTexName;
  289. end;
  290. procedure TGLCustomGLSLGlassShader.SetMainTexName(const Value: TGLLibMaterialName);
  291. begin
  292. // Assert(not(assigned(FMaterialLibrary)),'You must set Material Library Before');
  293. if FMainTexName = Value then Exit;
  294. FMainTexName := Value;
  295. FMainTexture := TGLMaterialLibrary(FMaterialLibrary).TextureByName(FMainTexName);
  296. NotifyChange(Self);
  297. end;
  298. procedure TGLCustomGLSLGlassShader.SetRefractionTexTexture(const Value: TGLTexture);
  299. begin
  300. if FRefractionTexture = Value then Exit;
  301. FRefractionTexture := Value;
  302. NotifyChange(Self)
  303. end;
  304. function TGLCustomGLSLGlassShader.GetRefractionTexName: TGLLibMaterialName;
  305. begin
  306. Result := TGLMaterialLibrary(FMaterialLibrary).GetNameOfTexture(FRefractionTexture);
  307. if Result = '' then Result := FRefractionTexName;
  308. end;
  309. procedure TGLCustomGLSLGlassShader.SetRefractionTexName(const Value: TGLLibMaterialName);
  310. begin
  311. // Assert(not(assigned(FMaterialLibrary)),'You must set Material Library Before');
  312. if FRefractionTexName = Value then Exit;
  313. FRefractionTexName := Value;
  314. FRefractionTexture := TGLMaterialLibrary(FMaterialLibrary).TextureByName(FRefractionTexName);
  315. NotifyChange(Self);
  316. end;
  317. procedure TGLCustomGLSLGlassShader.SetDiffuseColor(AValue: TGLColor);
  318. begin
  319. FDiffuseColor.DirectColor := AValue.Color;
  320. end;
  321. procedure TGLCustomGLSLGlassShader.Notification(AComponent: TComponent; Operation: TOperation);
  322. var
  323. Index: Integer;
  324. begin
  325. inherited;
  326. if Operation = opRemove then
  327. if AComponent = FMaterialLibrary then
  328. if FMaterialLibrary <> nil then
  329. begin
  330. if FMainTexture <> nil then
  331. begin
  332. Index := TGLMaterialLibrary(FMaterialLibrary).Materials.GetTextureIndex(FMainTexture);
  333. if Index <> -1 then
  334. SetMainTexTexture(nil);
  335. end;
  336. if FRefractionTexture <> nil then
  337. begin
  338. Index := TGLMaterialLibrary(FMaterialLibrary).Materials.GetTextureIndex(FRefractionTexture);
  339. if Index <> -1 then
  340. SetRefractionTexTexture(nil);
  341. end;
  342. FMaterialLibrary := nil;
  343. end;
  344. end;
  345. end.