Tässä se nyt on reaaliaikainen raytracing!
Toimii vain ja ainoastaan VB.Net 2003:ssa, johtuen <<, >> operaattoreista.
Ne ovat muutettavissa hitaammiksi käskyiksi, olen sen joskus tehnyt en enää vaan muista miten. Siinäpä haastetta jollekin. ;)
Ominaisuuksia ovat:
Valot
Varjot
Heijastukset
Liikkuminen
erilaiset primitiivit(taso, kolmio, sylinteri ja pallo)
liikkua voit nuolista vasemmalle oikealle eteen, taakse
numpadin 4 ja 8 pyörittävät
Tämä on aika hidas(aprox 0.5 fps)
Jos joku keksii optimointeja, olisiko ystävällinen ja kertoisi minulle!
Koodi on itse kirjoitettua, mutta olen suuren osan kääntänyt valmiista c++ koodista. ( http://www.2tothex.com/raytracing/ )
Tässä on kaikki koodi! n. 900 riviä! Kopioi kaikki koodi suoraan kaiken jo valmiin koodin päälle(sekavaa) =).
Selvennys: maalaa kaikki + ctrl + c sitten vb.netissä maalaa kaikki + ctrl + v
Valitan koodin pituutta. =( En vaan saanut tätä koodia järkevästi supistettua. Luettavuus olisi kärsinyt entisestään.
Kommentointi on englanninkielistä, johtuen lähdemateriaalista. Kommentointi on myös aika heikkoa.
Edit: Jos joku viitsii, niin voisi lisätä spotti ja suunta valot. Itsekin taidan ne joskus lisätä, kun jaksan. Yllä olevasta linkistä saa lisätietoa
Edit: Tuo n. 0.5 fps on saavutettu koneella:
Intel Pentium 4 1.8Ghz, 256mb 400mhz RDRAM
Public Structure ColorFloat Dim r, g, b As Double End Structure Public Structure Surface Dim baseColor As ColorFloat Dim reflectivity As Double End Structure Public Structure LightSource Dim location As Vector.sVector Dim c As ColorFloat ' values from 0 to 1 are within normal range. above that makes light brighter End Structure Public Class frmRaytracer Inherits System.Windows.Forms.Form Dim backbuffer As Bitmap Dim a As Double Const numPrimitives As Integer = 15 Dim primitives(numPrimitives) As Primitive.sPrimitive Const numLightSources As Integer = 4 Dim lightSources(numLightSources) As LightSource Const numVertices As Integer = 4 Dim vertices(numVertices) As Vector.sVector Dim directionTable() As Vector.sVector Dim cameraLocXDelta, cameraLocYDelta, cameraLocZDelta As Double Dim cameraRotX, cameraRoty, cameraRotz As Double #Region " Windows Form Designer generated code " Public Sub New() MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent() 'Add any initialization after the InitializeComponent() call End Sub 'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer 'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. Friend WithEvents picSurface As System.Windows.Forms.PictureBox <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.picSurface = New System.Windows.Forms.PictureBox Me.SuspendLayout() ' 'picSurface ' Me.picSurface.Location = New System.Drawing.Point(0, 0) Me.picSurface.Name = "picSurface" Me.picSurface.Size = New System.Drawing.Size(616, 520) Me.picSurface.TabIndex = 0 Me.picSurface.TabStop = False ' 'frmRaytracer ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(616, 518) Me.Controls.Add(Me.picSurface) Me.Name = "frmRaytracer" Me.Text = "Raytracer" Me.ResumeLayout(False) End Sub #End Region Private Sub frmRaytracer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim i As Integer ' allocate the ray direction lookup table directionTable = Tracer.GenerateRayDirectionTable SetupScene(primitives, numPrimitives, vertices, numVertices, lightSources, numLightSources) backbuffer = New Bitmap(picSurface.Width, picSurface.Height) End Sub Private Sub UpdateScene(ByVal primitives() As Primitive.sPrimitive, ByVal numPrimitives As Integer, ByVal vertices() As Vector.sVector, ByVal numVertices As Integer, ByVal lightSources() As LightSource, ByVal numLightSources As Integer, ByVal currTime As Double) Dim i As Integer For i = 0 To numPrimitives primitives(i).surface.baseColor.r = 128 * Math.Sin(currTime * i) + 128 primitives(i).surface.baseColor.g = 128 * Math.Sin(currTime * i + 3 + Math.Sin(currTime)) + 128 primitives(i).surface.baseColor.b = 128 * Math.Sin(currTime * i + 2 + 1.5 * Math.Sin(currTime)) + 128 primitives(i).surface.reflectivity = 0.5 + 0.5 * Math.Sin(currTime + i) Next Dim normal As Vector.sVector Vector.VectorSetXYZ(normal, 0.14999999999999999, -1, 0) Vector.Rotate(normal, 0, currTime, 0) primitives(0).planeProperties.normal = normal Vector.VectorSetXYZ(vertices(0), 0, -100, 50) Vector.Rotate(vertices(0), currTime * 1.3999999999999999, currTime, currTime * 1.2352000000000001) Vector.VectorSetXYZ(vertices(1), 100, 100, 0) Vector.Rotate(vertices(1), currTime * 1.3999999999999999, currTime, currTime * 1.2352000000000001) Vector.VectorSetXYZ(vertices(2), 0, 100, 250) Vector.Rotate(vertices(2), currTime * 1.3999999999999999, currTime, currTime * 1.2352000000000001) Vector.VectorSetXYZ(vertices(3), -100, 100, 0) Vector.Rotate(vertices(3), currTime * 1.3999999999999999, currTime, currTime * 1.2352000000000001) primitives(5).cylinderProperties.radius = 60 + 40 * Math.Sin(currTime) For i = 6 To numPrimitives Vector.VectorSetXYZ(primitives(i).sphereProperties.center, 120 * Math.Sin(currTime + i * 2 + 0.56000000000000005), 120 * Math.Sin(currTime + i * 2 + 3 * Math.Sin(currTime * 0.20000000000000001)), 120 * Math.Sin(currTime + i * 5 + 1 + Math.Sin(currTime * 0.10000000000000001))) primitives(i).sphereProperties.radius = 30 * Math.Sin(currTime * 0.40000000000000002 + Math.Sin(currTime + i)) + 40 Next For i = 0 To numLightSources lightSources(i).location.x = 250 * Math.Sin(currTime * 0.5 + i) lightSources(i).location.y = -100 lightSources(i).location.z = 250 * Math.Cos(currTime * 0.5 + i) lightSources(i).c.r = 0.14999999999999999 * Math.Sin(currTime + i) + 0.29999999999999999 lightSources(i).c.g = 0.14999999999999999 * Math.Sin(currTime + 3 + Math.Sin(currTime + i)) + 0.29999999999999999 lightSources(i).c.b = 0.14999999999999999 * Math.Sin(currTime * i + 2 + 1.5 * Math.Sin(currTime)) + 0.29999999999999999 Next End Sub Private Sub SetupScene(ByVal primitives() As Primitive.sPrimitive, ByVal numPrimitives As Integer, ByVal vertices() As Vector.sVector, ByVal numVertices As Integer, ByVal lightSources() As LightSource, ByVal numLightSources As Integer) Primitive.AssignPrimitiveType(primitives(0), Primitive.PrimitiveType.PLANE_TYPE) primitives(0).planeProperties.displacement = 150 Primitive.AssignPrimitiveType(primitives(1), Primitive.PrimitiveType.TRIANGLE_TYPE) primitives(1).triangleProperties.v1 = vertices(0) primitives(1).triangleProperties.v2 = vertices(1) primitives(1).triangleProperties.v3 = vertices(2) Primitive.AssignPrimitiveType(primitives(2), Primitive.PrimitiveType.TRIANGLE_TYPE) primitives(2).triangleProperties.v1 = vertices(0) primitives(2).triangleProperties.v2 = vertices(3) primitives(2).triangleProperties.v3 = vertices(1) Primitive.AssignPrimitiveType(primitives(3), Primitive.PrimitiveType.TRIANGLE_TYPE) primitives(3).triangleProperties.v1 = vertices(0) primitives(3).triangleProperties.v2 = vertices(2) primitives(3).triangleProperties.v3 = vertices(3) Primitive.AssignPrimitiveType(primitives(4), Primitive.PrimitiveType.TRIANGLE_TYPE) primitives(4).triangleProperties.v1 = vertices(1) primitives(4).triangleProperties.v2 = vertices(3) primitives(4).triangleProperties.v3 = vertices(2) Primitive.AssignPrimitiveType(primitives(5), Primitive.PrimitiveType.CYLINDER_TYPE) primitives(5).cylinderProperties.axis = Cylinder.eAxis.Y_INFINITE Vector.VectorSetXYZ(primitives(5).cylinderProperties.center, -200, 0, 150) Dim i As Integer For i = 6 To numPrimitives Primitive.AssignPrimitiveType(primitives(i), Primitive.PrimitiveType.SPHERE_TYPE) Next End Sub Private Sub frmRaytracer_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated Dim Cam As Camera.cCamera = New Camera.cCamera Camera.SetupCamera(Cam) Do While 1 = 1 Cam.location.x += cameraLocXDelta Cam.location.y += cameraLocYDelta Cam.location.z += cameraLocZDelta Camera.CameraRotate(Cam, cameraRotX, cameraRotY, cameraRotZ) a += 0.10000000000000001 If a >= 2 * Math.PI Then a = 0 UpdateScene(primitives, numPrimitives, vertices, numVertices, lightSources, numLightSources, a * 0.5) Tracer.TraceScene(Cam, primitives, numPrimitives, lightSources, numLightSources, backbuffer, directionTable) picSurface.BackgroundImage = backbuffer picSurface.Refresh() Application.DoEvents() Loop End Sub Private Sub frmRaytracer_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown Select Case e.KeyCode Case Keys.Up cameraLocZDelta = 100 Case Keys.Down cameraLocZDelta = -100 Case Keys.Left cameraLocXDelta = -100 Case Keys.Right cameraLocXDelta = 100 Case Keys.NumPad4 cameraRoty = -0.10000000000000001 Case Keys.NumPad6 cameraRoty = 0.10000000000000001 'Case Keys.NumPad8 ' cameraRotX = 0.10000000000000001 'Case Keys.NumPad5 ' cameraRotX = -0.10000000000000001 End Select End Sub Private Sub frmRaytracer_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp Select Case e.KeyCode Case Keys.Up cameraLocZDelta = 0 Case Keys.Down cameraLocZDelta = 0 Case Keys.Left cameraLocXDelta = 0 Case Keys.Right cameraLocXDelta = 0 Case Keys.NumPad4 cameraRoty = 0 Case Keys.NumPad6 cameraRoty = 0 'Case Keys.NumPad8 ' bugi pallot katoo ' cameraRotX = 0 'Case Keys.NumPad5 ' cameraRotX = 0 End Select End Sub End Class Public Class Tracer Public Shared Function GenerateRayDirectionTable() As Vector.sVector() Dim direction(640 * 480) As Vector.sVector Dim x, y As Integer For y = 0 To 479 For x = 0 To 639 direction(x + y * 640).x = x - 320 direction(x + y * 640).y = y - 240 direction(x + y * 640).z = 255 '58 + 0.40000000000000002 * Math.Sqrt((x - 320) * (x - 320) + (y - 240) * (y - 240)) ' fisheye Vector.VectorNormalize(direction(x + y * 640)) Next Next Return direction End Function Public Shared Sub TraceScene(ByRef cam As Camera.cCamera, ByVal prims() As Primitive.sPrimitive, ByVal numPrimitives As Integer, ByVal lightSources() As LightSource, ByVal numLightSources As Integer, ByVal buffer As Bitmap, ByVal directionTable() As Vector.sVector) ' setup view rays Dim primaryRay As Ray.sRay primaryRay.origin.x = 0 primaryRay.origin.y = 0 primaryRay.origin.z = -570 Dim xDiff As Integer = 80 ' equal to 1/2 of the vertical screen size Dim yDiff As Integer = 60 Dim x, y As Integer For y = 240 - yDiff To 240 + yDiff For x = 320 - xDiff To 319 + xDiff primaryRay.direction = directionTable(x + (y << 9) + (y << 7)) ' implimenting the direction table added some fps @ 240x180.... primaryRay = Camera.CalculateCameraRay(cam, x, y, directionTable) Dim ccolor As ColorFloat = TraceRay(-1, primaryRay, prims, numPrimitives, lightSources, numLightSources, 0) If ccolor.r > 255 Then ccolor.r = 255 If ccolor.g > 255 Then ccolor.g = 255 If ccolor.b > 255 Then ccolor.b = 255 buffer.SetPixel(x, y, Color.FromArgb(ccolor.r, ccolor.g, ccolor.b)) Next Next End Sub Public Shared Function TraceRay(ByVal ignorenum As Integer, ByVal pray As Ray.sRay, ByVal prims() As Primitive.sPrimitive, ByVal numPrimitives As Integer, ByVal lightsources() As LightSource, ByVal numLightsources As Integer, ByVal depth As Integer) As ColorFloat Dim returnColor As ColorFloat If depth > 5 Then ' prevent infinite reflection returnColor.r = 0 returnColor.g = 0 returnColor.b = 0 Return returnColor End If Dim closestIntersectionDistance As Double = 1000000 ' an impossibly large value Dim closestIntersectedPrimitiveNum As Integer = -1 Dim currResult As Ray.TraceResult Dim currPrimitiveNum As Integer For currPrimitiveNum = 0 To numPrimitives ' cycle through all of the spheres to find the closest interesction If currPrimitiveNum <> ignorenum Then currResult = Primitive.IntersectPrimitive(prims(currPrimitiveNum), pray) If currResult.hit Then If currResult.distance < closestIntersectionDistance Then closestIntersectionDistance = currResult.distance closestIntersectedPrimitiveNum = currPrimitiveNum End If End If End If Next If closestIntersectedPrimitiveNum = -1 Then ' nothing was intersected returnColor.r = 0 returnColor.g = 0 returnColor.b = 0 Else returnColor = Shader.Shade(prims(closestIntersectedPrimitiveNum), _ closestIntersectedPrimitiveNum, _ pray, _ closestIntersectionDistance, _ lightsources, numLightsources, _ prims, _ numPrimitives, _ depth) End If Return returnColor End Function Public Shared Function IsShadowed(ByVal currPrimitiveNum As Integer, _ ByVal raytolight As Ray.sRay, _ ByVal distanceToLight As Double, _ ByVal prims() As Primitive.sPrimitive, _ ByVal numPrimitives As Integer) As Boolean Dim i As Integer Dim tr As Ray.TraceResult tr.hit = False ' check every other sphere For i = 0 To numPrimitives If i <> currPrimitiveNum Then ' dont self-shadow Select Case prims(i).type Case Primitive.PrimitiveType.SPHERE_TYPE tr = Sphere.IntersectSphere(prims(i).sphereProperties, raytolight) Case Primitive.PrimitiveType.PLANE_TYPE tr = Plane.IntersectPlane(prims(i).planeProperties, raytolight) Case Primitive.PrimitiveType.CYLINDER_TYPE tr = Cylinder.IntersectCylinder(prims(i).cylinderProperties, raytolight) Case Primitive.PrimitiveType.CYLINDER_TYPE tr = Triangle.IntersectTriangle(prims(i).triangleProperties, raytolight) End Select If tr.hit And tr.distance < distanceToLight Then Return True End If Next Return False End Function End Class Public Class Shader Public Shared Function CalculateIntersection(ByVal pray As Ray.sRay, ByVal distance As Double) As Vector.sVector Dim intersection As Vector.sVector ' calculate the location of the intersection between the primitive and the ray intersection.x = pray.origin.x + distance * pray.direction.x intersection.y = pray.origin.y + distance * pray.direction.y intersection.z = pray.origin.z + distance * pray.direction.z Return intersection End Function Public Shared Function CalculateLightRay(ByVal lightLoc As Vector.sVector, ByVal intersection As Vector.sVector, ByRef rayToLight As Ray.sRay) As Double ' puts the resulting vector in lightDir Dim lightDir As Vector.sVector = Vector.VectorSub(lightLoc, intersection) ' because we need the distance to the light for the shadow calculations, we will normalize lightDir manually Dim distanceToLight As Double = Math.Sqrt((lightDir.x * lightDir.x) + (lightDir.y * lightDir.y) + (lightDir.z * lightDir.z)) Dim lightDirMagnitudeReciprocal As Double = 1 / distanceToLight lightDir.x *= lightDirMagnitudeReciprocal lightDir.y *= lightDirMagnitudeReciprocal lightDir.z *= lightDirMagnitudeReciprocal rayToLight.origin = intersection rayToLight.direction = lightDir Return distanceToLight End Function Public Shared Function CalculateLightingCoef(ByVal isShadowed As Boolean, ByVal directionToLight As Vector.sVector, ByVal normal As Vector.sVector) As Double If isShadowed Then ' no light reaches the intersection Return 0 Else ' only calculate how much light reaches the intersection if it is not in shadow Dim lightCoef As Double = Vector.VectorDot(directionToLight, normal) If lightCoef < 0 Then lightCoef = 0 Return lightCoef End If End Function Public Shared Function CalculateReflection(ByVal pray As Ray.sRay, ByVal intersection As Vector.sVector, _ ByVal normal As Vector.sVector, ByVal currPrimitiveNum As Integer, ByVal prims() As Primitive.sPrimitive, _ ByVal numPrimitives As Integer, ByVal lightsources() As LightSource, ByVal numLightSources As Integer, _ ByVal depth As Integer) As ColorFloat ' R = I - 2(N.I)*N Dim reflectedRay As Ray.sRay Dim nDotI As Double = 2 * ((normal.x * pray.direction.x) + (normal.y * pray.direction.y) + (normal.z * pray.direction.z)) reflectedRay.direction.x = pray.direction.x - (nDotI * normal.x) reflectedRay.direction.y = pray.direction.y - (nDotI * normal.y) reflectedRay.direction.z = pray.direction.z - (nDotI * normal.z) reflectedRay.origin = intersection Return Tracer.TraceRay(currPrimitiveNum, reflectedRay, prims, numPrimitives, lightsources, numLightSources, depth + 1) End Function Public Shared Function Shade(ByRef prim As Primitive.sPrimitive, _ ByVal currPrimitiveNum As Integer, _ ByVal pray As Ray.sRay, _ ByVal distance As Double, _ ByVal lightSources() As LightSource, ByVal numLightSources As Integer, _ ByVal prims() As Primitive.sPrimitive, _ ByVal numPrimitives As Integer, _ ByVal depth As Integer) As ColorFloat Dim returnColor As ColorFloat returnColor.r = 0 returnColor.g = 0 returnColor.b = 0 Dim intersection As Vector.sVector = CalculateIntersection(pray, distance) Dim normal As Vector.sVector = Primitive.CalculateNormal(prim, intersection) ' add specular components Dim i As Integer For i = 0 To numLightSources Dim rayToLight As Ray.sRay Dim distanceToLight As Double = CalculateLightRay(lightSources(i).location, intersection, rayToLight) ' sets rayToLight Dim lightCoef As Double = CalculateLightingCoef(Tracer.IsShadowed(currPrimitiveNum, rayToLight, distanceToLight, prims, numPrimitives), rayToLight.direction, normal) returnColor.r += prim.surface.baseColor.r * lightCoef * lightSources(i).c.r ' try checking first if lightCoef is 0... the check will probably be amortized over the returnColor.g += prim.surface.baseColor.g * lightCoef * lightSources(i).c.g ' cost of all these multiplications returnColor.b += prim.surface.baseColor.b * lightCoef * lightSources(i).c.b Next ' add reflective components If prim.surface.reflectivity <> 0 Then Dim reflectedColor As ColorFloat = CalculateReflection(pray, intersection, normal, currPrimitiveNum, prims, numPrimitives, lightSources, numLightSources, depth) returnColor.r += reflectedColor.r * prim.surface.reflectivity returnColor.g += reflectedColor.g * prim.surface.reflectivity returnColor.b += reflectedColor.b * prim.surface.reflectivity End If Return returnColor End Function End Class Public Class Ray Public Structure sRay Dim origin, direction As Vector.sVector End Structure Public Structure TraceResult Dim hit As Boolean Dim distance As Double End Structure End Class Public Class Camera Public Class cCamera Public location, right, up, forward As Vector.sVector ' forward, up and right define the direction of the camera Public rayRotationMatrix As Matrix.Matrix3x3 = New Matrix.Matrix3x3 ' the matrix to multiply a ray's direction to get its rotated direction End Class Public Shared Function CalculateCameraRay(ByVal cam As cCamera, ByVal x As Integer, ByVal y As Integer, ByVal directionTable() As Vector.sVector) As Ray.sRay Dim pray As Ray.sRay pray.origin = cam.location ' maybe optimize this statement pray.direction = directionTable(x + (y << 9) + (y << 7)) pray.direction = Matrix.VectorMultMatrix(pray.direction, cam.rayRotationMatrix) ' rotate the ray Return pray End Function Public Shared Sub SetupCamera(ByRef cam As cCamera) cam.location.x = 0 cam.location.y = 0 cam.location.z = -2700 Vector.VectorSetXYZ(cam.right, 1, 0, 0) Vector.VectorSetXYZ(cam.up, 0, -1, 0) Vector.VectorSetXYZ(cam.forward, 0, 0, 1) cam.rayRotationMatrix = Matrix.IdentityMatrix3x3() ' initally there is no rotation End Sub Public Shared Sub CameraRotate(ByRef cam As cCamera, ByVal thetaRight As Double, ByVal thetaUp As Double, ByVal thetaForward As Double) Dim rotationRight As Matrix.Matrix3x3 = New Matrix.Matrix3x3 Dim rotationUp As Matrix.Matrix3x3 = New Matrix.Matrix3x3 Dim rotationForward As Matrix.Matrix3x3 = New Matrix.Matrix3x3 ' calculate rotation matrices about each axis that defines the camera's direction rotationRight = Matrix.CalculateArbitrayRotationMatrix(cam.right, thetaRight) rotationUp = Matrix.CalculateArbitrayRotationMatrix(cam.up, thetaUp) rotationForward = Matrix.CalculateArbitrayRotationMatrix(cam.forward, thetaForward) Dim combinedRotationMatrix As Matrix.Matrix3x3 ' combinedeRotationMatrix = rotationRight * rotationUp * RotationForward 'combinedRotationMatrix = MatrixMult3x3(MatrixMult3x3(rotationRight, rotationUp), rotationForward); gives a compiler error combinedRotationMatrix = Matrix.MatrixMult3x3(rotationRight, rotationUp) combinedRotationMatrix = Matrix.MatrixMult3x3(combinedRotationMatrix, rotationForward) ' rotate the defining axes by the combined rotation matrix cam.right = Matrix.VectorMultMatrix(cam.right, combinedRotationMatrix) cam.up = Matrix.VectorMultMatrix(cam.up, combinedRotationMatrix) cam.forward = Matrix.VectorMultMatrix(cam.forward, combinedRotationMatrix) ' combine the current ray rotation matrix with the new matrix cam.rayRotationMatrix = Matrix.MatrixMult3x3(cam.rayRotationMatrix, combinedRotationMatrix) End Sub End Class Public Class Primitive Enum PrimitiveType SPHERE_TYPE PLANE_TYPE CYLINDER_TYPE TRIANGLE_TYPE End Enum Public Structure sPrimitive Dim surface As surface Dim type As PrimitiveType Dim planeProperties As Plane.PlaneProperties Dim sphereProperties As Sphere.SphereProperties Dim cylinderProperties As Cylinder.CylinderProperties Dim triangleProperties As Triangle.TriangleProperties End Structure Public Shared Sub AssignPrimitiveType(ByRef prim As sPrimitive, ByVal type As PrimitiveType) Select Case type Case PrimitiveType.SPHERE_TYPE prim.type = PrimitiveType.SPHERE_TYPE prim.sphereProperties = New Sphere.SphereProperties Case PrimitiveType.PLANE_TYPE prim.type = PrimitiveType.PLANE_TYPE prim.planeProperties = New Plane.PlaneProperties Case PrimitiveType.CYLINDER_TYPE prim.type = PrimitiveType.CYLINDER_TYPE prim.cylinderProperties = New Cylinder.CylinderProperties Case PrimitiveType.TRIANGLE_TYPE prim.type = PrimitiveType.TRIANGLE_TYPE prim.triangleProperties = New Triangle.TriangleProperties End Select End Sub Public Shared Sub AssignPrimitiveType(ByRef prim As sPrimitive) Select Case prim.type Case PrimitiveType.SPHERE_TYPE prim.sphereProperties = Nothing Case PrimitiveType.PLANE_TYPE prim.planeProperties = Nothing Case PrimitiveType.CYLINDER_TYPE prim.cylinderProperties = Nothing Case PrimitiveType.TRIANGLE_TYPE prim.triangleProperties = Nothing End Select End Sub Public Shared Function IntersectPrimitive(ByRef prim As sPrimitive, ByRef rray As Ray.sRay) As Ray.TraceResult Select Case prim.type Case PrimitiveType.SPHERE_TYPE Return Sphere.IntersectSphere(prim.sphereProperties, rray) Case PrimitiveType.PLANE_TYPE Return Plane.IntersectPlane(prim.planeProperties, rray) Case PrimitiveType.CYLINDER_TYPE Return Cylinder.IntersectCylinder(prim.cylinderProperties, rray) Case PrimitiveType.TRIANGLE_TYPE Return Triangle.IntersectTriangle(prim.triangleProperties, rray) End Select End Function Public Shared Function CalculateNormal(ByRef prim As sPrimitive, ByRef intersection As Vector.sVector) As Vector.sVector Select Case prim.type Case PrimitiveType.SPHERE_TYPE Return Sphere.SphereNormal(prim.sphereProperties, intersection) Case PrimitiveType.PLANE_TYPE Return Plane.PlaneNormal(prim.planeProperties) Case PrimitiveType.CYLINDER_TYPE Return Cylinder.CylinderNormal(prim.cylinderProperties, intersection) Case PrimitiveType.TRIANGLE_TYPE Return Triangle.TriangleNormal(prim.triangleProperties) End Select End Function End Class Public Class Vector Public Structure sVector Dim x, y, z As Double End Structure Public Shared Sub VectorSetXYZ(ByRef v As sVector, ByVal x As Double, ByVal y As Double, ByVal z As Double) v.x = x v.y = y v.z = z End Sub Public Shared Function VectorAdd(ByVal a As sVector, ByVal b As sVector) As sVector ' result = a + b Dim result As sVector result.x = a.x + b.x result.y = a.y + b.y result.z = a.z + b.z Return result End Function Public Shared Function VectorSub(ByVal a As sVector, ByVal b As sVector) As sVector ' result = a - b Dim result As sVector result.x = a.x - b.x result.y = a.y - b.y result.z = a.z - b.z Return result End Function Public Shared Function VectorDot(ByVal a As sVector, ByVal b As sVector) As Double Return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) End Function Public Shared Function VectorCross(ByVal a As sVector, ByVal b As sVector) As sVector Dim c As sVector c.x = a.y * b.z - a.z * b.y c.y = a.z * b.x - a.x * b.z c.z = a.x * b.y - a.y * b.x Return c End Function Public Shared Sub VectorNormalize(ByRef v As sVector) Dim scaleFactor As Double = 1 / Math.Sqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z)) v.x *= scaleFactor v.y *= scaleFactor v.z *= scaleFactor End Sub Public Shared Sub Rotate(ByRef v As sVector, ByVal ax As Double, ByVal ay As Double, ByVal az As Double) Dim temp As sVector temp.y = v.y v.y = v.y * Math.Cos(ax) - v.z * Math.Sin(ax) v.z = v.z * Math.Cos(ax) + temp.y * Math.Sin(ax) temp.z = v.z v.z = v.z * Math.Cos(ay) - v.x * Math.Sin(ay) v.x = v.x * Math.Cos(ay) + temp.z * Math.Sin(ay) temp.x = v.x v.x = v.x * Math.Cos(az) - v.y * Math.Sin(az) v.y = v.y * Math.Cos(az) + temp.x * Math.Sin(az) End Sub End Class Public Class Matrix Public Class Matrix3x3 Public elements(,) As Double Sub New() ReDim elements(2, 2) End Sub End Class ' multiples a vector by a 3x3 matrix to return a vector ' the vectors are treated as a 3x1 (meaning it has 3 columns and 1 row) matrix ' [b00 b10 b20] ' [rx ry rz] = [ax ay az] * [b01 b11 b21] ' [b02 b12 b22] Public Shared Function VectorMultMatrix(ByVal a As Vector.sVector, ByVal b As Matrix3x3) As Vector.sVector 'returns a*b. vectors are treated as matrices([x y z]) Dim result As Vector.sVector result.x = a.x * b.elements(0, 0) + a.y * b.elements(0, 1) + a.z * b.elements(0, 2) result.y = a.x * b.elements(1, 0) + a.y * b.elements(1, 1) + a.z * b.elements(1, 2) result.z = a.x * b.elements(2, 0) + a.y * b.elements(2, 1) + a.z * b.elements(2, 2) Return result End Function Public Shared Function MatrixMult3x3(ByVal a As Matrix3x3, ByVal b As Matrix3x3) As Matrix3x3 'returns ab Dim result As Matrix3x3 = New Matrix3x3 Dim i, j As Integer For i = 0 To 2 For j = 0 To 2 result.elements(i, j) = a.elements(0, j) * b.elements(i, 0) + a.elements(i, j) * b.elements(i, 1) + a.elements(2, j) * b.elements(i, 2) Next Next Return result End Function Public Shared Function CalculateArbitrayRotationMatrix(ByVal axis As Vector.sVector, ByVal theta As Double) As Matrix3x3 Dim r As Matrix3x3 = New Matrix3x3 Dim c As Double = Math.Cos(theta), s = Math.Sin(theta), t = 1 - Math.Cos(theta) r.elements(0, 0) = t * axis.x * axis.x + c r.elements(1, 0) = t * axis.x * axis.y - s * axis.z r.elements(2, 0) = t * axis.x * axis.z + s * axis.y r.elements(0, 1) = t * axis.x * axis.y + s * axis.z r.elements(1, 1) = t * axis.y * axis.y + c r.elements(2, 1) = t * axis.y * axis.z - s * axis.x r.elements(0, 2) = t * axis.x * axis.z - s * axis.y r.elements(1, 2) = t * axis.y * axis.z + s * axis.x r.elements(2, 2) = t * axis.z * axis.z + c Return r End Function Public Shared Function IdentityMatrix3x3() As Matrix3x3 Dim i As Matrix3x3 = New Matrix3x3 i.elements(0, 0) = 1 i.elements(1, 0) = 0 i.elements(2, 0) = 0 i.elements(0, 1) = 0 i.elements(1, 1) = 1 i.elements(2, 1) = 0 i.elements(0, 2) = 0 i.elements(1, 2) = 0 i.elements(2, 2) = 1 Return i End Function End Class Public Class Triangle Public Structure TriangleProperties ' to optimize, precalculate normal Dim v1, v2, v3 As Vector.sVector ' vertices End Structure Public Shared Function IntersectTriangle(ByVal tri As TriangleProperties, ByVal pray As Ray.sRay) As Ray.TraceResult Dim tr As Ray.TraceResult Dim u, v As Double Dim edge1, edge2, tvec, pvec, qvec As Vector.sVector Dim det, invDet As Double edge1 = Vector.VectorSub(tri.v2, tri.v1) edge2 = Vector.VectorSub(tri.v3, tri.v1) pvec = Vector.VectorCross(pray.direction, edge2) det = Vector.VectorDot(edge1, pvec) If det > -0.00000099999999999999995 And det < 0.00000099999999999999995 Then tr.hit = False Return tr End If invDet = 1 / det tvec = Vector.VectorSub(pray.origin, tri.v1) u = Vector.VectorDot(tvec, pvec) * invDet If u < 0 Or u > 1 Then tr.hit = False Return tr End If qvec = Vector.VectorCross(tvec, edge1) v = Vector.VectorDot(pray.direction, qvec) * invDet If v < 0 Or (u + v) > 1 Then tr.hit = False Return tr End If tr.distance = Vector.VectorDot(edge2, qvec) * invDet If tr.distance < 0 Then tr.hit = False Return tr End If tr.hit = True Return tr End Function Public Shared Function TriangleNormal(ByVal tr As TriangleProperties) As Vector.sVector Dim edge1 As Vector.sVector = Vector.VectorSub(tr.v2, tr.v1), edge2 = Vector.VectorSub(tr.v3, tr.v1) Dim normal As Vector.sVector = Vector.VectorCross(edge1, edge2) Vector.VectorNormalize(normal) Return normal End Function End Class Public Class Plane Public Structure PlaneProperties Dim normal As Vector.sVector Dim displacement As Double End Structure Public Shared Function PlaneNormal(ByVal pl As PlaneProperties) As Vector.sVector Return pl.normal End Function Public Shared Function IntersectPlane(ByVal pl As PlaneProperties, ByVal pray As Ray.sRay) As Ray.TraceResult Dim tr As Ray.TraceResult Dim t As Double = -(pl.normal.x * pray.origin.x + pl.normal.y * pray.origin.y + pl.normal.z * pray.origin.z + pl.displacement) / _ (pl.normal.x * pray.direction.x + pl.normal.y * pray.direction.y + pl.normal.z * pray.direction.z) If t < 0 Then tr.hit = False Return tr End If tr.hit = True tr.distance = t Return tr End Function End Class Public Class Sphere Public Structure SphereProperties Dim center As Vector.sVector Dim radius As Double End Structure Public Shared Function IntersectSphere(ByVal sp As SphereProperties, ByVal pray As Ray.sRay) As Ray.TraceResult Dim tr As Ray.TraceResult Dim rayToSphereCenter As Vector.sVector = Vector.VectorSub(sp.center, pray.origin) Dim lengthRTSC2 As Double = Vector.VectorDot(rayToSphereCenter, rayToSphereCenter) ' lengthRTSC2 = length of the ray from the ray's origin to the sphere's center squared Dim closestApproach As Double = Vector.VectorDot(rayToSphereCenter, pray.direction) If closestApproach < 0 Then ' "intersection" on säteen takana tr.hit = False Return tr End If ' 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 Dim halfCord2 As Double = (sp.radius * sp.radius) - lengthRTSC2 + (closestApproach * closestApproach) ' sphere.radius * sphere.radius could be precalced, but it might take longer to load it ' than to calculate it If halfCord2 < 0 Then ' the ray misses the sphere tr.hit = False Return tr End If tr.hit = True tr.distance = closestApproach - Math.Sqrt(halfCord2) Return tr End Function Public Shared Function SphereNormal(ByVal sp As SphereProperties, ByVal intersection As Vector.sVector) As Vector.sVector Dim normal As Vector.sVector 'Laske normaali "intersectionin" osoittaamaan pisteeseen Dim oneOverRadius As Double = 1 / sp.radius normal.x = (intersection.x - sp.center.x) * oneOverRadius ' sama kuin ( intersection.x - sphere.center.x ) / sphere.radius normal.y = (intersection.y - sp.center.y) * oneOverRadius normal.z = (intersection.z - sp.center.z) * oneOverRadius Return normal End Function End Class Public Class Cylinder Public Enum eAxis X_INFINITE Y_INFINITE Z_INFINITE End Enum Public Structure CylinderProperties Dim center As Vector.sVector Dim radius As Double Dim axis As Integer End Structure Public Shared Function IntersectCylinder(ByVal cy As CylinderProperties, ByVal pray As Ray.sRay) As Ray.TraceResult Dim tr As Ray.TraceResult Dim a, b, c As Double Select Case cy.axis Case eAxis.X_INFINITE a = pray.direction.y * pray.direction.y + pray.direction.z * pray.direction.z b = 2 * (pray.direction.y * (pray.origin.y - cy.center.y) + _ pray.direction.z * (pray.origin.z - cy.center.z)) c = (pray.origin.y - cy.center.y) * (pray.origin.y - cy.center.y) + _ (pray.origin.z - cy.center.z) * (pray.origin.z - cy.center.z) - cy.radius * cy.radius Case eAxis.Y_INFINITE a = pray.direction.x * pray.direction.x + _ pray.direction.z * pray.direction.z b = 2 * (pray.direction.x * (pray.origin.x - cy.center.x) + _ pray.direction.z * (pray.origin.z - cy.center.z)) c = (pray.origin.x - cy.center.x) * (pray.origin.x - cy.center.x) + _ (pray.origin.z - cy.center.z) * (pray.origin.z - cy.center.z) - cy.radius _ * cy.radius Case eAxis.Z_INFINITE a = pray.direction.x * pray.direction.x + _ pray.direction.y * pray.direction.y b = 2 * (pray.direction.x * (pray.origin.x - cy.center.x) + _ pray.direction.y * (pray.origin.y - cy.center.y)) c = (pray.origin.x - cy.center.x) * (pray.origin.x - cy.center.x) + _ (pray.origin.y - cy.center.y) * (pray.origin.y - cy.center.y) - cy.radius * cy.radius End Select Dim discriminant As Double = b * b - 4 * a * c If discriminant < 0 Then tr.hit = False Return tr End If tr.distance = (-b - Math.Sqrt(discriminant)) / (2 * a) If tr.distance < 0 Then tr.hit = False Return tr End If tr.hit = True Return tr End Function Public Shared Function CylinderNormal(ByVal cy As CylinderProperties, ByVal intersection As Vector.sVector) As Vector.sVector Dim normal As Vector.sVector Dim oneOverRadius As Double = 1 / cy.radius Select Case cy.axis Case eAxis.X_INFINITE normal.x = 0 normal.y = (intersection.y - cy.center.y) * oneOverRadius normal.z = (intersection.z - cy.center.z) * oneOverRadius Case eAxis.Y_INFINITE normal.x = (intersection.x - cy.center.x) * oneOverRadius normal.y = 0 normal.z = (intersection.z - cy.center.z) * oneOverRadius Case eAxis.Z_INFINITE normal.x = (intersection.x - cy.center.x) * oneOverRadius normal.y = (intersection.y - cy.center.y) * oneOverRadius normal.z = 0 End Select Return normal End Function End Class
ei tästä olisi missään saatavilla binarya?
kun vähän kiinnostaisi tämä osa-alue mutta en omista .NET:iä
jne... :/
En saa lähetettyä mitään ftp -palvelimelle(ei ohjelmaa).
Voisiko joku tehdä tästä binaryn?
Ja samalla hieman kommentoida? ;)
Tee exe niin voin kommentoida >:P
exe Löytyy:
http://koti.mbnet.fi/nordta/Tray/
Hieno on, hitaus ei haittaa kun ei ole peli.
Vanhempiin koneisii vaatinee .net Frameworking pohjille.
Sourcen ajo vaatii frmRaytracer määrittelyn aloitus formiksi.
Pieni bugi:
exe jää taustalle, vaikka formin sulkeekin.
Totta se pitäisi varmaan korjata. Tuo Tracing silmukka ei anna lopettaa exeä. Täytyy pistää End -komento Form_Unload metodiin.
Tai pikemminkin Form_Closing
Prkl! Miksi .netillä tehdyt ohjelmatkin tarvii sen frameworkin? :(
Siis .netillä tehdyt exe filut.
Aivan uskomaton!
Olisit voinut mainita millaisella koneella tuo 0.5FPS on 'saavutettu' (lainausmerkit ymmärtänet). Koodi on näköjään melko mallikaasti jäljennetty tuosta alkuperäisestä C++-koodista joka minun mielestäni ei ole paikoittain edes kovin hyvää mutta eikait siinä; tästä voi olla monelle suuri hyöty raytracingin saloja opetellessa ja oppiminenhan se on tärkeintä.
Lähetä ihmeessä koodisi myös tuon lähdesivuston tekijälle niin ehkä se pääsee tuonnekin esille.
No koneen tiedot ovat tuolla vinkissä, mutta sanotaan nyt tässäkin:
Pentium 4 1.8 ghz, 256mb 400mhz RDRAM, 64mb Geforce4 ti4200
pitkä koodi :o
Sooda:
lainaus:
Prkl! Miksi .netillä tehdyt ohjelmatkin tarvii sen frameworkin? :(
.NETillä tehdyt ohjelmat eivät vaadi MITÄÄN MUUTA kuin frameworkin. Ei mitään helkkarin dll juttuja tai mitään.
Ihan siisti.
FPS kyllä törkeän heikko, mutta onneksi kyseessä ei ole peli.
Meitzi kirjoitti:
.NETillä tehdyt ohjelmat eivät vaadi MITÄÄN MUUTA kuin frameworkin. Ei mitään helkkarin dll juttuja tai mitään.
Valitan, mutta se frameworkki sisältää dll-tiedostoja.
Aihe on jo aika vanha, joten et voi enää vastata siihen.