Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

381 lines
12 KiB

  1. // $Id$
  2. #include "raytrace.h"
  3. #include <mathlib/halton.h>
  4. // NOTE: This has to be the last file included!
  5. #include "tier0/memdbgon.h"
  6. static uint32 MapDistanceToPixel(float t)
  7. {
  8. if (t<0) return 0xffff0000;
  9. if (t>100) return 0xff000000;
  10. int a=t*1000; a&=0xff;
  11. int b=t*10; b &=0xff;
  12. int c=t*.01; c &=0xff;
  13. return 0xff000000+(a<<16)+(b<<8)+c;
  14. }
  15. #define IGAMMA (1.0/2.2)
  16. #define MAGIC_NUMBER (1<<23)
  17. static fltx4 Four_MagicNumbers={ MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER };
  18. static ALIGN16 int32 Four_255s[4]= {0xff,0xff,0xff,0xff};
  19. #define PIXMASK ( * ( reinterpret_cast< fltx4 *>( &Four_255s ) ) )
  20. void MapLinearIntensities(FourVectors const &intens,uint32 *p1, uint32 *p2, uint32 *p3, uint32 *p4)
  21. {
  22. // convert four pixels worth of sse-style rgb into argb lwords
  23. // NOTE the _mm_empty macro is voodoo. do not mess with this routine casually - simply throwing
  24. // anything that ends up generating a fpu stack references in here would be bad news.
  25. static fltx4 pixscale={255.0,255.0,255.0,255.0};
  26. fltx4 r,g,b;
  27. r=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.x,IGAMMA)));
  28. g=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.y,IGAMMA)));
  29. b=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.z,IGAMMA)));
  30. // now, convert to integer
  31. r=AndSIMD( AddSIMD( r, Four_MagicNumbers ), PIXMASK );
  32. g=AndSIMD( AddSIMD( g, Four_MagicNumbers ), PIXMASK );
  33. b=AndSIMD( AddSIMD( b, Four_MagicNumbers ), PIXMASK );
  34. *(p1)=(SubInt(r, 0))|(SubInt(g, 0)<<8)|(SubInt(b, 0)<<16);
  35. *(p2)=(SubInt(r, 1))|(SubInt(g, 1)<<8)|(SubInt(b, 1)<<16);
  36. *(p3)=(SubInt(r, 2))|(SubInt(g, 2)<<8)|(SubInt(b, 2)<<16);
  37. *(p4)=(SubInt(r, 3))|(SubInt(g, 3)<<8)|(SubInt(b, 3)<<16);
  38. }
  39. static ALIGN16 int32 signmask[4]={0x80000000,0x80000000,0x80000000,0x80000000};
  40. static ALIGN16 int32 all_ones[4]={-1,-1,-1,-1};
  41. static fltx4 all_zeros={0,0,0,0};
  42. static fltx4 TraceLimit={1.0e20,1.0e20,1.0e20,1.0e20};
  43. void RayTracingEnvironment::RenderScene(
  44. int width, int height, // width and height of desired rendering
  45. int stride, // actual width in pixels of target buffer
  46. uint32 *output_buffer, // pointer to destination
  47. Vector CameraOrigin, // eye position
  48. Vector ULCorner, // word space coordinates of upper left
  49. // monitor corner
  50. Vector URCorner, // top right corner
  51. Vector LLCorner, // lower left
  52. Vector LRCorner, // lower right
  53. RayTraceLightingMode_t lmode)
  54. {
  55. // first, compute deltas
  56. Vector dxvector=URCorner;
  57. dxvector-=ULCorner;
  58. dxvector*=(1.0/width);
  59. Vector dxvectortimes2=dxvector;
  60. dxvectortimes2+=dxvector;
  61. Vector dyvector=LLCorner;
  62. dyvector-=ULCorner;
  63. dyvector*=(1.0/height);
  64. // block_offsets-relative offsets for eahc of the 4 pixels in the block, in sse format
  65. FourVectors block_offsets;
  66. block_offsets.LoadAndSwizzle(Vector(0,0,0),dxvector,dyvector,dxvector+dyvector);
  67. FourRays myrays;
  68. myrays.origin.DuplicateVector(CameraOrigin);
  69. // tmprays is used fo rthe case when we cannot trace 4 rays at once.
  70. FourRays tmprays;
  71. tmprays.origin.DuplicateVector(CameraOrigin);
  72. // now, we will ray trace pixels. we will do the rays in a 2x2 pattern
  73. for(int y=0;y<height;y+=2)
  74. {
  75. Vector SLoc=dyvector;
  76. SLoc*=((float) y);
  77. SLoc+=ULCorner;
  78. uint32 *dest=output_buffer+y*stride;
  79. for(int x=0;x<width;x+=2)
  80. {
  81. myrays.direction.DuplicateVector(SLoc);
  82. myrays.direction+=block_offsets;
  83. myrays.direction.VectorNormalize();
  84. RayTracingResult rslt;
  85. Trace4Rays(myrays,all_zeros,TraceLimit, &rslt);
  86. if ((rslt.HitIds[0]==-1) && (rslt.HitIds[1]==-1) &&
  87. (rslt.HitIds[2]==-1) && (rslt.HitIds[3]==-1))
  88. MapLinearIntensities(BackgroundColor,dest,dest+1,dest+stride,dest+stride+1);
  89. else
  90. {
  91. // make sure normal points back towards ray origin
  92. fltx4 ndoti=rslt.surface_normal*myrays.direction;
  93. fltx4 bad_dirs=AndSIMD(CmpGtSIMD(ndoti,Four_Zeros),
  94. LoadAlignedSIMD((float *) signmask));
  95. // flip signs of all "wrong" normals
  96. rslt.surface_normal.x=XorSIMD(bad_dirs,rslt.surface_normal.x);
  97. rslt.surface_normal.y=XorSIMD(bad_dirs,rslt.surface_normal.y);
  98. rslt.surface_normal.z=XorSIMD(bad_dirs,rslt.surface_normal.z);
  99. FourVectors intens;
  100. intens.DuplicateVector(Vector(0,0,0));
  101. // set up colors
  102. FourVectors surf_colors;
  103. surf_colors.DuplicateVector(Vector(0,0,0));
  104. for(int i=0;i<4;i++)
  105. {
  106. if (rslt.HitIds[i]>=0)
  107. {
  108. surf_colors.X(i)=TriangleColors[rslt.HitIds[i]].x;
  109. surf_colors.Y(i)=TriangleColors[rslt.HitIds[i]].y;
  110. surf_colors.Z(i)=TriangleColors[rslt.HitIds[i]].z;
  111. }
  112. }
  113. FourVectors surface_pos=myrays.direction;
  114. surface_pos*=rslt.HitDistance;
  115. surface_pos+=myrays.origin;
  116. switch(lmode)
  117. {
  118. case DIRECT_LIGHTING:
  119. {
  120. // light all points
  121. for(int l=0;l<LightList.Count();l++)
  122. {
  123. LightList[l].ComputeLightAtPoints(surface_pos,rslt.surface_normal,
  124. intens);
  125. }
  126. }
  127. break;
  128. case DIRECT_LIGHTING_WITH_SHADOWS:
  129. {
  130. // light all points
  131. for(int l=0;l<LightList.Count();l++)
  132. {
  133. FourVectors ldir;
  134. ldir.DuplicateVector(LightList[l].m_Position);
  135. ldir-=surface_pos;
  136. fltx4 MaxT=ldir.length();
  137. ldir.VectorNormalizeFast();
  138. // now, compute shadow flag
  139. FourRays myrays;
  140. myrays.origin=surface_pos;
  141. FourVectors epsilon=ldir;
  142. epsilon*=0.01;
  143. myrays.origin+=epsilon;
  144. myrays.direction=ldir;
  145. RayTracingResult shadowtest;
  146. Trace4Rays(myrays,Four_Zeros,MaxT, &shadowtest);
  147. bi32x4 unshadowed=CmpGtSIMD(shadowtest.HitDistance,MaxT);
  148. if (! (IsAllZeros(unshadowed)))
  149. {
  150. FourVectors tmp;
  151. tmp.DuplicateVector(Vector(0,0,0));
  152. LightList[l].ComputeLightAtPoints(surface_pos,rslt.surface_normal,
  153. tmp);
  154. intens.x=AddSIMD(intens.x,AndSIMD(tmp.x,unshadowed));
  155. intens.y=AddSIMD(intens.y,AndSIMD(tmp.y,unshadowed));
  156. intens.z=AddSIMD(intens.z,AndSIMD(tmp.z,unshadowed));
  157. }
  158. }
  159. }
  160. break;
  161. }
  162. // now, mask off non-hitting pixels
  163. intens.VProduct(surf_colors);
  164. bi32x4 no_hit_mask=CmpGtSIMD(rslt.HitDistance,TraceLimit);
  165. intens.x=OrSIMD(AndSIMD(BackgroundColor.x,no_hit_mask),
  166. AndNotSIMD(no_hit_mask,intens.x));
  167. intens.y=OrSIMD(AndSIMD(BackgroundColor.y,no_hit_mask),
  168. AndNotSIMD(no_hit_mask,intens.y));
  169. intens.z=OrSIMD(AndSIMD(BackgroundColor.y,no_hit_mask),
  170. AndNotSIMD(no_hit_mask,intens.z));
  171. MapLinearIntensities(intens,dest,dest+1,dest+stride,dest+stride+1);
  172. }
  173. dest+=2;
  174. SLoc+=dxvectortimes2;
  175. }
  176. }
  177. }
  178. #define SQ(x) ((x)*(x))
  179. void RayTracingEnvironment::ComputeVirtualLightSources(void)
  180. {
  181. int start_pos=0;
  182. for(int b=0;b<3;b++)
  183. {
  184. int nl=LightList.Count();
  185. int where_to_start=start_pos;
  186. start_pos=nl;
  187. for(int l=where_to_start;l<nl;l++)
  188. {
  189. DirectionalSampler_t sample_generator;
  190. int n_desired=1*LightList[l].m_Color.Length();
  191. if (LightList[l].m_Type==MATERIAL_LIGHT_SPOT)
  192. n_desired*=LightList[l].m_Phi/2;
  193. for(int try1=0;try1<n_desired;try1++)
  194. {
  195. LightDesc_t const &li=LightList[l];
  196. FourRays myrays;
  197. myrays.origin.DuplicateVector(li.m_Position);
  198. RayTracingResult rslt;
  199. Vector trial_dir=sample_generator.NextValue();
  200. if (li.IsDirectionWithinLightCone(trial_dir))
  201. {
  202. myrays.direction.DuplicateVector(trial_dir);
  203. Trace4Rays(myrays,all_zeros,ReplicateX4(1000.0), &rslt);
  204. if ((rslt.HitIds[0]!=-1))
  205. {
  206. // make sure normal points back towards ray origin
  207. fltx4 ndoti=rslt.surface_normal*myrays.direction;
  208. fltx4 bad_dirs=AndSIMD(CmpGtSIMD(ndoti,Four_Zeros),
  209. LoadAlignedSIMD((float *) signmask));
  210. // flip signs of all "wrong" normals
  211. rslt.surface_normal.x=XorSIMD(bad_dirs,rslt.surface_normal.x);
  212. rslt.surface_normal.y=XorSIMD(bad_dirs,rslt.surface_normal.y);
  213. rslt.surface_normal.z=XorSIMD(bad_dirs,rslt.surface_normal.z);
  214. // a hit! let's make a virtual light source
  215. // treat the virtual light as a disk with its center at the hit position
  216. // and its radius scaled by the amount of the solid angle this probe
  217. // represents.
  218. float area_of_virtual_light=
  219. 4.0*M_PI*SQ( SubFloat( rslt.HitDistance, 0 ) )*(1.0/n_desired);
  220. FourVectors intens;
  221. intens.DuplicateVector(Vector(0,0,0));
  222. FourVectors surface_pos=myrays.direction;
  223. surface_pos*=rslt.HitDistance;
  224. surface_pos+=myrays.origin;
  225. FourVectors delta=rslt.surface_normal;
  226. delta*=0.1;
  227. surface_pos+=delta;
  228. LightList[l].ComputeLightAtPoints(surface_pos,rslt.surface_normal,
  229. intens);
  230. FourVectors surf_colors;
  231. surf_colors.DuplicateVector(TriangleColors[rslt.HitIds[0]]);
  232. intens*=surf_colors;
  233. // see if significant
  234. LightDesc_t l1;
  235. l1.m_Type=MATERIAL_LIGHT_SPOT;
  236. l1.m_Position=Vector(surface_pos.X(0),surface_pos.Y(0),surface_pos.Z(0));
  237. l1.m_Direction=Vector(rslt.surface_normal.X(0),rslt.surface_normal.Y(0),
  238. rslt.surface_normal.Z(0));
  239. l1.m_Color=Vector(intens.X(0),intens.Y(0),intens.Z(0));
  240. if (l1.m_Color.Length()>0)
  241. {
  242. l1.m_Color*=area_of_virtual_light/M_PI;
  243. l1.m_Range=0.0;
  244. l1.m_Falloff=1.0;
  245. l1.m_Attenuation0=1.0;
  246. l1.m_Attenuation1=0.0;
  247. l1.m_Attenuation2=1.0; // intens falls off as 1/r^2
  248. l1.m_Theta=0;
  249. l1.m_Phi=M_PI;
  250. l1.RecalculateDerivedValues();
  251. LightList.AddToTail(l1);
  252. }
  253. }
  254. }
  255. }
  256. }
  257. }
  258. }
  259. static unsigned int GetSignMask(Vector const &v)
  260. {
  261. unsigned int ret=0;
  262. if (v.x<0.0)
  263. ret++;
  264. if (v.y<0)
  265. ret+=2;
  266. if (v.z<0)
  267. ret+=4;
  268. return ret;
  269. }
  270. inline void RayTracingEnvironment::FlushStreamEntry(RayStream &s,int msk, RTECullMode_t cullMode )
  271. {
  272. assert(msk>=0);
  273. assert(msk<8);
  274. fltx4 tmax=s.PendingRays[msk].direction.length();
  275. fltx4 scl=ReciprocalSaturateSIMD(tmax);
  276. s.PendingRays[msk].direction*=scl; // normalize
  277. RayTracingResult tmpresult;
  278. Trace4Rays(s.PendingRays[msk],Four_Zeros,tmax,msk,&tmpresult,-1,NULL,cullMode);
  279. // now, write out results
  280. for(int r=0;r<4;r++)
  281. {
  282. RayTracingSingleResult *out=s.PendingStreamOutputs[msk][r];
  283. out->ray_length=SubFloat( tmax, r );
  284. out->surface_normal.x=tmpresult.surface_normal.X(r);
  285. out->surface_normal.y=tmpresult.surface_normal.Y(r);
  286. out->surface_normal.z=tmpresult.surface_normal.Z(r);
  287. out->HitID=tmpresult.HitIds[r];
  288. out->HitDistance=SubFloat( tmpresult.HitDistance, r );
  289. }
  290. s.n_in_stream[msk]=0;
  291. }
  292. void RayTracingEnvironment::AddToRayStream(RayStream &s,
  293. Vector const &start,Vector const &end,
  294. RayTracingSingleResult *rslt_out,
  295. RTECullMode_t cullMode )
  296. {
  297. Vector delta=end;
  298. delta-=start;
  299. int msk=GetSignMask(delta);
  300. assert(msk>=0);
  301. assert(msk<8);
  302. int pos=s.n_in_stream[msk];
  303. assert(pos<4);
  304. s.PendingRays[msk].origin.X(pos)=start.x;
  305. s.PendingRays[msk].origin.Y(pos)=start.y;
  306. s.PendingRays[msk].origin.Z(pos)=start.z;
  307. s.PendingRays[msk].direction.X(pos)=delta.x;
  308. s.PendingRays[msk].direction.Y(pos)=delta.y;
  309. s.PendingRays[msk].direction.Z(pos)=delta.z;
  310. s.PendingStreamOutputs[msk][pos]=rslt_out;
  311. if (pos==3)
  312. {
  313. FlushStreamEntry(s,msk,cullMode);
  314. }
  315. else
  316. s.n_in_stream[msk]++;
  317. }
  318. void RayTracingEnvironment::FinishRayStream(RayStream &s, RTECullMode_t cullMode )
  319. {
  320. for(int msk=0;msk<8;msk++)
  321. {
  322. int cnt=s.n_in_stream[msk];
  323. if (cnt)
  324. {
  325. // fill in unfilled entries with dups of first
  326. for(int c=cnt;c<4;c++)
  327. {
  328. s.PendingRays[msk].origin.X(c) = s.PendingRays[msk].origin.X(0);
  329. s.PendingRays[msk].origin.Y(c) = s.PendingRays[msk].origin.Y(0);
  330. s.PendingRays[msk].origin.Z(c) = s.PendingRays[msk].origin.Z(0);
  331. s.PendingRays[msk].direction.X(c) = s.PendingRays[msk].direction.X(0);
  332. s.PendingRays[msk].direction.Y(c) = s.PendingRays[msk].direction.Y(0);
  333. s.PendingRays[msk].direction.Z(c) = s.PendingRays[msk].direction.Z(0);
  334. s.PendingStreamOutputs[msk][c]=s.PendingStreamOutputs[msk][0];
  335. }
  336. FlushStreamEntry(s,msk,cullMode);
  337. }
  338. }
  339. }