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.

390 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. // $Id:$
  3. #ifndef RAYTRACE_H
  4. #define RAYTRACE_H
  5. #include <tier0/platform.h>
  6. #include <mathlib/vector.h>
  7. #include <mathlib/ssemath.h>
  8. #include <mathlib/lightdesc.h>
  9. #include <assert.h>
  10. #include <tier1/utlvector.h>
  11. #include <mathlib/mathlib.h>
  12. #include <bspfile.h>
  13. // fast SSE-ONLY ray tracing module. Based upon various "real time ray tracing" research.
  14. //#define DEBUG_RAYTRACE 1
  15. class FourRays
  16. {
  17. public:
  18. FourVectors origin;
  19. FourVectors direction;
  20. inline void Check(void) const
  21. {
  22. // in order to be valid to trace as a group, all four rays must have the same signs in all
  23. // of their direction components
  24. #ifndef NDEBUG
  25. for(int c=1;c<4;c++)
  26. {
  27. Assert(direction.X(0)*direction.X(c)>=0);
  28. Assert(direction.Y(0)*direction.Y(c)>=0);
  29. Assert(direction.Z(0)*direction.Z(c)>=0);
  30. }
  31. #endif
  32. }
  33. // returns direction sign mask for 4 rays. returns -1 if the rays can not be traced as a
  34. // bundle.
  35. int CalculateDirectionSignMask(void) const;
  36. };
  37. /// The format a triangle is stored in for intersections. size of this structure is important.
  38. /// This structure can be in one of two forms. Before the ray tracing environment is set up, the
  39. /// ProjectedEdgeEquations hold the coordinates of the 3 vertices, for facilitating bounding box
  40. /// checks needed while building the tree. afterwards, they are changed into the projected ege
  41. /// equations for intersection purposes.
  42. enum triangleflags
  43. {
  44. FCACHETRI_TRANSPARENT = 0x01,
  45. FCACHETRI_NEGATIVE_NORMAL = 0x02,
  46. };
  47. struct TriIntersectData_t
  48. {
  49. // this structure is 16longs=64 bytes for cache line packing.
  50. float m_flNx, m_flNy, m_flNz; // plane equation
  51. float m_flD;
  52. int32 m_nTriangleID; // id of the triangle.
  53. float m_ProjectedEdgeEquations[6]; // A,B,C for each edge equation. a
  54. // point is inside the triangle if
  55. // a*c1+b*c2+c is negative for all 3
  56. // edges.
  57. uint8 m_nCoordSelect0,m_nCoordSelect1; // the triangle is projected onto a 2d
  58. // plane for edge testing. These are
  59. // the indices (0..2) of the
  60. // coordinates preserved in the
  61. // projection
  62. uint8 m_nFlags; // triangle flags
  63. uint8 m_unused0; // no longer used
  64. };
  65. struct TriGeometryData_t
  66. {
  67. int32 m_nTriangleID; // id of the triangle.
  68. float m_VertexCoordData[9]; // can't use a vector in a union
  69. uint8 m_nFlags; // triangle flags
  70. signed char m_nTmpData0; // used by kd-tree builder
  71. signed char m_nTmpData1; // used by kd-tree builder
  72. // accessors to get around union annoyance
  73. FORCEINLINE Vector &Vertex(int idx)
  74. {
  75. return * ( reinterpret_cast<Vector *> ( m_VertexCoordData+3*idx ) );
  76. }
  77. };
  78. struct CacheOptimizedTriangle
  79. {
  80. union
  81. {
  82. TriIntersectData_t m_IntersectData;
  83. TriGeometryData_t m_GeometryData;
  84. } m_Data;
  85. // accessors to get around union annoyance
  86. FORCEINLINE Vector &Vertex(int idx)
  87. {
  88. return * ( reinterpret_cast<Vector *> (m_Data.m_GeometryData.m_VertexCoordData+3*idx ) );
  89. }
  90. FORCEINLINE const Vector &Vertex(int idx) const
  91. {
  92. return * ( reinterpret_cast<const Vector *> (m_Data.m_GeometryData.m_VertexCoordData+3*idx ) );
  93. }
  94. void ChangeIntoIntersectionFormat(void); // change information storage format for
  95. // computing intersections.
  96. int ClassifyAgainstAxisSplit(int split_plane, float split_value); // PLANECHECK_xxx below
  97. };
  98. #define PLANECHECK_POSITIVE 1
  99. #define PLANECHECK_NEGATIVE -1
  100. #define PLANECHECK_STRADDLING 0
  101. #define KDNODE_STATE_XSPLIT 0 // this node is an x split
  102. #define KDNODE_STATE_YSPLIT 1 // this node is a ysplit
  103. #define KDNODE_STATE_ZSPLIT 2 // this node is a zsplit
  104. #define KDNODE_STATE_LEAF 3 // this node is a leaf
  105. struct CacheOptimizedKDNode
  106. {
  107. // this is the cache intensive data structure. "Tricks" are used to fit it into 8 bytes:
  108. //
  109. // A) the right child is always stored after the left child, which means we only need one
  110. // pointer
  111. // B) The type of node (KDNODE_xx) is stored in the lower 2 bits of the pointer.
  112. // C) for leaf nodes, we store the number of triangles in the leaf in the same place as the floating
  113. // point splitting parameter is stored in a non-leaf node
  114. int32 Children; // child idx, or'ed with flags above
  115. float SplittingPlaneValue; // for non-leaf nodes, the nodes on the
  116. // "high" side of the splitting plane
  117. // are on the right
  118. #ifdef DEBUG_RAYTRACE
  119. Vector vecMins;
  120. Vector vecMaxs;
  121. #endif
  122. inline int NodeType(void) const
  123. {
  124. return Children & 3;
  125. }
  126. inline int32 TriangleIndexStart(void) const
  127. {
  128. assert(NodeType()==KDNODE_STATE_LEAF);
  129. return Children>>2;
  130. }
  131. inline int LeftChild(void) const
  132. {
  133. assert(NodeType()!=KDNODE_STATE_LEAF);
  134. return Children>>2;
  135. }
  136. inline int RightChild(void) const
  137. {
  138. return LeftChild()+1;
  139. }
  140. inline int NumberOfTrianglesInLeaf(void) const
  141. {
  142. assert(NodeType()==KDNODE_STATE_LEAF);
  143. return *((int32 *) &SplittingPlaneValue);
  144. }
  145. inline void SetNumberOfTrianglesInLeafNode(int n)
  146. {
  147. *((int32 *) &SplittingPlaneValue)=n;
  148. }
  149. protected:
  150. };
  151. struct RayTracingSingleResult
  152. {
  153. Vector surface_normal; // surface normal at intersection
  154. int32 HitID; // -1=no hit. otherwise, triangle index
  155. float HitDistance; // distance to intersection
  156. float ray_length; // leng of initial ray
  157. };
  158. struct RayTracingResult
  159. {
  160. FourVectors surface_normal; // surface normal at intersection
  161. ALIGN16 int32 HitIds[4] ALIGN16_POST; // -1=no hit. otherwise, triangle index
  162. fltx4 HitDistance; // distance to intersection
  163. };
  164. class RayTraceLight
  165. {
  166. public:
  167. FourVectors Position;
  168. FourVectors Intensity;
  169. };
  170. #define RTE_FLAGS_FAST_TREE_GENERATION 1
  171. #define RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS 2 // saves memory if not needed
  172. #define RTE_FLAGS_DONT_STORE_TRIANGLE_MATERIALS 4
  173. enum RayTraceLightingMode_t {
  174. DIRECT_LIGHTING, // just dot product lighting
  175. DIRECT_LIGHTING_WITH_SHADOWS, // with shadows
  176. GLOBAL_LIGHTING // global light w/ shadows
  177. };
  178. class RayStream
  179. {
  180. friend class RayTracingEnvironment;
  181. RayTracingSingleResult *PendingStreamOutputs[8][4];
  182. int n_in_stream[8];
  183. FourRays PendingRays[8];
  184. public:
  185. RayStream(void)
  186. {
  187. memset(n_in_stream,0,sizeof(n_in_stream));
  188. }
  189. };
  190. // When transparent triangles are in the list, the caller can provide a callback that will get called at each triangle
  191. // allowing the callback to stop processing if desired.
  192. // UNDONE: This is not currently SIMD - it really only supports single rays
  193. // Also for efficiency FourRays really needs some kind of active mask for the cases where rays get unbundled
  194. class ITransparentTriangleCallback
  195. {
  196. public:
  197. virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *hitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID ) = 0;
  198. };
  199. class RayTracingEnvironment
  200. {
  201. public:
  202. uint32 Flags; // RTE_FLAGS_xxx above
  203. Vector m_MinBound;
  204. Vector m_MaxBound;
  205. FourVectors BackgroundColor; //< color where no intersection
  206. CUtlVector<CacheOptimizedKDNode> OptimizedKDTree; //< the packed kdtree. root is 0
  207. CUtlBlockVector<CacheOptimizedTriangle> OptimizedTriangleList; //< the packed triangles
  208. CUtlVector<int32> TriangleIndexList; //< the list of triangle indices.
  209. CUtlVector<LightDesc_t> LightList; //< the list of lights
  210. CUtlVector<Vector> TriangleColors; //< color of tries
  211. CUtlVector<int32> TriangleMaterials; //< material index of tries
  212. public:
  213. RayTracingEnvironment() : OptimizedTriangleList( 1024 )
  214. {
  215. BackgroundColor.DuplicateVector(Vector(1,0,0)); // red
  216. Flags=0;
  217. }
  218. // call AddTriangle to set up the world
  219. void AddTriangle(int32 id, const Vector &v1, const Vector &v2, const Vector &v3,
  220. const Vector &color);
  221. // Adds a triangle with flags & material
  222. void AddTriangle(int32 id, const Vector &v1, const Vector &v2, const Vector &v3,
  223. const Vector &color, uint16 flags, int32 materialIndex);
  224. void AddQuad(int32 id, const Vector &v1, const Vector &v2, const Vector &v3,
  225. const Vector &v4, // specify vertices in cw or ccw order
  226. const Vector &color);
  227. // for ease of testing.
  228. void AddAxisAlignedRectangularSolid(int id,Vector mincoord, Vector Maxcoord,
  229. const Vector &color);
  230. // SetupAccelerationStructure to prepare for tracing
  231. void SetupAccelerationStructure(void);
  232. // lowest level intersection routine - fire 4 rays through the scene. all 4 rays must pass the
  233. // Check() function, and t extents must be initialized. skipid can be set to exclude a
  234. // particular id (such as the origin surface). This function finds the closest intersection.
  235. void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax,int DirectionSignMask,
  236. RayTracingResult *rslt_out,
  237. int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL);
  238. // higher level intersection routine that handles computing the mask and handling rays which do not match in direciton sign
  239. void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax,
  240. RayTracingResult *rslt_out,
  241. int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL);
  242. // compute virtual light sources to model inter-reflection
  243. void ComputeVirtualLightSources(void);
  244. // high level interface - pass viewing parameters, rendering flags, and a destination frame
  245. // buffer, and get a ray traced scene in 32-bit rgba format
  246. void RenderScene(int width, int height, // width and height of desired rendering
  247. int stride, // actual width in pixels of target buffer
  248. uint32 *output_buffer, // pointer to destination
  249. Vector CameraOrigin, // eye position
  250. Vector ULCorner, // word space coordinates of upper left
  251. // monitor corner
  252. Vector URCorner, // top right corner
  253. Vector LLCorner, // lower left
  254. Vector LRCorner, // lower right
  255. RayTraceLightingMode_t lightmode=DIRECT_LIGHTING);
  256. /// raytracing stream - lets you trace an array of rays by feeding them to this function.
  257. /// results will not be returned until FinishStream is called. This function handles sorting
  258. /// the rays by direction, tracing them 4 at a time, and de-interleaving the results.
  259. void AddToRayStream(RayStream &s,
  260. Vector const &start,Vector const &end,RayTracingSingleResult *rslt_out);
  261. inline void FlushStreamEntry(RayStream &s,int msk);
  262. /// call this when you are done. handles all cleanup. After this is called, all rslt ptrs
  263. /// previously passed to AddToRaySteam will have been filled in.
  264. void FinishRayStream(RayStream &s);
  265. int MakeLeafNode(int first_tri, int last_tri);
  266. float CalculateCostsOfSplit(
  267. int split_plane,int32 const *tri_list,int ntris,
  268. Vector MinBound,Vector MaxBound, float &split_value,
  269. int &nleft, int &nright, int &nboth);
  270. void RefineNode(int node_number,int32 const *tri_list,int ntris,
  271. Vector MinBound,Vector MaxBound, int depth);
  272. void CalculateTriangleListBounds(int32 const *tris,int ntris,
  273. Vector &minout, Vector &maxout);
  274. void AddInfinitePointLight(Vector position, // light center
  275. Vector intensity); // rgb amount
  276. // use the global variables set by LoadBSPFile to populated the RayTracingEnvironment with
  277. // faces.
  278. void InitializeFromLoadedBSP(void);
  279. void AddBSPFace(int id,dface_t const &face);
  280. // MakeRoomForTriangles - a hint telling it how many triangles we are going to add so that
  281. // the utl vectors used can be pre-allocated
  282. void MakeRoomForTriangles( int ntriangles );
  283. const CacheOptimizedTriangle &GetTriangle( int32 triID )
  284. {
  285. return OptimizedTriangleList[triID];
  286. }
  287. int32 GetTriangleMaterial( int32 triID )
  288. {
  289. return TriangleMaterials[triID];
  290. }
  291. const Vector &GetTriangleColor( int triID )
  292. {
  293. return TriangleColors[triID];
  294. }
  295. };
  296. #endif