home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 1_2002.ISO / Data / Zips / Semi-realt67388412002.psc / mdlPrimitives.bas < prev    next >
Encoding:
BASIC Source File  |  2002-04-01  |  12.4 KB  |  366 lines

  1. Attribute VB_Name = "mdlPrimitives"
  2. Option Explicit
  3. '//Realtime raytracer [version 2]
  4. '//Original (c++) version and other nice
  5. '//Raytrace versions (with shadows, cilinders, etc)
  6. '//Can be found at http://www.2tothex.com/
  7. '//VB port by Almar Joling / quadrantwars@quadrantwars.com
  8. '//Websites: http://www.quadrantwars.com (my game)
  9. '//          http://vbfibre.digitalrice.com (Many VB speed tricks with benchmarks)
  10.  
  11. '//This code is highly optimized. If you manage to gain some more FPS
  12. '//I'm always interested =-)
  13.  
  14. '//Finished @ 01/04/2002
  15. '//Feel free to post this code anywhere, but please leave the above info
  16. '//and author info intact. Thank you.
  17.  
  18.  
  19. '//Vector
  20. Public Type Vector3D
  21.     x As Single
  22.     y As Single
  23.     z As Single
  24. End Type
  25.  
  26. '//1 Ray
  27. Public Type Ray
  28.     Origin As Vector3D
  29.     Direction As Vector3D
  30. End Type
  31.  
  32. '//Color
  33. Public Type ColorFloat
  34.     R As Single
  35.     G As Single
  36.     b As Single
  37. End Type
  38.  
  39. '//Result of raytrace (for one ray)
  40. Public Type TraceResult
  41.     Hit As Boolean
  42.     Distance As Single
  43. End Type
  44.  
  45. '//Surface properties
  46. Public Type udtSurface
  47.     BaseColor As ColorFloat
  48.     sngReflectivity As Single
  49. End Type
  50.  
  51. '//Light source
  52. Public Type LightSource
  53.     location As Vector3D
  54.     Color As ColorFloat
  55. End Type
  56.  
  57. '-------------------------------
  58.  
  59. '//Primitives
  60. Public Enum EnumAxis
  61.     X_INFINITE
  62.     Y_INFINITE
  63.     Z_INFINITE
  64. End Enum
  65.  
  66. Public Type udtCylinder
  67.     Axis As EnumAxis
  68.     Center As Vector3D
  69.     sngRadius As Single
  70. End Type
  71.  
  72.  
  73. Public Type udtPlane
  74.     sngDisplacement As Single
  75.     vecNormal As Vector3D
  76. End Type
  77.  
  78. Public Type udtSphere
  79.     vecCenter As Vector3D
  80.     sngRadius As Single
  81. End Type
  82.  
  83. Public Type udtTriangle
  84.     v1 As Vector3D
  85.     v2 As Vector3D
  86.     v3 As Vector3D
  87. End Type
  88. '\\
  89.  
  90. '-------------------------------
  91.  
  92. '//Collection of primitives
  93. Public Enum EnumPrimitives
  94.     SPHERE_TYPE = 0
  95.     PLANE_TYPE = 1
  96.     CYLINDER_TYPE = 2
  97.     TRIANGLE_TYPE = 3
  98. End Enum
  99.  
  100. Public Type Primitive
  101.     Cilinder As udtCylinder
  102.     Plane As udtPlane
  103.     Sphere As udtSphere
  104.     Triangle As udtTriangle
  105.     Surface As udtSurface
  106.     Type As EnumPrimitives
  107. End Type
  108. '\\
  109.  
  110.  
  111.  
  112.  
  113. '//Math
  114.  
  115. Public Function CylinderNormal(Cylinder As udtCylinder, Intersection As Vector3D) As Vector3D
  116.     Dim Normal As Vector3D
  117.     Dim oneOverRadius As Single
  118.     oneOverRadius = 1 / Cylinder.sngRadius ' // might be faster to precalc this and store it in the sphere data structure, but also might be slower because it takes longer to load 32 bits of
  119.                                               '// data than to calculate 1 division (i think)
  120.     Select Case Cylinder.Axis
  121.         Case X_INFINITE
  122.             With Normal
  123.                 .x = 0
  124.                 .y = (Intersection.y - Cylinder.Center.y) * oneOverRadius
  125.                 .z = (Intersection.z - Cylinder.Center.z) * oneOverRadius
  126.                 CylinderNormal = Normal
  127.             End With
  128.             
  129.         Case Y_INFINITE
  130.             With Normal
  131.                 .x = (Intersection.x - Cylinder.Center.x) * oneOverRadius
  132.                 .y = 0
  133.                 .z = (Intersection.z - Cylinder.Center.z) * oneOverRadius
  134.                 CylinderNormal = Normal
  135.             End With
  136.             
  137.         Case Z_INFINITE
  138.             With Normal
  139.                 .x = (Intersection.x - Cylinder.Center.x) * oneOverRadius
  140.                 .y = (Intersection.y - Cylinder.Center.y) * oneOverRadius
  141.                 .z = 0
  142.                 CylinderNormal = Normal
  143.             End With
  144.     End Select
  145.     
  146. End Function
  147.  
  148. Public Function PlaneNormal(Plane As udtPlane) As Vector3D
  149.     PlaneNormal = Plane.vecNormal
  150. End Function
  151.  
  152. Public Function SphereNormal(Sphere As udtSphere, Intersection As Vector3D) As Vector3D
  153.     Dim Normal As Vector3D
  154.     Dim sngOneOverRadius As Single
  155.     '// calculate the normal of the sphere at the point of interesction
  156.     sngOneOverRadius = 1 / Sphere.sngRadius   '// might be faster to precalc this and store it in the sphere data structure, but also might be slower because it takes longer to load 32 bits of
  157.                                            '// data than to calculate 1 division (i think)
  158.     With Sphere.vecCenter
  159.         Normal.x = (Intersection.x - .x) * sngOneOverRadius  ' // same as ( intersection.x - sphere.center.x ) / sphere.radiu
  160.         Normal.y = (Intersection.y - .y) * sngOneOverRadius
  161.         Normal.z = (Intersection.z - .z) * sngOneOverRadius
  162.     End With
  163.     
  164.     SphereNormal = Normal
  165. End Function
  166.  
  167. Public Function TriangleNormal(Triangle As udtTriangle) As Vector3D
  168.     Dim vecEdge1 As Vector3D, vecEdge2 As Vector3D
  169.     Dim vecNormal As Vector3D
  170.     
  171.     vecEdge1 = VectorSub(Triangle.v2, Triangle.v1)
  172.     vecEdge2 = VectorSub(Triangle.v3, Triangle.v1)
  173.     vecNormal = VectorCross(vecEdge1, vecEdge2)
  174.     Call VectorNormalize(vecNormal)
  175.     
  176.     TriangleNormal = vecNormal
  177. End Function
  178.  
  179. '---------------------------------------------------------------------------------
  180. 'INTERSECT FUNCTIONS
  181. '---------------------------------------------------------------------------------
  182.  
  183. Public Function IntersectCylinder(Cylinder As udtCylinder, myRay As Ray) As TraceResult
  184.     Dim myTraceResult As TraceResult
  185.     Dim a As Single, b As Single, C As Single
  186.     Dim Discriminant As Single
  187.     
  188.     Select Case Cylinder.Axis
  189.         Case X_INFINITE
  190.             With myRay
  191.                 a = .Direction.y * .Direction.y + .Direction.z * .Direction.z
  192.                 b = 2 * (.Direction.y * (.Origin.y - Cylinder.Center.y) + .Direction.z * (.Origin.z - Cylinder.Center.z))
  193.                 C = (.Origin.y - Cylinder.Center.y) * (.Origin.y - Cylinder.Center.y) + (.Origin.z - Cylinder.Center.z) * (.Origin.z - Cylinder.Center.z) - Cylinder.sngRadius * Cylinder.sngRadius
  194.             End With
  195.             
  196.         Case Y_INFINITE
  197.             With myRay
  198.                 a = .Direction.x * .Direction.x + .Direction.z * .Direction.z
  199.                 b = 2 * (.Direction.x * (.Origin.x - Cylinder.Center.x) + .Direction.z * (.Origin.z - Cylinder.Center.z))
  200.                 C = (.Origin.x - Cylinder.Center.x) * (.Origin.x - Cylinder.Center.x) + (.Origin.z - Cylinder.Center.z) * (.Origin.z - Cylinder.Center.z) - Cylinder.sngRadius * Cylinder.sngRadius
  201.             End With
  202.             
  203.         Case Z_INFINITE:
  204.             With myRay
  205.                 a = .Direction.x * .Direction.x + .Direction.y * .Direction.y
  206.                 b = 2 * (.Direction.x * (.Origin.x - Cylinder.Center.x) + .Direction.y * (.Origin.y - Cylinder.Center.y))
  207.                 C = (.Origin.x - Cylinder.Center.x) * (.Origin.x - Cylinder.Center.x) + (.Origin.y - Cylinder.Center.y) * (.Origin.y - Cylinder.Center.y) - Cylinder.sngRadius * Cylinder.sngRadius
  208.             End With
  209.     End Select
  210.     
  211.     Discriminant = b * b - 4 * a * C
  212.     If Discriminant < 0 Then
  213.         myTraceResult.Hit = False
  214.         IntersectCylinder = myTraceResult
  215.         Exit Function
  216.     End If
  217.     
  218.     myTraceResult.Distance = (-b - Sqr(Discriminant)) / (2 * a)
  219.     If myTraceResult.Distance < 0 Then
  220.         myTraceResult.Hit = False
  221.         IntersectCylinder = myTraceResult
  222.         Exit Function
  223.     End If
  224.         
  225.     '//Return true
  226.     myTraceResult.Hit = True
  227.     IntersectCylinder = myTraceResult
  228.  
  229. End Function
  230.  
  231. Public Function IntersectPlane(Plane As udtPlane, myRay As Ray) As TraceResult
  232.     Dim myTraceResult As TraceResult
  233.     Dim t As Single
  234.     On Error Resume Next
  235.     
  236.     t = -(Plane.vecNormal.x * myRay.Origin.x + Plane.vecNormal.y * myRay.Origin.y + Plane.vecNormal.z * myRay.Origin.z + Plane.sngDisplacement) / (Plane.vecNormal.x * myRay.Direction.x + Plane.vecNormal.y * myRay.Direction.y + Plane.vecNormal.z * myRay.Direction.z)
  237.     
  238.     If t < 0 Then
  239.         myTraceResult.Hit = False
  240.         IntersectPlane = myTraceResult
  241.         Exit Function
  242.     End If
  243.     
  244.     myTraceResult.Hit = True
  245.     myTraceResult.Distance = t
  246.     IntersectPlane = myTraceResult
  247. End Function
  248.  
  249. Public Function IntersectSphere(Sphere As udtSphere, myRay As Ray) As TraceResult
  250.     Dim myTraceResult As TraceResult
  251.     Dim rayToSphereCenter As Vector3D
  252.     Dim lengthRTSC2 As Single, closestApproach As Single, halfCord2 As Single
  253.     
  254.     rayToSphereCenter = VectorSub(Sphere.vecCenter, myRay.Origin)
  255.     lengthRTSC2 = VectorDot(rayToSphereCenter, rayToSphereCenter)   ' // lengthRTSC2 = length of the ray from the ray's origin to the sphere's center squared
  256.       
  257.     closestApproach = VectorDot(rayToSphereCenter, myRay.Direction)
  258.     If closestApproach < 0 Then '// the intersection is behind the ray
  259.         myTraceResult.Hit = False
  260.         IntersectSphere = myTraceResult
  261.         Exit Function
  262.     End If
  263.     
  264.     '// halfCord2 = the distance squared from the closest approach of the ray to a perpendicular to the ray through the center of the sphere to the place where the ray actually intersects the sphere
  265.     halfCord2 = (Sphere.sngRadius * Sphere.sngRadius) - lengthRTSC2 + (closestApproach * closestApproach)  '// sphere.radius * sphere.radius could be precalced, but it might take longer to load it
  266.                                                                                                             '// than to calculate it
  267.     If halfCord2 < 0 Then '// the ray misses the sphere
  268.         myTraceResult.Hit = False
  269.         IntersectSphere = myTraceResult
  270.         Exit Function
  271.     End If
  272.     
  273.     myTraceResult.Hit = True
  274.     myTraceResult.Distance = closestApproach - Sqr(halfCord2)
  275.     IntersectSphere = myTraceResult
  276. End Function
  277.  
  278. Public Function IntersectTriangle(Triangle As udtTriangle, myRay As Ray) As TraceResult
  279.     Dim myTraceResult As TraceResult
  280.     Dim u As Single, V As Single
  281.     Dim edge1 As Vector3D, edge2 As Vector3D, tvec As Vector3D, pvec As Vector3D, qvec As Vector3D
  282.     Dim det As Single, invDet As Single
  283.     
  284.     edge1 = VectorSub(Triangle.v2, Triangle.v1)
  285.     edge2 = VectorSub(Triangle.v3, Triangle.v1)
  286.     pvec = VectorCross(myRay.Direction, edge2)
  287.     
  288.     det = VectorDot(edge1, pvec)
  289.     
  290.     With myTraceResult
  291.         If det > -0.000001 And det < 0.000001 Then
  292.             .Hit = False
  293.             IntersectTriangle = myTraceResult
  294.             Exit Function
  295.         End If
  296.         
  297.         invDet = 1 / det
  298.         
  299.         tvec = VectorSub(myRay.Origin, Triangle.v1)
  300.         
  301.         u = VectorDot(tvec, pvec) * invDet
  302.         
  303.         If u < 0 Or u > 1 Then
  304.             .Hit = False
  305.             IntersectTriangle = myTraceResult
  306.             Exit Function
  307.         End If
  308.         
  309.         qvec = VectorCross(tvec, edge1)
  310.         
  311.         V = VectorDot(myRay.Direction, qvec) * invDet
  312.         If (V < 0 Or (u + V) > 1) Then
  313.             .Hit = False
  314.             IntersectTriangle = myTraceResult
  315.             Exit Function
  316.         End If
  317.         
  318.         .Distance = VectorDot(edge2, qvec) * invDet
  319.         If (.Distance < 0) Then
  320.             .Hit = False
  321.             .Hit = False
  322.             IntersectTriangle = myTraceResult
  323.             Exit Function
  324.         End If
  325.         
  326.         .Hit = True
  327.         IntersectTriangle = myTraceResult
  328.     End With
  329. End Function
  330.  
  331. '// to optimize, write special shadow functions for each primitive. add a surface property: shadowed
  332. '// so it doesnt shadow itself
  333. Public Function IsShadowed(currPrimitiveNum As Long, rayToLight As Ray, distanceToLight As Single, Primitives() As Primitive, numPrimitives As Long)
  334.     Dim myTraceResult As TraceResult
  335.     Dim I As Long
  336.     myTraceResult.Hit = False
  337.     
  338.     '// check every other primitive
  339.     For I = 0 To numPrimitives
  340.         If I <> currPrimitiveNum Then  '// dont self-shadow
  341.             
  342.             Select Case Primitives(I).Type
  343.                 Case SPHERE_TYPE:
  344.                     myTraceResult = IntersectSphere(Primitives(I).Sphere, rayToLight)
  345.                 
  346.                 Case PLANE_TYPE:
  347.                     myTraceResult = IntersectPlane(Primitives(I).Plane, rayToLight)
  348.                 
  349.                 Case CYLINDER_TYPE:
  350.                     myTraceResult = IntersectCylinder(Primitives(I).Cilinder, rayToLight)
  351.                 
  352.                 Case TRIANGLE_TYPE:
  353.                     myTraceResult = IntersectTriangle(Primitives(I).Triangle, rayToLight)
  354.             End Select
  355.             
  356.             If (myTraceResult.Hit = True And (myTraceResult.Distance < distanceToLight)) Then
  357.                     IsShadowed = True
  358.                     Exit Function
  359.             End If
  360.         End If
  361.     Next I
  362.  
  363.     IsShadowed = False
  364.  
  365. End Function
  366.