GLSL.ShaderFur.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLSL.ShaderFur;
  5. (*
  6. Fur shader that simulate Fur / Hair / Grass.
  7. At this time only one light source is supported
  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. GLCoordinates,
  22. GLVectorGeometry,
  23. GLVectorTypes,
  24. GLTextureFormat,
  25. GLColor,
  26. GLTexture,
  27. GLMaterial,
  28. GLSL.Shader,
  29. GLS.ShaderCustom;
  30. type
  31. TGLCustomGLSLFurShader = class(TGLCustomGLSLShader)
  32. private
  33. FMaterialLibrary: TGLAbstractMaterialLibrary;
  34. FCurrentPass: Integer;
  35. FPassCount: Single;
  36. FFurLength: Single;
  37. FMaxFurLength: Single;
  38. FFurScale: Single;
  39. FRandomFurLength : Boolean;
  40. FColorScale: TGLColor;
  41. FAmbient: TGLColor;
  42. FGravity : TGLCoordinates;
  43. FLightIntensity : Single;
  44. FMainTex : TGLTexture;
  45. FNoiseTex : TGLTexture;
  46. FNoiseTexName : TGLLibMaterialName;
  47. FMainTexName : TGLLibMaterialName;
  48. FBlendSrc : TGLBlendFunction;
  49. FBlendDst : TGLBlendFunction;
  50. // FBlendEquation : TGLBlendEquation;
  51. function GetMaterialLibrary: TGLAbstractMaterialLibrary;
  52. procedure SetMainTexTexture(const Value: TGLTexture);
  53. procedure SetNoiseTexTexture(const Value: TGLTexture);
  54. function GetNoiseTexName: TGLLibMaterialName;
  55. procedure SetNoiseTexName(const Value: TGLLibMaterialName);
  56. function GetMainTexName: TGLLibMaterialName;
  57. procedure SetMainTexName(const Value: TGLLibMaterialName);
  58. procedure SetGravity(APosition:TGLCoordinates);
  59. procedure SetAmbient(AValue: TGLColor);
  60. procedure SetColorScale(AValue: TGLColor);
  61. protected
  62. procedure DoApply(var rci : TGLRenderContextInfo; Sender : TObject); override;
  63. function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
  64. procedure SetMaterialLibrary(const Value: TGLAbstractMaterialLibrary); virtual;
  65. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  66. public
  67. //Common stuff
  68. constructor Create(AOwner : TComponent); override;
  69. destructor Destroy; override;
  70. property PassCount: Single read FPassCount write FPassCount;
  71. property FurLength: Single read FFurLength write FFurLength;
  72. property MaxFurLength: Single read FMaxFurLength write FMaxFurLength;
  73. property FurDensity: Single read FFurScale write FFurScale;
  74. property RandomFurLength : Boolean read FRandomFurLength Write FRandomFurLength;
  75. property ColorScale: TGLColor read FColorScale Write setColorScale;
  76. property Ambient: TGLColor read FAmbient write setAmbient;
  77. property MaterialLibrary: TGLAbstractMaterialLibrary read getMaterialLibrary write SetMaterialLibrary;
  78. property MainTexture: TGLTexture read FMainTex write SetMainTexTexture;
  79. property MainTextureName: TGLLibMaterialName read GetMainTexName write SetMainTexName;
  80. property NoiseTexture: TGLTexture read FNoiseTex write SetNoiseTexTexture;
  81. property NoiseTextureName: TGLLibMaterialName read GetNoiseTexName write SetNoiseTexName;
  82. //property BlendEquation : TBlendEquation read FBlendEquation write FBlendEquation default beMin;
  83. property BlendSrc : TGLBlendFunction read FBlendSrc write FBlendSrc default bfSrcColor;
  84. property BlendDst : TGLBlendFunction read FBlendDst write FBlendDst default bfOneMinusDstColor;
  85. property Gravity : TGLCoordinates Read FGravity write setGravity;
  86. property LightIntensity : Single read FLightIntensity Write FLightIntensity;
  87. end;
  88. TGLSLFurShader = class(TGLCustomGLSLFurShader)
  89. published
  90. property PassCount;
  91. property FurLength;
  92. property MaxFurLength;
  93. property FurDensity;
  94. property RandomFurLength;
  95. property ColorScale;
  96. property Ambient;
  97. property LightIntensity;
  98. property Gravity;
  99. property BlendSrc;
  100. property BlendDst;
  101. property MainTexture;
  102. property MainTextureName;
  103. property NoiseTexture;
  104. property NoiseTextureName;
  105. end;
  106. //------------------------------------------
  107. implementation
  108. //------------------------------------------
  109. //------------------------------------------
  110. // TGLCustomGLSLFurShader
  111. //------------------------------------------
  112. constructor TGLCustomGLSLFurShader.Create(AOwner: TComponent);
  113. begin
  114. inherited;
  115. with VertexProgram.Code do
  116. begin
  117. clear;
  118. Add('uniform float fFurLength; ');
  119. Add('uniform float fFurMaxLength; ');
  120. Add('uniform float pass_index; ');
  121. Add('uniform int UseRandomLength; ');
  122. Add('uniform float fLayer; // 0 to 1 for the level ');
  123. Add('uniform vec3 vGravity; ');
  124. Add('varying vec3 normal; ');
  125. Add('varying vec2 vTexCoord; ');
  126. Add('varying vec3 lightVec; ');
  127. // Add('varying vec3 viewVec; ');
  128. Add('float rand(vec2 co){ ');
  129. Add(' return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); ');
  130. Add('} ');
  131. Add('void main() ');
  132. Add('{ ');
  133. Add(' mat4 mWorld = gl_ModelViewMatrix; ');
  134. Add(' vec3 Normal = gl_Normal; ');
  135. Add(' vec4 Position = gl_Vertex; ');
  136. Add(' vec4 lightPos = gl_LightSource[0].position;');
  137. Add(' vec4 vert = gl_ModelViewMatrix * gl_Vertex; ');
  138. Add(' normal = gl_NormalMatrix * gl_Normal; ');
  139. // Additional Gravit/Force Code
  140. Add(' vec3 vGravity2 = vGravity *mat3(mWorld ); ');
  141. // We use the pow function, so that only the tips of the hairs bend
  142. Add(' float k = pow(fLayer, 3.0); ');
  143. // Random the Hair length perhaps will can use a texture map for controling.
  144. Add(' vec3 vNormal = normalize( Normal * mat3(mWorld )); ');
  145. Add(' float RandomFurLength; ');
  146. Add(' if (UseRandomLength == 1) { RandomFurLength = fFurLength+fFurLength*rand(vNormal.xy); } ');
  147. Add(' else { RandomFurLength = fFurLength ; } ');
  148. Add(' RandomFurLength = pass_index*(RandomFurLength * vNormal); ');
  149. Add(' if (RandomFurLength > fFurMaxLength ) { RandomFurLength = fFurMaxLength; } ');
  150. Add(' Position.xyz += RandomFurLength +(vGravity2 * k); ');
  151. Add(' Position.xyz += pass_index*(fFurLength * Normal)+(vGravity2 * k); ');
  152. Add(' vTexCoord = gl_MultiTexCoord0; ');
  153. Add(' ');
  154. Add(' gl_Position = gl_ModelViewProjectionMatrix * Position; ');
  155. Add(' lightVec = vec3(lightPos - vert); ');
  156. // Add(' viewVec = -vec3(vert); ');
  157. Add('normal = vNormal; ');
  158. Add('} ');
  159. end;
  160. with FragmentProgram.Code do
  161. begin
  162. clear;
  163. Add('uniform vec4 fcolorScale; ');
  164. Add('uniform float pass_index; ');
  165. Add('uniform float fFurScale; ');
  166. Add('uniform vec4 vAmbient; ');
  167. Add('uniform float fLayer; // 0 to 1 for the level ');
  168. Add('uniform float vLightIntensity; ');
  169. Add('uniform sampler2D FurTexture; ');
  170. Add('uniform sampler2D ColourTexture; ');
  171. //textures
  172. Add('varying vec2 vTexCoord; ');
  173. Add('varying vec3 normal; ');
  174. Add('varying vec3 lightVec; ');
  175. // Add('varying vec3 viewVec; ');
  176. Add('void main() ');
  177. Add('{ ');
  178. // A Faking shadow
  179. Add(' vec4 fAlpha = texture2D( FurTexture, vTexCoord*fFurScale ); ');
  180. Add(' float fakeShadow = mix(0.3, 1.0, fAlpha.a-fLayer); ');
  181. Add(' ');
  182. Add(' vec4 FinalColour = vec4(0.0,0.0,0.0,1.0); ');
  183. Add('FinalColour = (fcolorScale*texture2D( ColourTexture, vTexCoord))*fakeShadow; ');
  184. // This comment part it's for controling if we must draw the hair according the red channel and the alpha in NoiseMap
  185. // Don' t work well a this time the NoiseMap must be perfect
  186. // Add('float visibility = 0.0; ');
  187. // Add('if (pass_index == 1.0) ');
  188. // Add('{ ');
  189. // Add(' visibility = 1.0; ');
  190. // Add('} ');
  191. // Add('else ');
  192. // Add('{ ');
  193. // Add(' if (fAlpha.a<fAlpha.r) { visibility = 0.0; } ');
  194. // Add(' else { visibility =mix(0.1,1.0,(1.02-fLayer)); } //-1.0; ');
  195. // Add('} ');
  196. Add('float visibility =mix(0.1,1.0,(1.02-fLayer)); '); // The Last past must be transparent
  197. // Simply Lighting - For this time only ONE light source is supported
  198. Add('vec4 ambient = vAmbient*FinalColour; ');
  199. Add('vec4 diffuse = FinalColour; ');
  200. Add('vec3 L = normalize(lightVec); ');
  201. Add('float NdotL = dot(L, normal); ');
  202. Add('// "Half-Lambert" technique for more pleasing diffuse term ');
  203. Add('diffuse = diffuse*(0.5*NdotL+0.5); ');
  204. Add('FinalColour = vLightIntensity*(ambient+ diffuse); // + no specular; ');
  205. Add('FinalColour.a = visibility ; ');
  206. Add(' // Return the calculated color ');
  207. Add(' gl_FragColor= FinalColour; ');
  208. Add('} ');
  209. end;
  210. //Fur stuff
  211. FPassCount := 16; // More is greater more the fur is dense
  212. FFurLength := 0.3000; // The minimal Hair length
  213. FMaxFurLength := 3.0;
  214. FRandomFurLength := false;
  215. FFurScale:=1.0;
  216. FColorScale := TGLColor.Create(Self);
  217. FColorScale.SetColor(0.2196,0.2201,0.2201,1.0);
  218. FAmbient := TGLColor.Create(Self);
  219. FAmbient.SetColor(1.0,1.0,1.0,1.0);
  220. // The Blend Funcs are very important for realistic fur rendering it can vary follow your textures
  221. FBlendSrc := bfOneMinusSrcColor;
  222. FBlendDst := bfOneMinusSrcAlpha;
  223. FGravity := TGLCoordinates.Create(self);
  224. FGravity.AsAffineVector := AffinevectorMake(0.0,0.0,0.0);
  225. FLightIntensity := 2.5;
  226. end;
  227. destructor TGLCustomGLSLFurShader.Destroy;
  228. begin
  229. Enabled:=false;
  230. FGravity.Free;
  231. FColorScale.Destroy;
  232. FAmbient.Destroy;
  233. inherited;
  234. end;
  235. procedure TGLCustomGLSLFurShader.DoApply(var rci: TGLRenderContextInfo;Sender: TObject);
  236. begin
  237. GetGLSLProg.UseProgramObject;
  238. //Fur stuff
  239. FCurrentPass := 1;
  240. param['pass_index'].AsVector1f := 1.0;
  241. param['fFurLength'].AsVector1f := FFurLength;
  242. param['fFurMaxLength'].AsVector1f := FMaxFurLength;
  243. param['fFurScale'].AsVector1f := FFurScale;
  244. if FRandomFurLength then param['UseRandomLength'].AsVector1i := 1
  245. else param['UseRandomLength'].AsVector1i := 0;
  246. param['fcolorScale'].AsVector4f := FColorScale.Color;
  247. param['FurTexture'].AsTexture2D[0] := FNoiseTex;
  248. param['ColourTexture'].AsTexture2D[1] := FMainTex;
  249. param['vGravity'].AsVector3f := FGravity.AsAffineVector;
  250. param['vAmbient'].AsVector4f := FAmbient.Color; //vectorMake(0.5,0.5,0.5,1.0);
  251. param['fLayer'].AsVector1f := 1/PassCount;
  252. param['vLightIntensity'].AsVector1f := FLightIntensity;
  253. gl.PushAttrib(GL_COLOR_BUFFER_BIT);
  254. gl.Enable(GL_BLEND);
  255. gl.BlendFunc(cGLBlendFunctionToGLEnum[FBlendSrc],cGLBlendFunctionToGLEnum[FBlendDst]);
  256. // gl.BlendFunc(GL_SRC_ALPHA, cGLBlendFunctionToGLEnum[FBlendSrc]);
  257. //gl.BlendFunc(GL_DST_ALPHA,cGLBlendFunctionToGLEnum[FBlendDst]);
  258. // gl.BlendEquation(cGLBlendEquationToGLEnum[BlendEquation]);
  259. end;
  260. function TGLCustomGLSLFurShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
  261. begin
  262. if FCurrentPass < PassCount then
  263. begin
  264. Inc(FCurrentPass);
  265. //GetGLSLProg.Uniform1f['pass_index'] := FCurrentPass;
  266. param['pass_index'].AsVector1f := FCurrentPass;
  267. param['fLayer'].AsVector1f := FCurrentPass/PassCount;
  268. Result := True;
  269. end
  270. else
  271. begin
  272. // glActiveTextureARB(GL_TEXTURE0_ARB);
  273. gl.ActiveTexture(GL_TEXTURE0_ARB);
  274. GetGLSLProg.EndUseProgramObject;
  275. gl.PopAttrib;
  276. Result := False;
  277. end;
  278. end;
  279. function TGLCustomGLSLFurShader.GetMaterialLibrary: TGLAbstractMaterialLibrary;
  280. begin
  281. Result := FMaterialLibrary;
  282. end;
  283. procedure TGLCustomGLSLFurShader.SetMaterialLibrary(const Value: TGLAbstractMaterialLibrary);
  284. begin
  285. if FMaterialLibrary <> nil then FMaterialLibrary.RemoveFreeNotification(Self);
  286. FMaterialLibrary := Value;
  287. if (FMaterialLibrary <> nil)
  288. and (FMaterialLibrary is TGLAbstractMaterialLibrary) then
  289. FMaterialLibrary.FreeNotification(Self);
  290. end;
  291. procedure TGLCustomGLSLFurShader.SetMainTexTexture(const Value: TGLTexture);
  292. begin
  293. if FMainTex = Value then Exit;
  294. FMainTex := Value;
  295. NotifyChange(Self)
  296. end;
  297. procedure TGLCustomGLSLFurShader.SetNoiseTexTexture(const Value: TGLTexture);
  298. begin
  299. if FNoiseTex = Value then Exit;
  300. FNoiseTex := Value;
  301. NotifyChange(Self);
  302. end;
  303. function TGLCustomGLSLFurShader.GetNoiseTexName: TGLLibMaterialName;
  304. begin
  305. Result := TGLMaterialLibrary(FMaterialLibrary).GetNameOfTexture(FNoiseTex);
  306. if Result = '' then Result := FNoiseTexName;
  307. end;
  308. procedure TGLCustomGLSLFurShader.SetNoiseTexName(const Value: TGLLibMaterialName);
  309. begin
  310. //Assert(not(assigned(FMaterialLibrary)),'You must set Material Library Before');
  311. if FNoiseTexName = Value then Exit;
  312. FNoiseTexName := Value;
  313. FNoiseTex := TGLMaterialLibrary(FMaterialLibrary).TextureByName(FNoiseTexName);
  314. NotifyChange(Self);
  315. end;
  316. function TGLCustomGLSLFurShader.GetMainTexName: TGLLibMaterialName;
  317. begin
  318. Result := TGLMaterialLibrary(FMaterialLibrary).GetNameOfTexture(FMainTex);
  319. if Result = '' then Result := FMainTexName;
  320. end;
  321. procedure TGLCustomGLSLFurShader.SetMainTexName(const Value: TGLLibMaterialName);
  322. begin
  323. // Assert(not(assigned(FMaterialLibrary)),'You must set Material Library Before');
  324. if FMainTexName = Value then Exit;
  325. FMainTexName := Value;
  326. FMainTex := TGLMaterialLibrary(FMaterialLibrary).TextureByName(FMainTexName);
  327. NotifyChange(Self);
  328. end;
  329. procedure TGLCustomGLSLFurShader.Notification(AComponent: TComponent; Operation: TOperation);
  330. var
  331. Index: Integer;
  332. begin
  333. inherited;
  334. if Operation = opRemove then
  335. if AComponent = FMaterialLibrary then
  336. if FMaterialLibrary <> nil then
  337. begin
  338. // Need to nil the textures that were owned by it
  339. if FNoiseTex <> nil then
  340. begin
  341. Index := TGLMaterialLibrary(FMaterialLibrary).Materials.GetTextureIndex(FNoiseTex);
  342. if Index <> -1 then
  343. SetNoiseTexTexture(nil);
  344. end;
  345. if FMainTex <> nil then
  346. begin
  347. Index := TGLMaterialLibrary(FMaterialLibrary).Materials.GetTextureIndex(FMainTex);
  348. if Index <> -1 then
  349. SetMainTexTexture(nil);
  350. end;
  351. FMaterialLibrary := nil;
  352. end;
  353. end;
  354. procedure TGLCustomGLSLFurShader.SetGravity(APosition: TGLCoordinates);
  355. begin
  356. FGravity.SetPoint(APosition.DirectX, APosition.DirectY, APosition.DirectZ);
  357. end;
  358. procedure TGLCustomGLSLFurShader.SetAmbient(AValue: TGLColor);
  359. begin
  360. FAmbient.DirectColor := AValue.Color;
  361. end;
  362. procedure TGLCustomGLSLFurShader.SetColorScale(AValue: TGLColor);
  363. begin
  364. FColorScale.DirectColor := AValue.Color;
  365. end;
  366. end.