3D Engine Kollision
Wahrscheinlich bekomme ich gleich ein "Besserwisser" von links oder rechts,DarkDragon hat geschrieben:Hab ich ja schon. Sogar für ne genaue Kollision:
http://robsite.de/php/pureboard-archiv/ ... php?t=5160
aber ich habe den Code gerade zum ersten Mal gesehen und hätte nach
kurzem Überfliegen folgenden Optimierungsvorschlag (gerade in Bezug auf
Deinen baldigen Release, DarkDragon
Originalcode:
Code: Alles auswählen
Mag.f = Magnitude(vLineDir\X, vLineDir\Y, vLineDir\Z)
vLineDir\X / Mag
vLineDir\Y / Mag
vLineDir\Z / Mag
Vorschlag:
Code: Alles auswählen
Mag.f = 1/Magnitude(vLineDir\X, vLineDir\Y, vLineDir\Z)
vLineDir\X * Mag
vLineDir\Y * Mag
vLineDir\Z * Mag
-
DarkDragon
- Beiträge: 6291
- Registriert: 29.08.2004 08:37
- Computerausstattung: Hoffentlich bald keine mehr
- Kontaktdaten:
hehe, nein, man kann es für alle 3DSachen nehmen. Nur das grafische ist OpenGLLukas-P hat geschrieben:Is die Procedure nicht für OpenGL?
@traumatic: in meiner sammlung hab ichs verbessert, auch in meiner Engine.
[Edit] achja@Lukas-P: Es gibt eine Edit funktion
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
-
DarkDragon
- Beiträge: 6291
- Registriert: 29.08.2004 08:37
- Computerausstattung: Hoffentlich bald keine mehr
- Kontaktdaten:
Ok, das ist der Code den du brauchst:
Den fügst du am anfang deines Codes ein.
Vorraussetzung für das ganze ist natürlich, dass du weißt wie das Modelformat von Ogre aufgebaut ist oder du erstellst deine Meshes durch DataSection und EndDataSection.
Dann liest du die ganze Sache in einen Array mit der Struktur Point3D. Doch du solltest nicht alles in den selben array speichern. Die Normalen , Texturpositionen und die Dreiecke getrennt
.
Dann gehst du bei jeder Bewegung durch, ob das sich Bewegende Objekt mit den anderen Objekten der Welt kollidiert. Wenn ja, dann bewegst du es einfach nicht. Wenn nein, dann bewegst du es. Eine Box-kollision sollte aber zuerst mal stattfinden.
Hier einmal 2 Prozeduren:
Achja: kann das mal bitte ein Moderator ins richtige Forum verschieben?
Code: Alles auswählen
Global PI.f
PI.f = ATan(1)*4
#WindowWidth = 500
#WindowHeight = 400
#WindowFlags = #PB_Window_TitleBar | #PB_Window_MaximizeGadget | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
Version = 1
Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
If Message = #WM_SIZE
glViewport_(0, 0, WindowWidth(), WindowHeight())
Result = 1
EndIf
ProcedureReturn Result
EndProcedure
Structure Point3D
X.f
Y.f
Z.f
EndStructure
Dim Vec.Point3D(2)
Dim Line3D.Point3D(1)
Procedure.f Magnitude(X.f, Y.f, Z.f)
ProcedureReturn Sqr(X*X + Y*Y + Z*Z)
EndProcedure
Procedure OGLSetCamera(FOV.f, X.f, Y.f, Z.f, AngleX.f, AngleY.f, AngleZ.f, Near.f, Far.f)
If AngleY <= 0
AngleY + 360
ElseIf AngleY > 360
AngleY - 360
EndIf
If AngleX <= 0
AngleX + 360
ElseIf AngleX > 360
AngleX - 360
EndIf
If AngleZ <= 0
AngleZ + 360
ElseIf AngleZ > 360
AngleZ - 360
EndIf
glMatrixMode_(5889)
glLoadIdentity_()
gluPerspective__(FOV, WindowWidth()/WindowHeight(), Near.f, Far.f)
glRotatef_(AngleX, 1.0, 0.0, 0.0)
glRotatef_(AngleY, 0.0, 1.0, 0.0)
glRotatef_(AngleZ, 0.0, 0.0, 1.0)
glTranslatef_(X, Y, Z)
glMatrixMode_(5888)
EndProcedure
Procedure.l Normal(*Pos1.Point3D, *Pos2.Point3D, *Pos3.Point3D, *vNormal.Point3D)
vVector1.Point3D
vVector1\X = *Pos1\X - *Pos2\X
vVector1\Y = *Pos1\Y - *Pos2\Y
vVector1\Z = *Pos1\Z - *Pos2\Z
vVector2.Point3D
vVector2\X = *Pos1\X - *Pos3\X
vVector2\Y = *Pos1\Y - *Pos3\Y
vVector2\Z = *Pos1\Z - *Pos3\Z
*vNormal\X = ((vVector1\Y * vVector2\Z) - (vVector1\Z * vVector2\Y))
*vNormal\Y = ((vVector1\Z * vVector2\X) - (vVector1\X * vVector2\Z))
*vNormal\Z = ((vVector1\X * vVector2\Y) - (vVector1\Y * vVector2\X))
Magnitude.f = Magnitude(*vNormal\X, *vNormal\Y, *vNormal\Z)
*vNormal\X / Magnitude
*vNormal\Y / Magnitude
*vNormal\Z / Magnitude
EndProcedure
Procedure.f PlaneDistance(*vNormal.Point3D, *Point.Point3D)
distance.f = 0
distance = - ((*vNormal\X * *Point\X) + (*vNormal\Y * *Point\Y) + (*vNormal\Z * *Point\Z))
ProcedureReturn distance.f
EndProcedure
Procedure IntersectedPlane(*LPos1.Point3D, *LPos2.Point3D, *TPos1.Point3D, *TPos2.Point3D, *TPos3.Point3D, *vNormal.Point3D)
distance1.f=0
distance2.f=0
originDistance.f = PlaneDistance(*vNormal.Point3D, *TPos1.Point3D)
distance1 = ((*vNormal\X * *LPos1\X) + (*vNormal\Y * *LPos1\Y) + (*vNormal\Z * *LPos1\Z)) + originDistance
distance2 = ((*vNormal\X * *LPos2\X) + (*vNormal\Y * *LPos2\Y) + (*vNormal\Z * *LPos2\Z)) + originDistance
If distance1 * distance2 >= 0
ProcedureReturn 0
Else
ProcedureReturn 1
EndIf
EndProcedure
Procedure.f Dot(*vVector1.Point3D, *vVector2.Point3D)
ProcedureReturn ((*vVector1\x * *vVector2\x) + (*vVector1\y * *vVector2\y) + (*vVector1\z * *vVector2\z))
EndProcedure
Procedure Isnan(Num.f)
If StrF(Num, 6) = "-1.#IND00"
ProcedureReturn 1
EndIf
EndProcedure
Procedure.f AngleBetweenVectors(*Vector1.Point3D, *Vector2.Point3D)
dotProduct.f = Dot(*Vector1, *Vector2)
vectorsMagnitude.f = Magnitude(*Vector1\X, *Vector1\Y, *Vector1\Z) * Magnitude(*Vector2\X, *Vector2\Y, *Vector2\Z)
angle.f = ACos(dotProduct / vectorsMagnitude)
If Isnan(angle.f)
ProcedureReturn 0
Else
ProcedureReturn angle
EndIf
EndProcedure
Procedure InsidePolygon(*vIntersection.Point3D, *TPos1.Point3D, *TPos2.Point3D, *TPos3.Point3D)
vA.Point3D
vB.Point3D
Angle.f = 0.0
MATCH_FACTOR.f = 0.9999
vA\X = *TPos1\X - *vIntersection\X
vA\Y = *TPos1\Y - *vIntersection\Y
vA\Z = *TPos1\Z - *vIntersection\Z
vB\X = *TPos2\X - *vIntersection\X
vB\Y = *TPos2\Y - *vIntersection\Y
vB\Z = *TPos2\Z - *vIntersection\Z
Angle + AngleBetweenVectors(@vA, @vB)
vA\X = *TPos2\X - *vIntersection\X
vA\Y = *TPos2\Y - *vIntersection\Y
vA\Z = *TPos2\Z - *vIntersection\Z
vB\X = *TPos3\X - *vIntersection\X
vB\Y = *TPos3\Y - *vIntersection\Y
vB\Z = *TPos3\Z - *vIntersection\Z
Angle + AngleBetweenVectors(@vA, @vB)
vA\X = *TPos3\X - *vIntersection\X
vA\Y = *TPos3\Y - *vIntersection\Y
vA\Z = *TPos3\Z - *vIntersection\Z
vB\X = *TPos1\X - *vIntersection\X
vB\Y = *TPos1\Y - *vIntersection\Y
vB\Z = *TPos1\Z - *vIntersection\Z
Angle + AngleBetweenVectors(@vA, @vB)
If Angle >= (MATCH_FACTOR * (2.0 * PI))
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure IntersectionPoint(*vNormal.Point3D, *LPos1.Point3D, *LPos2.Point3D, distance.f)
vPoint.Point3D
vLineDir.Point3D
Numerator.f = 0.0
Denominator.f = 0.0
dist.f = 0.0
vLineDir\X = *LPos2\X - *LPos1\X
vLineDir\Y = *LPos2\Y - *LPos1\Y
vLineDir\Z = *LPos2\Z - *LPos1\Z
Mag.f = 1/Magnitude(vLineDir\X, vLineDir\Y, vLineDir\Z)
vLineDir\X * Mag
vLineDir\Y * Mag
vLineDir\Z * Mag
Numerator = - (*vNormal\X * *LPos1\X + *vNormal\Y * *LPos1\Y + *vNormal\Z * *LPos1\Z + distance)
Denominator = Dot(*vNormal, @vLineDir)
If Denominator = 0.0
ProcedureReturn *LPos1
EndIf
dist = Numerator / Denominator
vPoint\X = (*LPos1\X + (vLineDir\X * dist))
vPoint\Y = (*LPos1\Y + (vLineDir\y * dist))
vPoint\Z = (*LPos1\Z + (vLineDir\z * dist))
ProcedureReturn @vPoint
EndProcedure
Procedure IntersectedPolygon(*TPos1.Point3D, *TPos2.Point3D, *TPos3.Point3D, *LPos1.Point3D, *LPos2.Point3D, *vNormal.Point3D)
originDistance.f = PlaneDistance(*vNormal.Point3D, *TPos1.Point3D)
If IntersectedPlane(*LPos1.Point3D, *LPos2.Point3D, *TPos1.Point3D, *TPos2.Point3D, *TPos3.Point3D, *vNormal.Point3D) = 0
ProcedureReturn 0
EndIf
CopyMemory(IntersectionPoint(*vNormal.Point3D, *LPos1.Point3D, *LPos2.Point3D, originDistance), @vIntersection.Point3D, SizeOf(Point3D))
If InsidePolygon(@vIntersection, *TPos1.Point3D, *TPos2.Point3D, *TPos3.Point3D) = 1
ProcedureReturn 1
EndIf
EndProcedure Vorraussetzung für das ganze ist natürlich, dass du weißt wie das Modelformat von Ogre aufgebaut ist oder du erstellst deine Meshes durch DataSection und EndDataSection.
Dann liest du die ganze Sache in einen Array mit der Struktur Point3D. Doch du solltest nicht alles in den selben array speichern. Die Normalen , Texturpositionen und die Dreiecke getrennt
Dann gehst du bei jeder Bewegung durch, ob das sich Bewegende Objekt mit den anderen Objekten der Welt kollidiert. Wenn ja, dann bewegst du es einfach nicht. Wenn nein, dann bewegst du es. Eine Box-kollision sollte aber zuerst mal stattfinden.
Hier einmal 2 Prozeduren:
Code: Alles auswählen
Procedure SphereCollision(X1.f, Y1.f, Z1.f, Size1.f, X2.f, Y2.f, Z2.f, Size2.f) ;Size ist der Radius
If Sqr((X1-X2)*(X1-X2)+(Y1-Y2)*(Y1-Y2)+(Z1-Z2)*(Z1-Z2)) <= Size1+Size2
Result = 1
Else
Result = 0
EndIf
ProcedureReturn Result
EndProcedure
Procedure BoxCollision(X1.f, Y1.f, Z1.f, SizeX1.f, SizeY1.f, SizeZ1.f, X2.f, Y2.f, Z2.f, SizeX2.f, SizeY2.f, SizeZ2.f) ;Size ist der Radius der einzelnen Objekte
If Sqr((X1-X2)*(X1-X2)) <= SizeX1+SizeX2 And Sqr((Y1-Y2)*(Y1-Y2)) <= SizeY1+SizeY2 And Sqr((Z1-Z2)*(Z1-Z2)) <= SizeZ1+SizeZ2
Result = 1
Else
Result = 0
EndIf
ProcedureReturn Result
EndProcedure
Debug "Sollte 1 ergeben:"
Debug "Sphere: "+Str(SphereCollision(0.0, 0.0, 0.0, 1.5, 0.0, 0.0, 2.0, 1.0))
Debug "Box: "+Str(BoxCollision(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.5, 1.0, 1.0))
Debug "Sollte 0 ergeben:"
Debug "Sphere: "+Str(SphereCollision(0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 2.0, 1.0))
Debug "Box: "+Str(BoxCollision(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.5, 1.0, 1.0)) Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.