#### Archived

This topic is now archived and is closed to further replies.

# Problem with very basic collision detection.

This topic is 5207 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello friends. I been trying to figure out how to add working collision detection to my code for a while now. I been researching many web sites and finaly understood how to do it. But when I try to implement the code, it does not seem to be working correctly. What I have is just a very simple DirectX app written in VB.NET. It only has 1 triangle, and 1 point. I want to detect when the point intersects the plane of my triangle. (I am not worrying about wether the point is IN the triangle or not yet.) So I have a point. With a location of (-1.0, 0.0, 0.0) And a triangle. With points A(1.0F, 0.0F, 1.0F) B(1.0F, 1.0F, 0.0F) C(1.0F, 0.0F, -1.0F) As I move the point with my arrow keys, I perform the following to detect if there was a collision with the point and the plane of the triangle. ' Get 2 edges of the triangle U.X = B.X - A.X U.Y = B.Y - A.Y U.Z = B.Z - A.Z V.X = C.X - A.X V.Y = C.Y - A.Y V.Z = C.Z - A.Z ' Calculate the normal of the triangle N = Vector3.Cross(U, V) ' Normalize the normal so it has a length of 1 L = Sqrt((N.X ^ 2) + (N.Y ^ 2) + (N.Z ^ 2)) N.X = N.X / L N.Y = N.Y / L N.Z = N.Z / L ' Get the determinant of the triangles plane equation d = Vector3.Dot(N, A) ' Calculate distance between the plane and the test point Distance = Vector3.Dot(point, N) - d At this point I simply check if the sign of Distance changes. If it goes from positive to negative that means the point passed through the plane of my triangle. If Distance is 0, then the point is exactly lying on the plane. The problem is that the point is going from positive to negative too early. When I move the point closer to the polygon, the distance value lowers as it should, but it reaches zero before it ever reaches the polygon. (Zero should mean the point is directly on the plane) Even more interesting is that if the point starts off at (0.0, 0.0, 0.0) then the collision on the plane works perfect. As soon as the point hits the plane, the distance value is 0, and becomes negative as it passes through. If anyone has any idea why this is happening I would greatly appreciate the help! Here is the complete source code. Lanauge is Visual Basic.NET, API is Managed DirectX 9.0b (Note: Im using the basic code from microsofts MatricesTutorial and changed it to have only the functionality that I need.)
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D
Imports Direct3D = Microsoft.DirectX.Direct3D
Imports System.Math

Namespace MatricesTutorial
Public Class Matrices
Inherits Form
Private device As device = Nothing
Private vbTri As VertexBuffer = Nothing
Private vbLine As VertexBuffer = Nothing
Private presentParams As New PresentParameters()
Private pause As Boolean = False
Private sngX As Single = 0.0F
Private camSngZ As Single = -5.0F
Private camLookVector As Vector3
Private camLocationVector As Vector3
Private info As Microsoft.DirectX.Direct3D.Font
Private U, V As Vector3     ' 2 vectors representing the edges of my triangle
Private A, B, C As Vector3  ' 3 points on my triangle
Private N As Vector3        ' vector representing the triangle Normal (a vector perpendicular to the plane of the triangle)
Private L As Double         ' Length/Magnitude of the normal vector
Private d As Double         ' plane determinant
Private cosAlpha2 As Double
Private point As Vector3
Private Distance As Double  ' distance between test point and triangle's plane

' Variables for determining view position
Private position As Vector3
Private velocity As Vector3
Private yaw As Single = 0.0F
Private yawVelocity As Single = 0.0F
Private pitch As Single = 0.0F
Private pitchVelocity As Single = 0.0F
Private viewMatrix As Matrix
Private orientationMatrix As Matrix

Public Sub New()
Me.ClientSize = New System.Drawing.Size(400, 300)
Me.Text = "Collision"
camLocationVector = New Vector3(0.0F, 0.0F, -1.0F)
camLookVector = New Vector3(0.0F, 0.0F, 0.0F)

position = New Vector3(0.0F, 3.0F, -4.0F)
velocity = New Vector3(0.0F, 0.0F, 0.0F)
yaw = 0.03F
yawVelocity = 0.0F
pitch = 0.5F
pitchVelocity = 0.0F
viewMatrix = Matrix.Translation(0.0F, 0.0F, 10.0F)
orientationMatrix = Matrix.Translation(0.0F, 0.0F, 0.0F)
camLookVector.Z += 0.1F
camLookVector.X += 0.1F
camLocationVector.Z += camLocationVector.Z
camLocationVector.X += camLookVector.X
camLookVector.Z += 0.1F
camLookVector.X += 0.1F
camLocationVector.Z += camLocationVector.Z
camLocationVector.X += camLookVector.X
End Sub

