Deferred.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. /******************************************************************************/
  2. #include "!Header.h"
  3. /******************************************************************************/
  4. #define MacroFrom 192.0f
  5. #define MacroTo 320.0f
  6. #define MacroMax 0.70f
  7. #define MacroScale (1.0f/32)
  8. #define DEFAULT_TEX_SIZE 1024.0f // 1024x1024
  9. #define PARALLAX_MODE 1 // 1=best
  10. #define RELIEF_STEPS_MAX 32
  11. #define RELIEF_STEPS_BINARY 3 // 3 works good in most cases, 4 could be used for absolute best quality
  12. #define RELIEF_STEPS_MUL 0.75f // 0.75f gets slightly worse quality but better performance, 1.0f gets full quality but slower performance, default=0.75f
  13. #define RELIEF_LOD_OFFSET 0.33f // values >0 increase performance (by using fewer steps and smaller LOD's) which also makes results more soft and flat helping to reduce jitter for distant pixels, default=0.33f
  14. #define RELIEF_TAN_POS 1 // 0=gets worse quality but better performance (not good for triangles with vertexes with very different normals or for surfaces very close to camera), 1=gets full quality but slower performance, default=1
  15. #define RELIEF_DEC_NRM 1 // if reduce relief bump intensity where there are big differences between vtx normals, tangents and binormals, default=1
  16. #define RELIEF_MODE 1 // 1=best
  17. #define RELIEF_Z_LIMIT 0.4f // smaller values may cause leaking (UV swimming), and higher reduce bump intensity at angles, default=0.4f
  18. #define RELIEF_LOD_TEST 0 // close to camera (test enabled=4.76 fps, test disabled=4.99 fps), far from camera (test enabled=9.83 fps, test disabled=9.52 fps), conclusion: this test reduces performance when close to camera by a similar factor to when far away, however since more likely pixels will be close to camera (as for distant LOD's other shaders are used) we prioritize close to camera performance, so this check should be disabled, default=0
  19. /******************************************************************************/
  20. #define PARAMS \
  21. uniform Bool skin ,\
  22. uniform Int materials ,\
  23. uniform Int textures ,\
  24. uniform Int bump_mode ,\
  25. uniform Bool alpha_test,\
  26. uniform Bool light_map ,\
  27. uniform Bool detail ,\
  28. uniform Bool macro ,\
  29. uniform Bool rflct ,\
  30. uniform Bool color ,\
  31. uniform Bool mtrl_blend,\
  32. uniform Bool heightmap ,\
  33. uniform Int fx ,\
  34. uniform Bool tesselate
  35. /******************************************************************************/
  36. struct VS_PS
  37. {
  38. Vec2 tex :TEXCOORD0;
  39. Vec pos :TEXCOORD1;
  40. Vec _tpos :TEXCOORD2;
  41. Vec vel :TEXCOORD3;
  42. Matrix3 mtrx :TEXCOORD4; // !! may not be Normalized !!
  43. Vec2 tex_l :TEXCOORD7;
  44. VecH4 material:COLOR0 ;
  45. VecH col :COLOR1 ;
  46. #if DX9
  47. Half fade_out:COLOR0 ; // can't use TEXCOORD8 on DX9
  48. #elif GL
  49. #define fade_out material.x // can't use TEXCOORD8 and can't reuse COLOR0 on GL
  50. #else
  51. Half fade_out:TEXCOORD8;
  52. #endif
  53. Vec tpos() {return Normalize(_tpos);}
  54. };
  55. /******************************************************************************/
  56. // VS
  57. /******************************************************************************/
  58. void VS
  59. (
  60. VtxInput vtx,
  61. out VS_PS O,
  62. out Vec4 O_vtx:POSITION,
  63. IF_IS_CLIP
  64. PARAMS
  65. )
  66. {
  67. Vec pos=vtx.pos();
  68. VecH nrm, tan; if(bump_mode>=SBUMP_FLAT)nrm=vtx.nrm(); if(bump_mode>SBUMP_FLAT)tan=vtx.tan(nrm, heightmap);
  69. if(textures || detail)O.tex =vtx.tex (heightmap);
  70. if(light_map )O.tex_l =vtx.tex1 ();
  71. if(materials>1 )O.material=vtx.material();
  72. if(materials<=1)O.col.rgb=MaterialColor3();/*else
  73. if(!mtrl_blend )
  74. {
  75. O.col.rgb =O.material.x*MultiMaterial0Color3()
  76. +O.material.y*MultiMaterial1Color3();
  77. if(materials>=3)O.col.rgb+=O.material.z*MultiMaterial2Color3();
  78. if(materials>=4)O.col.rgb+=O.material.w*MultiMaterial3Color3();
  79. }*/
  80. if(color)
  81. {
  82. if(materials<=1 /*|| !mtrl_blend*/)O.col.rgb*=vtx.color3();
  83. else O.col.rgb =vtx.color3();
  84. }
  85. if(heightmap && textures && materials==1)O.tex*=MaterialTexScale();
  86. if(fx==FX_LEAF)
  87. {
  88. if(bump_mode> SBUMP_FLAT)BendLeaf(vtx.hlp(), pos, nrm, tan);else
  89. if(bump_mode==SBUMP_FLAT)BendLeaf(vtx.hlp(), pos, nrm );else
  90. BendLeaf(vtx.hlp(), pos );
  91. }
  92. if(fx==FX_LEAFS)
  93. {
  94. if(bump_mode> SBUMP_FLAT)BendLeafs(vtx.hlp(), vtx.size(), pos, nrm, tan);else
  95. if(bump_mode==SBUMP_FLAT)BendLeafs(vtx.hlp(), vtx.size(), pos, nrm );else
  96. BendLeafs(vtx.hlp(), vtx.size(), pos );
  97. }
  98. if(!skin)
  99. {
  100. #if MODEL>=SM_4 || MODEL==SM_GL
  101. if(true) // instance
  102. {
  103. O.vel=ObjVel[vtx.instance()]; // #PER_INSTANCE_VEL
  104. O.pos=TransformPos(pos, vtx.instance());
  105. if(bump_mode>=SBUMP_FLAT)O.mtrx[2]=TransformDir(nrm, vtx.instance());
  106. if(bump_mode> SBUMP_FLAT)O.mtrx[0]=TransformDir(tan, vtx.instance());
  107. if(fx==FX_GRASS)
  108. {
  109. BendGrass(pos, O.pos, vtx.instance());
  110. O.fade_out=GrassFadeOut(vtx.instance());
  111. }
  112. UpdateVelocities_VS(O.vel, pos, O.pos, vtx.instance());
  113. }else
  114. #endif
  115. {
  116. O.vel=ObjVel[0];
  117. O.pos=TransformPos(pos);
  118. if(bump_mode>=SBUMP_FLAT)O.mtrx[2]=TransformDir(nrm);
  119. if(bump_mode> SBUMP_FLAT)O.mtrx[0]=TransformDir(tan);
  120. if(fx==FX_GRASS)
  121. {
  122. BendGrass(pos, O.pos);
  123. O.fade_out=GrassFadeOut();
  124. }
  125. UpdateVelocities_VS(O.vel, pos, O.pos);
  126. }
  127. }else
  128. {
  129. VecI bone=vtx.bone();
  130. O.vel=GetBoneVel ( bone, vtx.weight());
  131. O.pos=TransformPos(pos, bone, vtx.weight());
  132. if(bump_mode>=SBUMP_FLAT)O.mtrx[2]=TransformDir(nrm, bone, vtx.weight());
  133. if(bump_mode> SBUMP_FLAT)O.mtrx[0]=TransformDir(tan, bone, vtx.weight());
  134. UpdateVelocities_VS(O.vel, pos, O.pos);
  135. }
  136. // normalize (have to do all at the same time, so all have the same lengths)
  137. if(bump_mode> SBUMP_FLAT // calculating binormal (this also covers the case when we have tangent from heightmap which is not Normalized)
  138. || bump_mode==SBUMP_RELIEF && RELIEF_DEC_NRM // needed for RELIEF_DEC_NRM effect
  139. || tesselate) // needed for tesselation
  140. {
  141. O.mtrx[2]=Normalize(O.mtrx[2]);
  142. if(bump_mode>SBUMP_FLAT)O.mtrx[0]=Normalize(O.mtrx[0]);
  143. }
  144. if(bump_mode>SBUMP_FLAT)O.mtrx[1]=vtx.bin(O.mtrx[2], O.mtrx[0], heightmap);
  145. if((bump_mode>=SBUMP_PARALLAX_MIN && bump_mode<=SBUMP_PARALLAX_MAX)
  146. || (bump_mode==SBUMP_RELIEF && !RELIEF_TAN_POS ))O._tpos=mul(O.mtrx, -O.pos);
  147. O_vtx=Project(O.pos); CLIP(O.pos);
  148. }
  149. /******************************************************************************/
  150. // PS
  151. /******************************************************************************/
  152. void PS
  153. (
  154. VS_PS I,
  155. IF_IS_FRONT
  156. out DeferredSolidOutput output,
  157. PARAMS
  158. )
  159. {
  160. VecH nrm;
  161. Half glow, specular, sss;
  162. if(bump_mode==SBUMP_ZERO)
  163. {
  164. glow =MaterialGlow();
  165. specular=MaterialSpecular();
  166. sss =MaterialSss();
  167. nrm =0;
  168. }else
  169. if(materials==1)
  170. {
  171. // apply tex coord bump offset
  172. if(textures==2)
  173. {
  174. if(bump_mode>=SBUMP_PARALLAX_MIN && bump_mode<=SBUMP_PARALLAX_MAX) // parallax mapping
  175. {
  176. const Int steps=bump_mode-SBUMP_PARALLAX0;
  177. Vec tpos=I.tpos();
  178. #if PARALLAX_MODE==0 // too flat
  179. Flt scale=MaterialBump()/steps;
  180. #elif PARALLAX_MODE==1 // best results (not as flat, and not much aliasing)
  181. Flt scale=MaterialBump()/(steps*Lerp(1, tpos.z, tpos.z)); // MaterialBump()/steps/Lerp(1, tpos.z, tpos.z);
  182. #elif PARALLAX_MODE==2 // generates too steep walls (not good for parallax)
  183. Flt scale=MaterialBump()/(steps*Lerp(1, tpos.z, Sat(tpos.z/0.5f))); // MaterialBump()/steps/Lerp(1, tpos.z, tpos.z);
  184. #elif PARALLAX_MODE==3 // introduces a bit too much aliasing/artifacts on surfaces perpendicular to view direction
  185. Flt scale=MaterialBump()/steps*(2-tpos.z); // MaterialBump()/steps*Lerp(1, 1/tpos.z, tpos.z)
  186. #else // correct however introduces way too much aliasing/artifacts on surfaces perpendicular to view direction
  187. Flt scale=MaterialBump()/steps/tpos.z;
  188. #endif
  189. tpos.xy*=scale;
  190. UNROLL for(Int i=0; i<steps; i++)I.tex+=(Tex(Col, I.tex).w-0.5f)*tpos.xy;
  191. }else
  192. if(bump_mode==SBUMP_RELIEF) // relief mapping
  193. {
  194. #if RELIEF_LOD_TEST
  195. BRANCH if(GetLod(I.tex, DEFAULT_TEX_SIZE)<=4)
  196. #endif
  197. {
  198. #if MODEL>=SM_4
  199. Flt TexSize, TexHeight; Col.GetDimensions(TexSize, TexHeight);
  200. #else
  201. Flt TexSize=DEFAULT_TEX_SIZE;
  202. #endif
  203. Flt lod=Max(0, GetLod(I.tex, TexSize)+RELIEF_LOD_OFFSET); // yes, can be negative, so use Max(0) to avoid increasing number of steps when surface is close to camera
  204. //lod=Trunc(lod); don't do this as it would reduce performance and generate more artifacts, with this disabled, we generate fewer steps gradually, and blend with the next MIP level softening results
  205. #if RELIEF_TAN_POS
  206. Vec tpos=Normalize(mul(I.mtrx, -I.pos));
  207. #else
  208. Vec tpos=I.tpos();
  209. #endif
  210. #if RELIEF_MODE==0
  211. Flt scale=MaterialBump();
  212. #elif RELIEF_MODE==1 // best
  213. Flt scale=MaterialBump()/Lerp(1, tpos.z, Sat(tpos.z/RELIEF_Z_LIMIT));
  214. #elif RELIEF_MODE==2 // produces slight aliasing/artifacts on surfaces perpendicular to view direction
  215. Flt scale=MaterialBump()/Max(tpos.z, RELIEF_Z_LIMIT);
  216. #else // correct however introduces way too much aliasing/artifacts on surfaces perpendicular to view direction
  217. Flt scale=MaterialBump()/tpos.z;
  218. #endif
  219. #if RELIEF_DEC_NRM
  220. scale*=Length2(I.mtrx[0])*Length2(I.mtrx[1])*Length2(I.mtrx[2]); // vtx matrix vectors are interpolated linearly, which means that if there are big differences between vtx vectors, then their length will be smaller and smaller, for example if #0 vtx normal is (1,0), and #1 vtx normal is (0,1), then interpolated value between them will be (0.5, 0.5)
  221. #endif
  222. tpos.xy*=-scale;
  223. Flt length=Length(tpos.xy) * TexSize / Pow(2, lod);
  224. if(RELIEF_STEPS_MUL!=1)if(lod>0)length*=RELIEF_STEPS_MUL; // don't use this for first LOD
  225. I.tex-=tpos.xy*0.5f;
  226. Int steps =Mid(length, 0, RELIEF_STEPS_MAX);
  227. Flt stp =1.0f/(steps+1),
  228. ray =1;
  229. Vec2 tex_step=tpos.xy*stp;
  230. #if 1 // linear + interval search (faster)
  231. // linear search
  232. Flt height_next, height_prev=0.5f; // use 0.5 as approximate average value, we could do "TexLodI(Col, I.tex, lod).w", however in tests that wasn't needed but only reduced performance
  233. LOOP for(Int i=0; ; i++)
  234. {
  235. ray -=stp;
  236. I.tex+=tex_step;
  237. height_next=TexLodI(Col, I.tex, lod).w;
  238. if(i>=steps || height_next>=ray)break;
  239. height_prev=height_next;
  240. }
  241. // interval search
  242. if(1)
  243. {
  244. Flt ray_prev=ray+stp;
  245. // prev pos: I.tex-tex_step, height_prev-ray_prev
  246. // next pos: I.tex , height_next-ray
  247. Flt hn=height_next-ray, hp=height_prev-ray_prev,
  248. frac=Sat(hn/(hn-hp));
  249. I.tex-=tex_step*frac;
  250. BRANCH if(lod<=0) // extra step (needed only for closeup)
  251. {
  252. Flt ray_cur=ray+stp*frac,
  253. height_cur=TexLodI(Col, I.tex, lod).w;
  254. if( height_cur>=ray_cur) // if still below, then have to go back more, lerp between this position and prev pos
  255. {
  256. // prev pos: I.tex-tex_step (BUT I.tex before adjustment), height_prev-ray_prev
  257. // next pos: I.tex , height_cur -ray_cur
  258. tex_step*=1-frac; // we've just travelled "tex_step*frac", so to go to the prev point, we need what's left, "tex_step*(1-frac)"
  259. }else // we went back too far, go forward, lerp between next pos and this position
  260. {
  261. // prev pos: I.tex , height_cur -ray_cur
  262. // next pos: I.tex (BUT I.tex before adjustment), height_next-ray
  263. hp=hn;
  264. tex_step*=-frac; // we've just travelled "tex_step*frac", so to go to the next point, we need the same way but other direction, "tex_step*-frac"
  265. }
  266. hn=height_cur-ray_cur;
  267. frac=Sat(hn/(hn-hp));
  268. I.tex-=tex_step*frac;
  269. }
  270. }
  271. #else // linear + binary search (slower because requires 3 tex reads in binary to get the same results as with only 0-1 tex reads in interval)
  272. // linear search
  273. LOOP for(Int i=0; ; i++)
  274. {
  275. ray -=stp;
  276. I.tex+=tex_step;
  277. if(i>=steps || TexLodI(Col, I.tex, lod).w>=ray)break;
  278. }
  279. // binary search
  280. {
  281. Flt ray_prev=ray+stp,
  282. l=0, r=1, m=0.5f;
  283. UNROLL for(Int i=0; i<RELIEF_STEPS_BINARY; i++)
  284. {
  285. Flt height=TexLodI(Col, I.tex-tex_step*m, lod).w;
  286. if( height>Lerp(ray, ray_prev, m))l=m;else r=m;
  287. m=Avg(l, r);
  288. }
  289. I.tex-=tex_step*m;
  290. }
  291. #endif
  292. }
  293. }
  294. }
  295. VecH4 tex_nrm; // #MaterialTextureChannelOrder
  296. if(textures==0)
  297. {
  298. if(detail)I.col.rgb+=GetDetail(I.tex).z;
  299. nrm =Normalize(I.mtrx[2]);
  300. glow =MaterialGlow ();
  301. specular=MaterialSpecular();
  302. }else
  303. if(textures==1)
  304. {
  305. VecH4 tex=Tex(Col, I.tex); if(alpha_test)AlphaTest(tex.w, I.fade_out, fx);
  306. I.col.rgb*=tex.rgb ; if(detail )I.col.rgb+=GetDetail(I.tex).z;
  307. nrm =Normalize(I.mtrx[2]);
  308. glow =MaterialGlow ();
  309. specular =MaterialSpecular();
  310. }else
  311. if(textures==2)
  312. {
  313. tex_nrm =Tex(Nrm, I.tex); if( alpha_test)AlphaTest(tex_nrm.a, I.fade_out, fx);
  314. glow =MaterialGlow (); if(!alpha_test)glow*=tex_nrm.a;
  315. specular=MaterialSpecular()*tex_nrm.z;
  316. if(bump_mode==SBUMP_FLAT)
  317. {
  318. nrm =Normalize(I.mtrx[2]);
  319. I.col.rgb*=Tex(Col, I.tex).rgb; if(detail)I.col.rgb+=GetDetail(I.tex).z;
  320. }else // normal mapping
  321. {
  322. VecH det;
  323. if(detail)det=GetDetail(I.tex);
  324. nrm.xy =(tex_nrm.xy*2-1)*MaterialRough();
  325. if(detail)nrm.xy+=det.xy;
  326. nrm.z =CalcZ(nrm.xy);
  327. nrm =Normalize(Transform(nrm, I.mtrx));
  328. I.col.rgb*=Tex(Col, I.tex).rgb;
  329. if(detail)I.col.rgb+=det.z;
  330. }
  331. }
  332. if(macro )I.col.rgb =Lerp(I.col.rgb, Tex(Mac, I.tex*MacroScale).rgb, LerpRS(MacroFrom, MacroTo, I.pos.z)*MacroMax);
  333. if(light_map)I.col.rgb*=Tex(Lum, I.tex_l).rgb;
  334. sss=MaterialSss();
  335. // reflection
  336. if(rflct)
  337. {
  338. Vec rfl=Transform3(reflect(I.pos, nrm), CamMatrix);
  339. I.col.rgb+=TexCube(Rfl, rfl).rgb*((textures==2) ? MaterialReflect()*tex_nrm.z : MaterialReflect());
  340. }
  341. }else // materials>1
  342. {
  343. // assuming that in multi materials textures!=0
  344. Vec2 tex0, tex1, tex2, tex3;
  345. tex0=I.tex*MultiMaterial0TexScale();
  346. tex1=I.tex*MultiMaterial1TexScale();
  347. if(materials>=3)tex2=I.tex*MultiMaterial2TexScale();
  348. if(materials>=4)tex3=I.tex*MultiMaterial3TexScale();
  349. // apply tex coord bump offset
  350. if(textures==2)
  351. {
  352. if(bump_mode>=SBUMP_PARALLAX_MIN && bump_mode<=SBUMP_PARALLAX_MAX) // parallax mapping
  353. {
  354. const Int steps=bump_mode-SBUMP_PARALLAX0;
  355. Vec tpos=I.tpos();
  356. #if PARALLAX_MODE==0 // too flat
  357. Flt scale=1/steps;
  358. #elif PARALLAX_MODE==1 // best results (not as flat, and not much aliasing)
  359. Flt scale=1/(steps*Lerp(1, tpos.z, tpos.z)); // 1/steps/Lerp(1, tpos.z, tpos.z);
  360. #elif PARALLAX_MODE==2 // generates too steep walls (not good for parallax)
  361. Flt scale=1/(steps*Lerp(1, tpos.z, Sat(tpos.z/0.5f)));
  362. #elif PARALLAX_MODE==3 // introduces a bit too much aliasing/artifacts on surfaces perpendicular to view direction
  363. Flt scale=1/steps*(2-tpos.z); // 1/steps*Lerp(1, 1/tpos.z, tpos.z)
  364. #else // correct however introduces way too much aliasing/artifacts on surfaces perpendicular to view direction
  365. Flt scale=1/steps/tpos.z;
  366. #endif
  367. tpos.xy*=scale;
  368. // (x-0.5)*bump_mul = x*bump_mul - 0.5*bump_mul
  369. VecH4 bump_mul; bump_mul.x=MultiMaterial0Bump();
  370. VecH4 bump_add; bump_mul.y=MultiMaterial1Bump(); if(materials==2){bump_mul.xy *=I.material.xy ; bump_add.xy =bump_mul.xy *-0.5f;}
  371. if(materials>=3)bump_mul.z=MultiMaterial2Bump(); if(materials==3){bump_mul.xyz *=I.material.xyz ; bump_add.xyz =bump_mul.xyz *-0.5f;}
  372. if(materials>=4)bump_mul.w=MultiMaterial3Bump(); if(materials==4){bump_mul.xyzw*=I.material.xyzw; bump_add.xyzw=bump_mul.xyzw*-0.5f;}
  373. UNROLL for(Int i=0; i<steps; i++) // I.tex+=(Tex(Col, I.tex).w-0.5f)*tpos.xy;
  374. {
  375. Half h =Tex(Col , tex0).w*bump_mul.x+bump_add.x
  376. +Tex(Col1, tex1).w*bump_mul.y+bump_add.y;
  377. if(materials>=3)h+=Tex(Col2, tex2).w*bump_mul.z+bump_add.z;
  378. if(materials>=4)h+=Tex(Col3, tex3).w*bump_mul.w+bump_add.w;
  379. Vec2 offset=h*tpos.xy;
  380. tex0+=offset;
  381. tex1+=offset;
  382. if(materials>=3)tex2+=offset;
  383. if(materials>=4)tex3+=offset;
  384. }
  385. }else
  386. if(bump_mode==SBUMP_RELIEF)
  387. {
  388. #if RELIEF_LOD_TEST
  389. BRANCH if(GetLod(I.tex, DEFAULT_TEX_SIZE)<=4)
  390. #endif
  391. {
  392. VecH4 bump_mul; bump_mul.x=MultiMaterial0Bump(); Half avg_bump;
  393. bump_mul.y=MultiMaterial1Bump(); if(materials==2){bump_mul.xy *=I.material.xy ; avg_bump=Sum(bump_mul.xy );} // use 'Sum' because they're premultipled by 'I.material'
  394. if(materials>=3)bump_mul.z=MultiMaterial2Bump(); if(materials==3){bump_mul.xyz *=I.material.xyz ; avg_bump=Sum(bump_mul.xyz );}
  395. if(materials>=4)bump_mul.w=MultiMaterial3Bump(); if(materials==4){bump_mul.xyzw*=I.material.xyzw; avg_bump=Sum(bump_mul.xyzw);}
  396. Flt TexSize=DEFAULT_TEX_SIZE, // here we have 2..4 textures, so use a default value
  397. lod=Max(0, GetLod(I.tex, TexSize)+RELIEF_LOD_OFFSET); // yes, can be negative, so use Max(0) to avoid increasing number of steps when surface is close to camera
  398. //lod=Trunc(lod); don't do this as it would reduce performance and generate more artifacts, with this disabled, we generate fewer steps gradually, and blend with the next MIP level softening results
  399. #if RELIEF_TAN_POS
  400. Vec tpos=Normalize(mul(I.mtrx, -I.pos));
  401. #else
  402. Vec tpos=I.tpos();
  403. #endif
  404. #if RELIEF_MODE==0
  405. Flt scale=avg_bump;
  406. #elif RELIEF_MODE==1 // best
  407. Flt scale=avg_bump/Lerp(1, tpos.z, Sat(tpos.z/RELIEF_Z_LIMIT));
  408. #elif RELIEF_MODE==2 // produces slight aliasing/artifacts on surfaces perpendicular to view direction
  409. Flt scale=avg_bump/Max(tpos.z, RELIEF_Z_LIMIT);
  410. #else // correct however introduces way too much aliasing/artifacts on surfaces perpendicular to view direction
  411. Flt scale=avg_bump/tpos.z;
  412. #endif
  413. #if RELIEF_DEC_NRM
  414. scale*=Length2(I.mtrx[0])*Length2(I.mtrx[1])*Length2(I.mtrx[2]); // vtx matrix vectors are interpolated linearly, which means that if there are big differences between vtx vectors, then their length will be smaller and smaller, for example if #0 vtx normal is (1,0), and #1 vtx normal is (0,1), then interpolated value between them will be (0.5, 0.5)
  415. #endif
  416. tpos.xy*=-scale;
  417. Flt length=Length(tpos.xy) * TexSize / Pow(2, lod);
  418. if(RELIEF_STEPS_MUL!=1)if(lod>0)length*=RELIEF_STEPS_MUL; // don't use this for first LOD
  419. //I.tex-=tpos.xy*0.5f;
  420. Vec2 offset=tpos.xy*0.5f;
  421. tex0-=offset;
  422. tex1-=offset;
  423. if(materials>=3)tex2-=offset;
  424. if(materials>=4)tex3-=offset;
  425. Int steps =Mid(length, 0, RELIEF_STEPS_MAX);
  426. Flt stp =1.0f/(steps+1),
  427. ray =1;
  428. Vec2 tex_step=tpos.xy*stp;
  429. #if 1 // linear + interval search (faster)
  430. // linear search
  431. Flt height_next, height_prev=0.5f; // use 0.5 as approximate average value, we could do "TexLodI(Col, I.tex, lod).w", however in tests that wasn't needed but only reduced performance
  432. LOOP for(Int i=0; ; i++)
  433. {
  434. ray-=stp;
  435. //I.tex+=tex_step;
  436. tex0+=tex_step;
  437. tex1+=tex_step;
  438. if(materials>=3)tex2+=tex_step;
  439. if(materials>=4)tex3+=tex_step;
  440. //height_next=TexLodI(Col, I.tex, lod).w;
  441. height_next =TexLodI(Col , tex0, lod).w*I.material.x
  442. +TexLodI(Col1, tex1, lod).w*I.material.y;
  443. if(materials>=3)height_next+=TexLodI(Col2, tex2, lod).w*I.material.z;
  444. if(materials>=4)height_next+=TexLodI(Col3, tex3, lod).w*I.material.w;
  445. if(i>=steps || height_next>=ray)break;
  446. height_prev=height_next;
  447. }
  448. // interval search
  449. if(1)
  450. {
  451. Flt ray_prev=ray+stp;
  452. // prev pos: I.tex-tex_step, height_prev-ray_prev
  453. // next pos: I.tex , height_next-ray
  454. Flt hn=height_next-ray, hp=height_prev-ray_prev,
  455. frac=Sat(hn/(hn-hp));
  456. //I.tex-=tex_step*frac;
  457. offset=tex_step*frac;
  458. tex0-=offset;
  459. tex1-=offset;
  460. if(materials>=3)tex2-=offset;
  461. if(materials>=4)tex3-=offset;
  462. BRANCH if(lod<=0) // extra step (needed only for closeup)
  463. {
  464. Flt ray_cur=ray+stp*frac,
  465. //height_cur=TexLodI(Col, I.tex, lod).w;
  466. height_cur =TexLodI(Col , tex0, lod).w*I.material.x
  467. +TexLodI(Col1, tex1, lod).w*I.material.y;
  468. if(materials>=3)height_cur+=TexLodI(Col2, tex2, lod).w*I.material.z;
  469. if(materials>=4)height_cur+=TexLodI(Col3, tex3, lod).w*I.material.w;
  470. if(height_cur>=ray_cur) // if still below, then have to go back more, lerp between this position and prev pos
  471. {
  472. // prev pos: I.tex-tex_step (BUT I.tex before adjustment), height_prev-ray_prev
  473. // next pos: I.tex , height_cur -ray_cur
  474. tex_step*=1-frac; // we've just travelled "tex_step*frac", so to go to the prev point, we need what's left, "tex_step*(1-frac)"
  475. }else // we went back too far, go forward, lerp between next pos and this position
  476. {
  477. // prev pos: I.tex , height_cur -ray_cur
  478. // next pos: I.tex (BUT I.tex before adjustment), height_next-ray
  479. hp=hn;
  480. tex_step*=-frac; // we've just travelled "tex_step*frac", so to go to the next point, we need the same way but other direction, "tex_step*-frac"
  481. }
  482. hn=height_cur-ray_cur;
  483. frac=Sat(hn/(hn-hp));
  484. //I.tex-=tex_step*frac;
  485. offset=tex_step*frac;
  486. tex0-=offset;
  487. tex1-=offset;
  488. if(materials>=3)tex2-=offset;
  489. if(materials>=4)tex3-=offset;
  490. }
  491. }
  492. #else // linear + binary search (slower because requires 3 tex reads in binary to get the same results as with only 0-1 tex reads in interval)
  493. this needs to be updated for 4 materials
  494. // linear search
  495. LOOP for(Int i=0; ; i++)
  496. {
  497. ray -=stp;
  498. I.tex+=tex_step;
  499. if(i>=steps || TexLodI(Col, I.tex, lod).w>=ray)break;
  500. }
  501. // binary search
  502. {
  503. Flt ray_prev=ray+stp,
  504. l=0, r=1, m=0.5f;
  505. UNROLL for(Int i=0; i<RELIEF_STEPS_BINARY; i++)
  506. {
  507. Half height=TexLodI(Col, I.tex-tex_step*m, lod).w;
  508. if( height>Lerp(ray, ray_prev, m))l=m;else r=m;
  509. m=Avg(l, r);
  510. }
  511. I.tex-=tex_step*m;
  512. }
  513. #endif
  514. }
  515. }
  516. }
  517. // detail texture
  518. VecH det0, det1, det2, det3;
  519. if( detail) // #MaterialTextureChannelOrder
  520. {
  521. det0=Tex(Det , tex0*MultiMaterial0DetScale()).xyz*MultiMaterial0DetMul()+MultiMaterial0DetAdd();
  522. det1=Tex(Det1, tex1*MultiMaterial1DetScale()).xyz*MultiMaterial1DetMul()+MultiMaterial1DetAdd();
  523. if(materials>=3)det2=Tex(Det2, tex2*MultiMaterial2DetScale()).xyz*MultiMaterial2DetMul()+MultiMaterial2DetAdd();
  524. if(materials>=4)det3=Tex(Det3, tex3*MultiMaterial3DetScale()).xyz*MultiMaterial3DetMul()+MultiMaterial3DetAdd();
  525. }
  526. // macro texture
  527. Half mac_blend;
  528. if( macro)mac_blend=LerpRS(MacroFrom, MacroTo, I.pos.z)*MacroMax;
  529. // combine color + detail + macro !! do this first because it may modify 'I.material' which affects secondary texture !!
  530. VecH tex;
  531. if(mtrl_blend)
  532. {
  533. VecH4 col0, col1, col2, col3;
  534. col0=Tex(Col , tex0); col0.rgb*=MultiMaterial0Color3(); I.material.x=MultiMaterialWeight(I.material.x, col0.a);
  535. col1=Tex(Col1, tex1); col1.rgb*=MultiMaterial1Color3(); I.material.y=MultiMaterialWeight(I.material.y, col1.a); if(materials==2)I.material.xy /=I.material.x+I.material.y;
  536. if(materials>=3){col2=Tex(Col2, tex2); col2.rgb*=MultiMaterial2Color3(); I.material.z=MultiMaterialWeight(I.material.z, col2.a); if(materials==3)I.material.xyz /=I.material.x+I.material.y+I.material.z;}
  537. if(materials>=4){col3=Tex(Col3, tex3); col3.rgb*=MultiMaterial3Color3(); I.material.w=MultiMaterialWeight(I.material.w, col3.a); if(materials==4)I.material.xyzw/=I.material.x+I.material.y+I.material.z+I.material.w;}
  538. {if(detail)col0.rgb+=det0.z; if(macro)col0.rgb=Lerp(col0.rgb, Tex(Mac , tex0*MacroScale).rgb, MultiMaterial0Macro()*mac_blend); tex =I.material.x*col0.rgb;}
  539. {if(detail)col1.rgb+=det1.z; if(macro)col1.rgb=Lerp(col1.rgb, Tex(Mac1, tex1*MacroScale).rgb, MultiMaterial1Macro()*mac_blend); tex+=I.material.y*col1.rgb;}
  540. if(materials>=3){if(detail)col2.rgb+=det2.z; if(macro)col2.rgb=Lerp(col2.rgb, Tex(Mac2, tex2*MacroScale).rgb, MultiMaterial2Macro()*mac_blend); tex+=I.material.z*col2.rgb;}
  541. if(materials>=4){if(detail)col3.rgb+=det3.z; if(macro)col3.rgb=Lerp(col3.rgb, Tex(Mac3, tex3*MacroScale).rgb, MultiMaterial3Macro()*mac_blend); tex+=I.material.w*col3.rgb;}
  542. }else
  543. {
  544. {VecH col0=Tex(Col , tex0).rgb; if(detail)col0+=det0.z; if(macro)col0=Lerp(col0, Tex(Mac , tex0*MacroScale).rgb, MultiMaterial0Macro()*mac_blend); tex =I.material.x*col0*MultiMaterial0Color3();}
  545. {VecH col1=Tex(Col1, tex1).rgb; if(detail)col1+=det1.z; if(macro)col1=Lerp(col1, Tex(Mac1, tex1*MacroScale).rgb, MultiMaterial1Macro()*mac_blend); tex+=I.material.y*col1*MultiMaterial1Color3();}
  546. if(materials>=3){VecH col2=Tex(Col2, tex2).rgb; if(detail)col2+=det2.z; if(macro)col2=Lerp(col2, Tex(Mac2, tex2*MacroScale).rgb, MultiMaterial2Macro()*mac_blend); tex+=I.material.z*col2*MultiMaterial2Color3();}
  547. if(materials>=4){VecH col3=Tex(Col3, tex3).rgb; if(detail)col3+=det3.z; if(macro)col3=Lerp(col3, Tex(Mac3, tex3*MacroScale).rgb, MultiMaterial3Macro()*mac_blend); tex+=I.material.w*col3*MultiMaterial3Color3();}
  548. }
  549. if(materials<=1 /*|| !mtrl_blend*/ || color)I.col.rgb*=tex;
  550. else I.col.rgb =tex;
  551. // normal, specular, glow !! do this second after modifying 'I.material' !!
  552. if(textures<=1)
  553. {
  554. nrm=Normalize(I.mtrx[2]);
  555. VecH2 tex =I.material.x*MultiMaterial0NormalAdd().zw // #MaterialTextureChannelOrder
  556. +I.material.y*MultiMaterial1NormalAdd().zw;
  557. if(materials>=3)tex+=I.material.z*MultiMaterial2NormalAdd().zw;
  558. if(materials>=4)tex+=I.material.w*MultiMaterial3NormalAdd().zw;
  559. specular=tex.x;
  560. glow =tex.y;
  561. // reflection
  562. if(rflct)
  563. {
  564. Vec rfl=Transform3(reflect(I.pos, nrm), CamMatrix);
  565. I.col.rgb+=TexCube(Rfl , rfl).rgb*(MultiMaterial0Reflect()*I.material.x);
  566. I.col.rgb+=TexCube(Rfl1, rfl).rgb*(MultiMaterial1Reflect()*I.material.y);
  567. if(materials>=3)I.col.rgb+=TexCube(Rfl2, rfl).rgb*(MultiMaterial2Reflect()*I.material.z);
  568. if(materials>=4)I.col.rgb+=TexCube(Rfl3, rfl).rgb*(MultiMaterial3Reflect()*I.material.w);
  569. }
  570. }else
  571. {
  572. Half tex_spec[4];
  573. if(bump_mode==SBUMP_FLAT)
  574. {
  575. nrm=Normalize(I.mtrx[2]);
  576. VecH2 tex; // #MaterialTextureChannelOrder
  577. {VecH2 nrm0; nrm0=Tex(Nrm , tex0).zw; if(rflct)tex_spec[0]=nrm0.x; nrm0=nrm0*MultiMaterial0NormalMul().zw+MultiMaterial0NormalAdd().zw; tex =I.material.x*nrm0;}
  578. {VecH2 nrm1; nrm1=Tex(Nrm1, tex1).zw; if(rflct)tex_spec[1]=nrm1.x; nrm1=nrm1*MultiMaterial1NormalMul().zw+MultiMaterial1NormalAdd().zw; tex+=I.material.y*nrm1;}
  579. if(materials>=3){VecH2 nrm2; nrm2=Tex(Nrm2, tex2).zw; if(rflct)tex_spec[2]=nrm2.x; nrm2=nrm2*MultiMaterial2NormalMul().zw+MultiMaterial2NormalAdd().zw; tex+=I.material.z*nrm2;}
  580. if(materials>=4){VecH2 nrm3; nrm3=Tex(Nrm3, tex3).zw; if(rflct)tex_spec[3]=nrm3.x; nrm3=nrm3*MultiMaterial3NormalMul().zw+MultiMaterial3NormalAdd().zw; tex+=I.material.w*nrm3;}
  581. specular=tex.x;
  582. glow =tex.y;
  583. }else // normal mapping
  584. {
  585. VecH4 tex; // #MaterialTextureChannelOrder
  586. {VecH4 nrm0=Tex(Nrm , tex0); if(rflct)tex_spec[0]=nrm0.z; nrm0=nrm0*MultiMaterial0NormalMul()+MultiMaterial0NormalAdd(); if(detail)nrm0.xy+=det0.xy; tex =I.material.x*nrm0;}
  587. {VecH4 nrm1=Tex(Nrm1, tex1); if(rflct)tex_spec[1]=nrm1.z; nrm1=nrm1*MultiMaterial1NormalMul()+MultiMaterial1NormalAdd(); if(detail)nrm1.xy+=det1.xy; tex+=I.material.y*nrm1;}
  588. if(materials>=3){VecH4 nrm2=Tex(Nrm2, tex2); if(rflct)tex_spec[2]=nrm2.z; nrm2=nrm2*MultiMaterial2NormalMul()+MultiMaterial2NormalAdd(); if(detail)nrm2.xy+=det2.xy; tex+=I.material.z*nrm2;}
  589. if(materials>=4){VecH4 nrm3=Tex(Nrm3, tex3); if(rflct)tex_spec[3]=nrm3.z; nrm3=nrm3*MultiMaterial3NormalMul()+MultiMaterial3NormalAdd(); if(detail)nrm3.xy+=det3.xy; tex+=I.material.w*nrm3;}
  590. nrm=VecH(tex.xy, CalcZ(tex.xy));
  591. nrm=Normalize(Transform(nrm, I.mtrx));
  592. specular=tex.z;
  593. glow =tex.w;
  594. }
  595. // reflection
  596. if(rflct)
  597. {
  598. Vec rfl=Transform3(reflect(I.pos, nrm), CamMatrix);
  599. I.col.rgb+=TexCube(Rfl , rfl).rgb*(MultiMaterial0Reflect()*I.material.x*tex_spec[0]);
  600. I.col.rgb+=TexCube(Rfl1, rfl).rgb*(MultiMaterial1Reflect()*I.material.y*tex_spec[1]);
  601. if(materials>=3)I.col.rgb+=TexCube(Rfl2, rfl).rgb*(MultiMaterial2Reflect()*I.material.z*tex_spec[2]);
  602. if(materials>=4)I.col.rgb+=TexCube(Rfl3, rfl).rgb*(MultiMaterial3Reflect()*I.material.w*tex_spec[3]);
  603. }
  604. }
  605. sss=0;
  606. }
  607. if(fx!=FX_GRASS && fx!=FX_LEAF && fx!=FX_LEAFS)BackFlip(nrm, front);
  608. I.col.rgb+=Highlight.rgb;
  609. UpdateColorBySss(I.col.rgb, nrm, sss);
  610. output.color (I.col.rgb );
  611. output.glow (glow );
  612. output.normal (nrm );
  613. output.specular(specular );
  614. output.velocity(I.vel, I.pos);
  615. }
  616. /******************************************************************************/
  617. // HULL / DOMAIN
  618. /******************************************************************************/
  619. #if MODEL>=SM_4
  620. HSData HSConstant(InputPatch<VS_PS,3> I) {return GetHSData(I[0].pos, I[1].pos, I[2].pos, I[0].mtrx[2], I[1].mtrx[2], I[2].mtrx[2]);}
  621. [maxtessfactor(5.0)]
  622. [domain("tri")]
  623. [partitioning("fractional_odd")] // use 'odd' because it supports range from 1.0 ('even' supports range from 2.0)
  624. [outputtopology("triangle_cw")]
  625. [patchconstantfunc("HSConstant")]
  626. [outputcontrolpoints(3)]
  627. VS_PS HS
  628. (
  629. InputPatch<VS_PS,3> I, UInt cp_id:SV_OutputControlPointID,
  630. PARAMS
  631. )
  632. {
  633. VS_PS O;
  634. O.pos =I[cp_id].pos ;
  635. if(materials<=1 /*|| !mtrl_blend*/ || color)O.col =I[cp_id].col ;
  636. O.vel =I[cp_id].vel ;
  637. if(textures || detail )O.tex =I[cp_id].tex ;
  638. if(light_map )O.tex_l =I[cp_id].tex_l ;
  639. if(materials>1 )O.material=I[cp_id].material;
  640. if(fx==FX_GRASS )O.fade_out=I[cp_id].fade_out;
  641. if(bump_mode==SBUMP_FLAT )O.mtrx[2] =I[cp_id].mtrx[2] ;
  642. if(bump_mode> SBUMP_FLAT )O.mtrx =I[cp_id].mtrx ;
  643. if((bump_mode>=SBUMP_PARALLAX_MIN && bump_mode<=SBUMP_PARALLAX_MAX)
  644. || (bump_mode==SBUMP_RELIEF && !RELIEF_TAN_POS ))O._tpos=I[cp_id]._tpos;
  645. return O;
  646. }
  647. /******************************************************************************/
  648. [domain("tri")]
  649. void DS
  650. (
  651. HSData hs_data, const OutputPatch<VS_PS,3> I, Vec B:SV_DomainLocation,
  652. out VS_PS O,
  653. out Vec4 O_vtx:POSITION,
  654. PARAMS
  655. )
  656. {
  657. if(materials<=1 /*|| !mtrl_blend*/ || color)O.col =I[0].col *B.z + I[1].col *B.x + I[2].col *B.y;
  658. O.vel =I[0].vel *B.z + I[1].vel *B.x + I[2].vel *B.y;
  659. if(textures || detail )O.tex =I[0].tex *B.z + I[1].tex *B.x + I[2].tex *B.y;
  660. if(light_map )O.tex_l =I[0].tex_l *B.z + I[1].tex_l *B.x + I[2].tex_l *B.y;
  661. if(materials>1 )O.material=I[0].material*B.z + I[1].material*B.x + I[2].material*B.y;
  662. if(fx==FX_GRASS )O.fade_out=I[0].fade_out*B.z + I[1].fade_out*B.x + I[2].fade_out*B.y;
  663. if(bump_mode>SBUMP_FLAT)
  664. {
  665. O.mtrx[0]=I[0].mtrx[0]*B.z + I[1].mtrx[0]*B.x + I[2].mtrx[0]*B.y;
  666. O.mtrx[1]=I[0].mtrx[1]*B.z + I[1].mtrx[1]*B.x + I[2].mtrx[1]*B.y;
  667. //mtrx[2] is handled below
  668. }
  669. if((bump_mode>=SBUMP_PARALLAX_MIN && bump_mode<=SBUMP_PARALLAX_MAX)
  670. || (bump_mode==SBUMP_RELIEF && !RELIEF_TAN_POS ))O._tpos=I[0]._tpos*B.z + I[1]._tpos*B.x + I[2]._tpos*B.y;
  671. SetDSPosNrm(O.pos, O.mtrx[2], I[0].pos, I[1].pos, I[2].pos, I[0].mtrx[2], I[1].mtrx[2], I[2].mtrx[2], B, hs_data, false, 0);
  672. O_vtx=Project(O.pos);
  673. }
  674. #endif
  675. /******************************************************************************/
  676. // TECHNIQUES
  677. /******************************************************************************/
  678. CUSTOM_TECHNIQUE
  679. /******************************************************************************/