Team Fortress 2 Source Code as on 22/4/2020
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.

350 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <tier0/platform.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include <stdlib.h>
  11. #include "bitmap/float_bm.h"
  12. #include "vstdlib/vstdlib.h"
  13. #include "raytrace.h"
  14. #include "mathlib/bumpvects.h"
  15. #include "mathlib/halton.h"
  16. #include "tier0/threadtools.h"
  17. #include "tier0/progressbar.h"
  18. // In order to handle intersections with wrapped copies, we repeat the bitmap triangles this many
  19. // times
  20. #define NREPS_TILE 1
  21. extern int n_intersection_calculations;
  22. struct SSBumpCalculationContext // what each thread needs to see
  23. {
  24. RayTracingEnvironment *m_pRtEnv;
  25. FloatBitMap_t *ret_bm; // the bitmnap we are building
  26. FloatBitMap_t const *src_bm;
  27. int nrays_to_trace_per_pixel;
  28. float bump_scale;
  29. Vector *trace_directions; // light source directions to trace
  30. Vector *normals;
  31. int min_y; // range of scanlines to computer for
  32. int max_y;
  33. uint32 m_nOptionFlags;
  34. int thread_number;
  35. };
  36. static unsigned SSBumpCalculationThreadFN( void * ctx1 )
  37. {
  38. SSBumpCalculationContext *ctx = ( SSBumpCalculationContext * ) ctx1;
  39. RayStream ray_trace_stream_ctx;
  40. RayTracingSingleResult * rslts = new
  41. RayTracingSingleResult[ctx->ret_bm->Width * ctx->nrays_to_trace_per_pixel];
  42. for( int y = ctx->min_y; y <= ctx->max_y; y++ )
  43. {
  44. if ( ctx->thread_number == 0 )
  45. ReportProgress("Computing output",(1+ctx->max_y-ctx->min_y),y-ctx->min_y);
  46. for( int r = 0; r < ctx->nrays_to_trace_per_pixel; r++ )
  47. {
  48. for( int x = 0; x < ctx->ret_bm->Width; x++ )
  49. {
  50. Vector surf_pnt( x, y, ctx->bump_scale * ctx->src_bm->Pixel( x, y, 3 ) );
  51. // move the ray origin up a hair
  52. surf_pnt.z += 0.55;
  53. Vector trace_end = surf_pnt;
  54. Vector trace_dir = ctx->trace_directions[ r ];
  55. trace_dir *= ( 1 + NREPS_TILE * 2 ) * max( ctx->src_bm->Width, ctx->src_bm->Height );
  56. trace_end += trace_dir;
  57. ctx->m_pRtEnv->AddToRayStream( ray_trace_stream_ctx, surf_pnt, trace_end,
  58. & ( rslts[ r + ctx->nrays_to_trace_per_pixel * ( x )] ));
  59. }
  60. }
  61. if ( ctx->nrays_to_trace_per_pixel )
  62. ctx->m_pRtEnv->FinishRayStream( ray_trace_stream_ctx );
  63. // now, all ray tracing results are in the results buffer. Determine the visible self-shadowed
  64. // bump map lighting at each vertex in each basis direction
  65. for( int x = 0; x < ctx->src_bm->Width; x++ )
  66. {
  67. int nNumChannels = ( ctx->m_nOptionFlags & SSBUMP_OPTION_NONDIRECTIONAL ) ? 1 : 3;
  68. for( int c = 0; c < nNumChannels; c++ )
  69. {
  70. float sum_dots = 0;
  71. float sum_possible_dots = 0;
  72. Vector ldir = g_localBumpBasis[c];
  73. float ndotl = DotProduct( ldir, ctx->normals[x + y * ctx->src_bm->Width] );
  74. if ( ndotl < 0 )
  75. ctx->ret_bm->Pixel( x, y, c ) = 0;
  76. else
  77. {
  78. if ( ctx->nrays_to_trace_per_pixel )
  79. {
  80. RayTracingSingleResult *this_rslt =
  81. rslts + ctx->nrays_to_trace_per_pixel * ( x );
  82. for( int r = 0; r < ctx->nrays_to_trace_per_pixel; r++ )
  83. {
  84. float dot;
  85. if ( ctx->m_nOptionFlags & SSBUMP_OPTION_NONDIRECTIONAL )
  86. dot = ctx->trace_directions[r].z;
  87. else
  88. dot = DotProduct( ldir, ctx->trace_directions[r] );
  89. if ( dot > 0 )
  90. {
  91. sum_possible_dots += dot;
  92. if ( this_rslt[r].HitID == - 1 )
  93. sum_dots += dot;
  94. }
  95. }
  96. }
  97. else
  98. {
  99. sum_dots = sum_possible_dots = 1.0;
  100. }
  101. ctx->ret_bm->Pixel( x, y, c ) = ( ndotl * sum_dots ) / sum_possible_dots;
  102. }
  103. }
  104. if ( ctx->m_nOptionFlags & SSBUMP_OPTION_NONDIRECTIONAL )
  105. {
  106. ctx->ret_bm->Pixel( x, y, 1 ) = ctx->ret_bm->Pixel( x, y, 0 ); // copy height
  107. ctx->ret_bm->Pixel( x, y, 2 ) = ctx->ret_bm->Pixel( x, y, 0 ); // copy height
  108. ctx->ret_bm->Pixel( x, y, 3 ) = ctx->ret_bm->Pixel( x, y, 0 ); // copy height
  109. }
  110. else
  111. {
  112. ctx->ret_bm->Pixel( x, y, 3 ) = ctx->src_bm->Pixel( x, y, 3 ); // copy height
  113. }
  114. }
  115. }
  116. delete[] rslts;
  117. return 0;
  118. }
  119. void FloatBitMap_t::ComputeVertexPositionsAndNormals( float flHeightScale, Vector **ppPosOut, Vector **ppNormalOut ) const
  120. {
  121. Vector *verts = new Vector[Width * Height];
  122. // first, calculate vertex positions
  123. for( int y = 0; y < Height; y++ )
  124. for( int x = 0; x < Width; x++ )
  125. {
  126. Vector * out = verts + x + y * Width;
  127. out->x = x;
  128. out->y = y;
  129. out->z = flHeightScale * Pixel( x, y, 3 );
  130. }
  131. Vector *normals = new Vector[Width * Height];
  132. // now, calculate normals, smoothed
  133. for( int y = 0; y < Height; y++ )
  134. for( int x = 0; x < Width; x++ )
  135. {
  136. // now, calculcate average normal
  137. Vector avg_normal( 0, 0, 0 );
  138. for( int xofs =- 1;xofs <= 1;xofs++ )
  139. for( int yofs =- 1;yofs <= 1;yofs++ )
  140. {
  141. int x0 = ( x + xofs );
  142. if ( x0 < 0 )
  143. x0 += Width;
  144. int y0 = ( y + yofs );
  145. if ( y0 < 0 )
  146. y0 += Height;
  147. x0 = x0 % Width;
  148. y0 = y0 % Height;
  149. int x1 = ( x0 + 1 ) % Width;
  150. int y1 = ( y0 + 1 ) % Height;
  151. // now, form the two triangles from this vertex
  152. Vector p0 = verts[x0 + y0 * Width];
  153. Vector e1 = verts[x1 + y0 * Width];
  154. e1 -= p0;
  155. Vector e2 = verts[x0 + y1 * Width];
  156. e2 -= p0;
  157. Vector n1;
  158. CrossProduct( e1, e2, n1 );
  159. if ( n1.z < 0 )
  160. n1.Negate();
  161. e1 = verts[x + y1 * Width];
  162. e1 -= p0;
  163. e2 = verts[x1 + y1 * Width];
  164. e2 -= p0;
  165. Vector n2;
  166. CrossProduct( e1, e2, n2 );
  167. if ( n2.z < 0 )
  168. n2.Negate();
  169. n1.NormalizeInPlace();
  170. n2.NormalizeInPlace();
  171. avg_normal += n1;
  172. avg_normal += n2;
  173. }
  174. avg_normal.NormalizeInPlace();
  175. normals[x + y * Width]= avg_normal;
  176. }
  177. *ppPosOut = verts;
  178. *ppNormalOut = normals;
  179. }
  180. FloatBitMap_t *FloatBitMap_t::ComputeSelfShadowedBumpmapFromHeightInAlphaChannel(
  181. float bump_scale, int nrays_to_trace_per_pixel,
  182. uint32 nOptionFlags ) const
  183. {
  184. // first, add all the triangles from the height map to the "world".
  185. // we will make multiple copies to handle wrapping
  186. int tcnt = 1;
  187. Vector * verts;
  188. Vector * normals;
  189. ComputeVertexPositionsAndNormals( bump_scale, & verts, & normals );
  190. RayTracingEnvironment rtEnv;
  191. rtEnv.Flags |= RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS; // save some ram
  192. if ( nrays_to_trace_per_pixel )
  193. {
  194. rtEnv.MakeRoomForTriangles( ( 1 + 2 * NREPS_TILE ) * ( 1 + 2 * NREPS_TILE ) * 2 * Height * Width );
  195. // now, add a whole mess of triangles to trace against
  196. for( int tilex =- NREPS_TILE; tilex <= NREPS_TILE; tilex++ )
  197. for( int tiley =- NREPS_TILE; tiley <= NREPS_TILE; tiley++ )
  198. {
  199. int min_x = 0;
  200. int max_x = Width - 1;
  201. int min_y = 0;
  202. int max_y = Height - 1;
  203. if ( tilex < 0 )
  204. min_x = Width / 2;
  205. if ( tilex > 0 )
  206. max_x = Width / 2;
  207. if ( tiley < 0 )
  208. min_y = Height / 2;
  209. if ( tiley > 0 )
  210. max_y = Height / 2;
  211. for( int y = min_y; y <= max_y; y++ )
  212. for( int x = min_x; x <= max_x; x++ )
  213. {
  214. Vector ofs( tilex * Width, tiley * Height, 0 );
  215. int x1 = ( x + 1 ) % Width;
  216. int y1 = ( y + 1 ) % Height;
  217. Vector v0 = verts[x + y * Width];
  218. Vector v1 = verts[x1 + y * Width];
  219. Vector v2 = verts[x1 + y1 * Width];
  220. Vector v3 = verts[x + y1 * Width];
  221. v0.x = x; v0.y = y;
  222. v1.x = x + 1; v1.y = y;
  223. v2.x = x + 1; v2.y = y + 1;
  224. v3.x = x; v3.y = y + 1;
  225. v0 += ofs; v1 += ofs; v2 += ofs; v3 += ofs;
  226. rtEnv.AddTriangle( tcnt++, v0, v1, v2, Vector( 1, 1, 1 ) );
  227. rtEnv.AddTriangle( tcnt++, v0, v3, v2, Vector( 1, 1, 1 ) );
  228. }
  229. }
  230. //printf("added %d triangles\n",tcnt-1);
  231. ReportProgress("Creating kd-tree",0,0);
  232. rtEnv.SetupAccelerationStructure();
  233. // ok, now we have built a structure for ray intersection. we will take advantage
  234. // of the SSE ray tracing code by intersecting rays as a batch.
  235. }
  236. // We need to calculate for each vertex (i.e. pixel) of the heightmap, how "much" of the world
  237. // it can see in each basis direction. we will do this by sampling a sphere of rays around the
  238. // vertex, and using dot-product weighting to measure the lighting contribution in each basis
  239. // direction. note that the surface normal is not used here. The surface normal will end up
  240. // being reflected in the result because of rays being blocked when they try to pass through
  241. // the planes of the triangles touching the vertex.
  242. // note that there is no reason inter-bounced lighting could not be folded into this
  243. // calculation.
  244. FloatBitMap_t * ret = new FloatBitMap_t( Width, Height );
  245. Vector *trace_directions=new Vector[nrays_to_trace_per_pixel];
  246. DirectionalSampler_t my_sphere_sampler;
  247. for( int r=0; r < nrays_to_trace_per_pixel; r++)
  248. {
  249. Vector trace_dir=my_sphere_sampler.NextValue();
  250. // trace_dir=Vector(1,0,0);
  251. trace_dir.z=fabs(trace_dir.z); // upwards facing only
  252. trace_directions[ r ]= trace_dir;
  253. }
  254. volatile SSBumpCalculationContext ctxs[32];
  255. ctxs[0].m_pRtEnv =& rtEnv;
  256. ctxs[0].ret_bm = ret;
  257. ctxs[0].src_bm = this;
  258. ctxs[0].nrays_to_trace_per_pixel = nrays_to_trace_per_pixel;
  259. ctxs[0].bump_scale = bump_scale;
  260. ctxs[0].trace_directions = trace_directions;
  261. ctxs[0].normals = normals;
  262. ctxs[0].min_y = 0;
  263. ctxs[0].max_y = Height - 1;
  264. ctxs[0].m_nOptionFlags = nOptionFlags;
  265. int nthreads = min( 32, (int)GetCPUInformation()->m_nPhysicalProcessors );
  266. ThreadHandle_t waithandles[32];
  267. int starty = 0;
  268. int ystep = Height / nthreads;
  269. for( int t = 0;t < nthreads; t++ )
  270. {
  271. if ( t )
  272. memcpy( (void * ) ( & ctxs[t] ), ( void * ) & ctxs[0], sizeof( ctxs[0] ));
  273. ctxs[t].thread_number = t;
  274. ctxs[t].min_y = starty;
  275. if ( t != nthreads - 1 )
  276. ctxs[t].max_y = min( Height - 1, starty + ystep - 1 );
  277. else
  278. ctxs[t].max_y = Height - 1;
  279. waithandles[t]= CreateSimpleThread( SSBumpCalculationThreadFN, ( SSBumpCalculationContext * ) & ctxs[t] );
  280. starty += ystep;
  281. }
  282. for(int t=0;t<nthreads;t++)
  283. {
  284. ThreadJoin( waithandles[t] );
  285. }
  286. if ( nOptionFlags & SSBUMP_MOD2X_DETAIL_TEXTURE )
  287. {
  288. const float flOutputScale = 0.5 * ( 1.0 / .57735026 ); // normalize so that a flat normal yields 0.5
  289. // scale output weights by color channel
  290. for( int nY = 0; nY < Height; nY++ )
  291. for( int nX = 0; nX < Width; nX++ )
  292. {
  293. float flScale = flOutputScale * (2.0/3.0) * ( Pixel( nX, nY, 0 ) + Pixel( nX, nY, 1 ) + Pixel( nX, nY, 2 ) );
  294. ret->Pixel( nX, nY, 0 ) *= flScale;
  295. ret->Pixel( nX, nY, 1 ) *= flScale;
  296. ret->Pixel( nX, nY, 2 ) *= flScale;
  297. }
  298. }
  299. delete[] verts;
  300. delete[] trace_directions;
  301. delete[] normals;
  302. return ret; // destructor will clean up rtenv
  303. }
  304. // generate a conventional normal map from a source with height stored in alpha.
  305. FloatBitMap_t *FloatBitMap_t::ComputeBumpmapFromHeightInAlphaChannel( float bump_scale ) const
  306. {
  307. Vector *verts;
  308. Vector *normals;
  309. ComputeVertexPositionsAndNormals( bump_scale, &verts, &normals );
  310. FloatBitMap_t *ret=new FloatBitMap_t( Width, Height );
  311. for( int y = 0; y < Height; y++ )
  312. for( int x = 0; x < Width; x++ )
  313. {
  314. Vector const & N = normals[ x + y * Width ];
  315. ret->Pixel( x, y, 0 ) = 0.5+ 0.5 * N.x;
  316. ret->Pixel( x, y, 1 ) = 0.5+ 0.5 * N.y;
  317. ret->Pixel( x, y, 2 ) = 0.5+ 0.5 * N.z;
  318. ret->Pixel( x, y, 3 ) = Pixel( x, y, 3 );
  319. }
  320. return ret;
  321. }