Public Function InitializeGraphics() As Boolean
Try
presentParams.Windowed = True
presentParams.BackBufferFormat = Format.X8R8G8B8
presentParams.AutoDepthStencilFormat = DepthFormat.D16
presentParams.EnableAutoDepthStencil = True
device = New Device(0, DeviceType.Hardware, Me, CreateFlags.SoftwareVertexProcessing, presentParams)
Me.OnCreateDevice(device, Nothing)
Me.OnResetDevice(device, Nothing)
pause = False

Return True
Catch e As DirectXException
Return False
End Try
End Function 'InitializeGraphics

Public Sub OnCreateDevice(ByVal sender As Object, ByVal e As EventArgs)
Dim dev As Device = CType(sender, Device)
vbTri = New VertexBuffer(GetType(CustomVertex.PositionColored), 3, dev, 0, CustomVertex.PositionColored.Format, Pool.Default)
Me.OnCreateTriangle(vbTri, Nothing)
vbLine = New VertexBuffer(GetType(CustomVertex.PositionColored), 2, dev, 0, CustomVertex.PositionColored.Format, Pool.Default)
End Sub 'OnCreateDevice

Public Sub OnResetDevice(ByVal sender As Object, ByVal e As EventArgs)
Dim dev As Device = CType(sender, Device)
dev.RenderState.CullMode = Cull.None
dev.RenderState.Lighting = False
dev.RenderState.ZBufferEnable = True
info = New Microsoft.DirectX.Direct3D.Font(device, New System.Drawing.Font("Arial", 11, FontStyle.Bold))
End Sub 'OnResetDevice

Public Sub OnCreateTriangle(ByVal sender As Object, ByVal e As EventArgs)
Dim vb As VertexBuffer = CType(sender, VertexBuffer)
Dim verts As CustomVertex.PositionColored() = CType(vb.Lock(0, 0), CustomVertex.PositionColored())
verts(0).X = 1.0F
verts(0).Y = 0.0F
verts(0).Z = 1.0F
verts(0).Color = System.Drawing.Color.Green.ToArgb()
verts(1).X = 1.0F
verts(1).Y = 1.0F
verts(1).Z = 0.0F
verts(1).Color = System.Drawing.Color.Red.ToArgb()
verts(2).X = 1.0F
verts(2).Y = 0.0F
verts(2).Z = -1.0F
verts(2).Color = System.Drawing.Color.Blue.ToArgb()
vb.Unlock()
A.X = 1.0F
A.Y = 0.0F
A.Z = 1.0F
B.X = 1.0F
B.Y = 1.0F
B.Z = 0.0F
C.X = 1.0F
C.Y = 0.0F
C.Z = -1.0F
End Sub 'OnCreateTriangle

Public Sub OnCreateLine(ByVal sender As Object, ByVal e As EventArgs)
Dim vb As VertexBuffer = CType(sender, VertexBuffer)
Dim verts As CustomVertex.PositionColored() = CType(vb.Lock(0, 0), CustomVertex.PositionColored())

verts(0).X = -1.01F
verts(0).Y = 0.1F
verts(0).Z = 0.0F
verts(0).Color = System.Drawing.Color.White.ToArgb()
verts(1).X = -1.0F
verts(1).Y = 0.1F
verts(1).Z = 0.0F
verts(1).Color = System.Drawing.Color.White.ToArgb()
vb.Unlock()
point.X = -1.0F
point.Y = 0.1F
point.Z = 0.0F
End Sub 'OnCreateLine

Private Sub Render()
If device Is Nothing Then
Return
End If
If pause Then
Return
End If
device.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, System.Drawing.Color.Black, 1.0F, 0)
device.BeginScene()

SetupMatrices()

device.Transform.World = Matrix.Translation(0.0F, 0.0F, 0.0F)
device.SetStreamSource(0, vbTri, 0)
device.VertexFormat = CustomVertex.PositionColored.Format
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1)

device.Transform.World = Matrix.Translation(point.X, point.Y, point.Z)
device.SetStreamSource(0, vbLine, 0)
device.VertexFormat = CustomVertex.PositionColored.Format
device.DrawPrimitives(PrimitiveType.LineList, 0, 1)
info.DrawText(Nothing, "U: " & U.X & U.Y & U.Z & " V: " & V.X & V.Y & V.Z, New System.Drawing.Rectangle(5, 5, 400, 15), DrawTextFormat.Left Or DrawTextFormat.Top, Drawing.Color.FromArgb(255, 255, 255, 255))
info.DrawText(Nothing, "Normal: " & N.X & N.Y & N.Z, New System.Drawing.Rectangle(5, 20, 400, 15), DrawTextFormat.Left Or DrawTextFormat.Top, Drawing.Color.FromArgb(255, 255, 255, 255))
info.DrawText(Nothing, "Length: " & L, New System.Drawing.Rectangle(5, 35, 400, 15), DrawTextFormat.Left Or DrawTextFormat.Top, Drawing.Color.FromArgb(255, 255, 255, 255))
info.DrawText(Nothing, "Normalized Normal: " & N.X & N.Y & N.Z, New System.Drawing.Rectangle(5, 50, 400, 15), DrawTextFormat.Left Or DrawTextFormat.Top, Drawing.Color.FromArgb(255, 255, 255, 255))
info.DrawText(Nothing, "d: " & d, New System.Drawing.Rectangle(5, 65, 400, 15), DrawTextFormat.Left Or DrawTextFormat.Top, Drawing.Color.FromArgb(255, 255, 255, 255))
info.DrawText(Nothing, "Distance: " & Distance, New System.Drawing.Rectangle(5, 80, 400, 15), DrawTextFormat.Left Or DrawTextFormat.Top, Drawing.Color.FromArgb(255, 255, 255, 255))

device.EndScene()
device.Present()
End Sub 'Render

Private Sub CheckCollision()
' Get 2 edges of the triangle
U.X = B.X - A.X
U.Y = B.Y - A.Y
U.Z = B.Z - A.Z
V.X = C.X - A.X
V.Y = C.Y - A.Y
V.Z = C.Z - A.Z
' Calculate the normal of the triangle
N = Vector3.Cross(U, V)
' Normalize the normal so it has a length of 1
L = Sqrt((N.X ^ 2) + (N.Y ^ 2) + (N.Z ^ 2))
N.X = N.X / L
N.Y = N.Y / L
N.Z = N.Z / L
' Get the derterminant of the triangles plane equation
d = Vector3.Dot(N, B)
' Calculate distance between the plane and the test point
Distance = Vector3.Dot(point, N) - d
End Sub

Private Sub SetupMatrices()

Dim iTime As Integer = Environment.TickCount Mod 1000
device.Transform.View = Matrix.LookAtLH(camLocationVector, New Vector3(0.0F, 0.0F, 0.0F), New Vector3(0.0F, 1.0F, 0.0F)) 'camLocationVector, camLookVector,
device.Transform.Projection = Matrix.PerspectiveFovLH(CSng(Math.PI) / 4, 4 / 3, 1.0F, 100.0F)
End Sub 'SetupMatrices

Private Sub window_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
Select Case e.KeyCode
Case Keys.Right
point.X = point.X + 0.02F
CheckCollision()
If Distance < 0 Then
point.X = point.X - 0.02F
End If
Case Keys.Left
point.X = point.X - 0.02F
CheckCollision()
Case Keys.Up
point.Y = point.Y + 0.02F
CheckCollision()
Case Keys.Down
point.Y = point.Y - 0.02F
CheckCollision()
End Select
End Sub
Protected Overrides Sub offPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
CheckCollision()
Me.Render()
End Sub 'OnPaint

Protected Overrides Sub offKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
If Asc(e.KeyChar) = CInt(System.Windows.Forms.Keys.Escape) Then
Me.Close()
End If
End Sub 'OnKeyPress

Protected Overrides Sub offResize(ByVal e As System.EventArgs)
pause = (Me.WindowState = FormWindowState.Minimized Or Not Me.Visible)
End Sub 'OnResize

Shared Sub Main()
Dim frm As New Matrices
If Not frm.InitializeGraphics() Then
MessageBox.Show("Could not initialize Direct3D.")
Return
End If
frm.Show()
frm.Width = frm.Width + 1

While frm.Created
frm.Render()
Application.DoEvents()
End While
End Sub 'Main
End Class
End Namespace

[edited by - EvolvedAnt on March 18, 2004 3:25:08 PM]

##### Share on other sites
don''t see anything wrong in there. what''s your cross product and dot product functions? what the normal looks like?

##### Share on other sites
The DirectX API has a Vector3 class that besides holding an X Y Z value, also contains Static methods called Dot() Cross() and Normalize()

I use these rather than write my own Dot product function since I imagine Microsoft knows how to do it better/faster. So im sure there is nothing wrong with how they are implemented.

From my testing I think the problem involved a difference between testing against model space and world space. I think I may have fixed the problem by creating my point based on the origin in model space, and then testing collisions only on the world coordinates of the point after it went through a world transformation.

I still have some more tests to run but I hope I am right.

• 18
• 11
• 20
• 9
• 52
• ### Forum Statistics

• Total Topics
631397
• Total Posts
2999812
×