Cloth Simulation

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: Cloth Simulation

BeitragMo, Jul 26, 2010 20:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Von Xaymar angeregt habe ich in der letzten Stunde schnell eine kleine Demo zusammengeworfen, wie eine simple Cloth Simulation mithilfe einfachster Verletintegration aussehen könnte.

Was ist Cloth Simulation? Wenn man das Wörterbuch zur Hand nimmt, sollte man eigentlich schnell draufkommen. Im Prinzip geht es darum, Stoffe realistisch zu simulieren, damit man zum Beispiel der weiblichen Hauptfigur im Spiel möglichst echt die Hüllen fallen lassen kann .... oder so.

Edit: Neue Version!

Screenshots:
user posted image

Mit CLOTH_SIZE = 128 (laaaaaangsam):
user posted image


BlitzBasic: [AUSKLAPPEN]
Const CLOTH_SIZE = 32

Const GRAVITY_X# = 0.0
Const GRAVITY_Y# = -0.001
Const GRAVITY_Z# = 0.0

Const ITERATIONS = 16

Type TCloth
Field Mesh
Field Surface

Field GridSpacing#

Field NodeX#[ CLOTH_SIZE*CLOTH_SIZE ]
Field NodeY#[ CLOTH_SIZE*CLOTH_SIZE ]
Field NodeZ#[ CLOTH_SIZE*CLOTH_SIZE ]

Field OldX# [ CLOTH_SIZE*CLOTH_SIZE ]
Field OldY# [ CLOTH_SIZE*CLOTH_SIZE ]
Field OldZ# [ CLOTH_SIZE*CLOTH_SIZE ]
End Type


Graphics3D 800, 600, 0, 2

;--------------------------- Grafikkram
Local Cam = CreateCamera()
PositionEntity Cam, 1.0, 3.0, -4.0

Local Light = CreateLight( 2 )
PositionEntity Light, 3.0, 4.0, -5.0
LightRange Light, 2.5

Local Cube = CreateCube()
EntityBox Cube, -1.0, -0.2, -1.0, 2.0, 0.6, 2.0
PositionEntity Cube, 1.0, 0.0, 0.0
ScaleEntity Cube, 0.9, 0.2, 0.9
EntityPickMode Cube, 3

Local Cylinder = CreateCylinder( 16 )
ScaleMesh Cylinder, 1.2, 1.2, 1.2
EntityAlpha Cylinder, 0.0
CreateCylinder( 32, True, Cylinder )
ScaleEntity Cylinder, 0.15, 3.0, 0.15
PositionEntity Cylinder, 0.0, 1.0, 0.2
TurnEntity Cylinder, 85.0, 90.0, 0.0
EntityPickMode Cylinder, 2


PointEntity Cam, Cube
;--------------------------- /Grafikkram

Local Cloth.TCloth = CreateCloth( -1.5, 1.5, -2.2, 3.0/CLOTH_SIZE )
EntityColor Cloth\Mesh, 255, 128, 128
EntityAlpha Cloth\Mesh, 0.999 ;Kleiner Hack, um den Z-Buffer für das Mesh auszuhebeln

Local Timer = CreateTimer( 60 )

While Not KeyHit( 1 )
RenderWorld

UpdateCloth( Cloth )

WireFrame MouseDown( 1 )

Local I = CLOTH_SIZE*( CLOTH_SIZE - 1 )/2
Local Pivot = CreatePivot()
PositionEntity Pivot, Cloth\NodeX[ I ], Cloth\NodeY[ I ], Cloth\NodeZ[ I ]
PointEntity Cam, Pivot

Text 0, 0, "Linke Maustaste für Wireframe"

Flip 0
WaitTimer Timer
Wend
End

Function CreateCloth.TCloth( X#, Y#, Z#, GridSpacing# )
Local Cloth.TCloth = New TCloth

Cloth\Mesh = CreateMesh()
Cloth\Surface = CreateSurface( Cloth\Mesh )
Cloth\GridSpacing# = GridSpacing#

EntityFX Cloth\Mesh, 16

For GridZ = 0 To CLOTH_SIZE - 1
For GridX = 0 To CLOTH_SIZE - 1
AddVertex Cloth\Surface, X# + GridX*GridSpacing#, Y#, Z# + GridZ*GridSpacing#, GridX/Float( CLOTH_SIZE ), GridZ/Float( CLOTH_SIZE )

Cloth\NodeX[ GridX + GridZ*CLOTH_SIZE ] = X# + GridX*GridSpacing#
Cloth\NodeY[ GridX + GridZ*CLOTH_SIZE ] = Y#
Cloth\NodeZ[ GridX + GridZ*CLOTH_SIZE ] = Z# + GridZ*GridSpacing#

Cloth\OldX[ GridX + GridZ*CLOTH_SIZE ] = Cloth\NodeX[ GridX + GridZ*CLOTH_SIZE ]
Cloth\OldY[ GridX + GridZ*CLOTH_SIZE ] = Cloth\NodeY[ GridX + GridZ*CLOTH_SIZE ]
Cloth\OldZ[ GridX + GridZ*CLOTH_SIZE ] = Cloth\NodeZ[ GridX + GridZ*CLOTH_SIZE ]
Next
Next

For Z = 0 To CLOTH_SIZE - 2
For X = 0 To CLOTH_SIZE - 2
Local Index = X + Z*CLOTH_SIZE

AddTriangle Cloth\Surface, Index + 1, Index, Index + CLOTH_SIZE
AddTriangle Cloth\Surface, Index + 1, Index + CLOTH_SIZE, Index + CLOTH_SIZE + 1
Next
Next

Return Cloth
End Function

Function UpdateCloth( Cloth.TCloth )
For Z = 0 To CLOTH_SIZE - 1
For X = 0 To CLOTH_SIZE - 1
Local Index = X + Z*CLOTH_SIZE
Local OldX# = Cloth\NodeX[ Index ]
Local OldY# = Cloth\NodeY[ Index ]
Local OldZ# = Cloth\NodeZ[ Index ]

Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ]*1.99 - Cloth\OldX[ Index ]*0.99 + GRAVITY_X#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ]*1.99 - Cloth\OldY[ Index ]*0.99 + GRAVITY_Y#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ]*1.99 - Cloth\OldZ[ Index ]*0.99 + GRAVITY_Z#

Cloth\OldX[ Index ] = OldX#
Cloth\OldY[ Index ] = OldY#
Cloth\OldZ[ Index ] = OldZ#
Next
Next

For I = 1 To ITERATIONS
For Z = 0 To CLOTH_SIZE - 1
For X = 0 To CLOTH_SIZE - 1
Index = X + Z*CLOTH_SIZE

If X Then
Local IndexL = Index - 1

Local Diff1X# = Cloth\NodeX[ Index ] - Cloth\NodeX[ IndexL ]
Local Diff1Y# = Cloth\NodeY[ Index ] - Cloth\NodeY[ IndexL ]
Local Diff1Z# = Cloth\NodeZ[ Index ] - Cloth\NodeZ[ IndexL ]
Local Length1# = Sqr( Diff1X#*Diff1X# + Diff1Y#*Diff1Y# + Diff1Z#*Diff1Z# )

Local LengthD1# = ( Length1# - Cloth\GridSpacing# )*0.5

LengthD1# = LengthD1#/Length1#

Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ] - Diff1X#*LengthD1#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ] - Diff1Y#*LengthD1#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ] - Diff1Z#*LengthD1#
Cloth\NodeX[ IndexL ] = Cloth\NodeX[ IndexL ] + Diff1X#*LengthD1#
Cloth\NodeY[ IndexL ] = Cloth\NodeY[ IndexL ] + Diff1Y#*LengthD1#
Cloth\NodeZ[ IndexL ] = Cloth\NodeZ[ IndexL ] + Diff1Z#*LengthD1#
EndIf


If Z Then
Local IndexD = Index - CLOTH_SIZE

Local Diff2X# = Cloth\NodeX[ Index ] - Cloth\NodeX[ IndexD ]
Local Diff2Y# = Cloth\NodeY[ Index ] - Cloth\NodeY[ IndexD ]
Local Diff2Z# = Cloth\NodeZ[ Index ] - Cloth\NodeZ[ IndexD ]

Local Length2# = Sqr( Diff2X#*Diff2X# + Diff2Y#*Diff2Y# + Diff2Z#*Diff2Z# )

Local LengthD2# = ( Length2# - Cloth\GridSpacing# )*0.5

LengthD2# = LengthD2#/Length2#

Cloth\NodeX[ IndexD ] = Cloth\NodeX[ IndexD ] + Diff2X#*LengthD2#
Cloth\NodeY[ IndexD ] = Cloth\NodeY[ IndexD ] + Diff2Y#*LengthD2#
Cloth\NodeZ[ IndexD ] = Cloth\NodeZ[ IndexD ] + Diff2Z#*LengthD2#
Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ] - Diff2X#*LengthD2#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ] - Diff2Y#*LengthD2#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ] - Diff2Z#*LengthD2#
EndIf

Next
Next
Next

For Z = 0 To CLOTH_SIZE - 1
For X = 0 To CLOTH_SIZE - 1
Index = X + Z*CLOTH_SIZE

Local VX# = Cloth\NodeX[ Index ] - Cloth\OldX[ Index ]
Local VY# = Cloth\NodeY[ Index ] - Cloth\OldY[ Index ]
Local VZ# = Cloth\NodeZ[ Index ] - Cloth\OldZ[ Index ]

If LinePick( Cloth\OldX[ Index ], Cloth\OldY[ Index ], Cloth\OldZ[ Index ], VX#, VY#, VZ# ) Then
Local NX# = PickedNX()
Local NY# = PickedNY()
Local NZ# = PickedNZ()

Local D# = -( PickedX()*NX# + PickedY()*NY# + PickedZ()*NZ# )

Local Dist# = Cloth\NodeX[ Index ]*NX# + Cloth\NodeY[ Index ]*NY# + Cloth\NodeZ[ Index ]*NZ# + D#

Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ] - Dist#*NX#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ] - Dist#*NY#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ] - Dist#*NZ#
EndIf

VertexCoords Cloth\Surface, Index, Cloth\NodeX[ Index ], Cloth\NodeY[ Index ], Cloth\NodeZ[ Index ]
Next
Next

UpdateNormalsEx Cloth\Surface
End Function

Function UpdateNormalsEx( Surface )
TriangleCount = CountTriangles( Surface )
For Triangle = 0 To TriangleCount - 1
V1 = TriangleVertex( Surface, Triangle, 0 )
V2 = TriangleVertex( Surface, Triangle, 1 )
V3 = TriangleVertex( Surface, Triangle, 2 )

VX1# = VertexX( Surface, V2 ) - VertexX( Surface, V1 )
VY1# = VertexY( Surface, V2 ) - VertexY( Surface, V1 )
VZ1# = VertexZ( Surface, V2 ) - VertexZ( Surface, V1 )

VX2# = VertexX( Surface, V3 ) - VertexX( Surface, V1 )
VY2# = VertexY( Surface, V3 ) - VertexY( Surface, V1 )
VZ2# = VertexZ( Surface, V3 ) - VertexZ( Surface, V1 )

VX3# = VY1*VZ2 - VZ1*VY2
VY3# = VZ1*VX2 - VX1*VZ2
VZ3# = VX1*VY2 - VY1*VX2

TFormNormal VX3, VY3, VZ3, 0, 0

VertexNormal Surface, V1, TFormedX(), TFormedY(), TFormedZ()
VertexNormal Surface, V2, TFormedX(), TFormedY(), TFormedZ()
VertexNormal Surface, V3, TFormedX(), TFormedY(), TFormedZ()
Next
End Function
  • Zuletzt bearbeitet von Noobody am Di, Jul 27, 2010 18:16, insgesamt einmal bearbeitet

Blaulicht

BeitragMo, Jul 26, 2010 20:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Wunderschön *tränen in den augen*

Blaulicht
Intel Core i7 860 OC 3,7GHz | 4 GB DDR3 1600MHZ RAM | ATI Radeon HD5850 (1024 MB DDR5 RAM) | Windows 7 Ultimate

Chrise

BeitragMo, Jul 26, 2010 23:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Wow! Brilliant! Und auch der Einfall, besseres Linepick zu nehmen anstatt Kollisionen , fantastisch!
Ich bin gespannt was du noch alles in B3D zaubern wirst in deiner BB-laufbahn Very Happy

lg Chrise
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

darth

BeitragDi, Jul 27, 2010 2:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

funktioniert ziemlich gut und auch mit ordentlicher Geschwindigkeit. Die Idee "LinePick" zu verwenden ist echt interessant. Führt halt dazu, dass man ständig die Kollisionsboxen/-kugeln mitschleppen muss. Zudem kann man so keine Kollision mit anderen Stoffen oder Eigenkollision bauen. Was auch cool wäre, wären Stoffe die auch von Körpern runterrutschen, im Moment kleben sie am Objekt fest wenn sie mal drauf sind.

Weil ich heut Abend etwas Zeit hatte und keine Lust hatte etwas eigenes anzufangen habe ich mal kurz die Kollision umgeschrieben. Ich wollte von dem LinePick weg, damit die Objekte direkt getestet werden. Es hat sich herausgestellt, dass es funktioniert, aber l-a-n-g-s-a-m :/ ich musste die Kugel rausnehmen, das ging noch etwa mit 1FPS.
Ich berechne in jedem Schritt die Normale jedes Dreiecks neu, das könnte man vielleicht einmal vorausberechnen und dann speichern, da BB aber nur konstante Arrays in Types unterstützt hab ich das weggelassen, würde für bewegte Objekte sowieso nicht funktionieren - ist allerdings halt ein etwas nerviger Rechenaufwand.

Damit ich alle Meshes durchgehen kann, habe ich einen Type eingeführt, der das Mesh als Feld beinhaltet, Meshes die nicht in ein Objekt gepackt werden, kommen bei der Kollision nicht zur Geltung.
Ich hatte anfangs das Problem, dass das Tuch "im Objekt" war, ich habe da etwas geschummelt und die Punkte in ein skaliertes System transformiert.
Ein anderes Problem war, dass der Stoff am Objekt klebte, das habe ich auch mit einer kleinen Schummelei korrigiert, wenn die Geschwindigkeit in die selbe Richtung wie die Normale zeigt, wird die Kollision ignoriert, das bedingt allerdings, dass alle Normalen nach aussen zeigen.

So im Endeffekt ist Noobodys Variante wohl besser einsetzbar, vor allem wenn man es nur für statische Objekte oder nur als grafische Verzierung in einer Demo verwenden möchte. Mein Ansatz ist einfach viel zu langsam, könnte aber theoretisch komplexere Objekte als einfache Würfel und Kugeln behandeln (in der Theorie :> habe ich ehrlich gesagt nie getestet..)
Nun denn, hier der Code:

BlitzBasic: [AUSKLAPPEN]
Const CLOTH_SIZE = 32

Const GRAVITY_X# = 0.0
Const GRAVITY_Y# = -0.001
Const GRAVITY_Z# = 0.0

Const ITERATIONS = 10

Type TCloth
Field Mesh
Field Surface

Field GridSpacing#

Field NodeX#[ CLOTH_SIZE*CLOTH_SIZE ]
Field NodeY#[ CLOTH_SIZE*CLOTH_SIZE ]
Field NodeZ#[ CLOTH_SIZE*CLOTH_SIZE ]

Field OldX# [ CLOTH_SIZE*CLOTH_SIZE ]
Field OldY# [ CLOTH_SIZE*CLOTH_SIZE ]
Field OldZ# [ CLOTH_SIZE*CLOTH_SIZE ]
End Type

Type TObject ;für ein for-each
Field Mesh
End Type

Function newObject.TObject(mesh)
Local o.TObject=New TObject

o\Mesh=mesh

Return o
End Function

Graphics3D 800, 600, 0, 2

;--------------------------- Grafikkram
Global Cam = CreateCamera()
PositionEntity Cam, 0.0, 3.0, -4.0

Local Piv=CreatePivot()
EntityParent Cam, Piv

Local Light = CreateLight( 2 )
PositionEntity Light, 3.0, 4.0, -5.0
LightRange Light, 2.5

Local Cube = CreateCube()
EntityBox Cube, -1.0, -0.2, -1.0, 2.0, 0.6, 2.0
ScaleEntity Cube, 0.9, 0.2, 0.9
EntityPickMode Cube, 3
newObject(Cube)

;Local Sphere = CreateSphere( 32 )
;PositionEntity Sphere, 1.0, -1.0, -1.0
;ScaleEntity Sphere, 0.9, 0.9, 0.9
;EntityPickMode Sphere, 1
;newObject(Sphere)

Global Scale=CreatePivot()
ScaleEntity Scale, 0.9, 0.9, 0.9

PointEntity Cam, Cube
;--------------------------- /Grafikkram

Local Cloth.TCloth = CreateCloth( -1.5, 2.0, -2.2, 3.0/CLOTH_SIZE )
EntityColor Cloth\Mesh, 255, 0, 0

Local Timer = CreateTimer( 60 )

While Not KeyHit( 1 )
RenderWorld

TurnEntity Piv, KeyDown(208)-KeyDown(200), KeyDown(203)-KeyDown(205), 0

UpdateCloth( Cloth )

WireFrame MouseDown( 1 )

Text 10, 10, "Linke Maustaste für Wireframe"
Text 10, 30, "Pfeiltasten um Kamera zu drehen"

fpsCount=fpsCount+1
If MilliSecs()-fpsTime>999
fpsCur=fpsCount
fpsCount=0
fpsTime=MilliSecs()
EndIf
Text 10,600-20,"FPS: "+fpsCur

Flip 0
WaitTimer Timer
Wend
End

Function CreateCloth.TCloth( X#, Y#, Z#, GridSpacing# )
Local Cloth.TCloth = New TCloth

Cloth\Mesh = CreateMesh()
Cloth\Surface = CreateSurface( Cloth\Mesh )
Cloth\GridSpacing# = GridSpacing#

EntityFX Cloth\Mesh, 16

For GridZ = 0 To CLOTH_SIZE - 1
For GridX = 0 To CLOTH_SIZE - 1
AddVertex Cloth\Surface, X# + GridX*GridSpacing#, Y#, Z# + GridZ*GridSpacing#, GridX/Float( CLOTH_SIZE ), GridZ/Float( CLOTH_SIZE )

Cloth\NodeX[ GridX + GridZ*CLOTH_SIZE ] = X# + GridX*GridSpacing#
Cloth\NodeY[ GridX + GridZ*CLOTH_SIZE ] = Y#
Cloth\NodeZ[ GridX + GridZ*CLOTH_SIZE ] = Z# + GridZ*GridSpacing#

Cloth\OldX[ GridX + GridZ*CLOTH_SIZE ] = Cloth\NodeX[ GridX + GridZ*CLOTH_SIZE ]
Cloth\OldY[ GridX + GridZ*CLOTH_SIZE ] = Cloth\NodeY[ GridX + GridZ*CLOTH_SIZE ]
Cloth\OldZ[ GridX + GridZ*CLOTH_SIZE ] = Cloth\NodeZ[ GridX + GridZ*CLOTH_SIZE ]
Next
Next

For Z = 0 To CLOTH_SIZE - 2
For X = 0 To CLOTH_SIZE - 2
Local Index = X + Z*CLOTH_SIZE

AddTriangle Cloth\Surface, Index + 1, Index, Index + CLOTH_SIZE
AddTriangle Cloth\Surface, Index + 1, Index + CLOTH_SIZE, Index + CLOTH_SIZE + 1
Next
Next

Return Cloth
End Function

Function UpdateCloth( Cloth.TCloth )
For Z = 0 To CLOTH_SIZE - 1
For X = 0 To CLOTH_SIZE - 1
Local Index = X + Z*CLOTH_SIZE
Local OldX# = Cloth\NodeX[ Index ]
Local OldY# = Cloth\NodeY[ Index ]
Local OldZ# = Cloth\NodeZ[ Index ]

Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ]*1.99 - Cloth\OldX[ Index ]*0.99 + GRAVITY_X#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ]*1.99 - Cloth\OldY[ Index ]*0.99 + GRAVITY_Y#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ]*1.99 - Cloth\OldZ[ Index ]*0.99 + GRAVITY_Z#

Cloth\OldX[ Index ] = OldX#
Cloth\OldY[ Index ] = OldY#
Cloth\OldZ[ Index ] = OldZ#
Next
Next

For I = 1 To ITERATIONS
For Z = 0 To CLOTH_SIZE - 1
For X = 0 To CLOTH_SIZE - 1
Index = X + Z*CLOTH_SIZE

If X Then
Local IndexL = Index - 1

Local Diff1X# = Cloth\NodeX[ Index ] - Cloth\NodeX[ IndexL ]
Local Diff1Y# = Cloth\NodeY[ Index ] - Cloth\NodeY[ IndexL ]
Local Diff1Z# = Cloth\NodeZ[ Index ] - Cloth\NodeZ[ IndexL ]
Local Length1# = Sqr( Diff1X#*Diff1X# + Diff1Y#*Diff1Y# + Diff1Z#*Diff1Z# )

Local LengthD1# = ( Length1# - Cloth\GridSpacing# )*0.5

LengthD1# = LengthD1#/Length1#

Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ] - Diff1X#*LengthD1#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ] - Diff1Y#*LengthD1#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ] - Diff1Z#*LengthD1#
Cloth\NodeX[ IndexL ] = Cloth\NodeX[ IndexL ] + Diff1X#*LengthD1#
Cloth\NodeY[ IndexL ] = Cloth\NodeY[ IndexL ] + Diff1Y#*LengthD1#
Cloth\NodeZ[ IndexL ] = Cloth\NodeZ[ IndexL ] + Diff1Z#*LengthD1#
EndIf


If Z Then
Local IndexD = Index - CLOTH_SIZE

Local Diff2X# = Cloth\NodeX[ Index ] - Cloth\NodeX[ IndexD ]
Local Diff2Y# = Cloth\NodeY[ Index ] - Cloth\NodeY[ IndexD ]
Local Diff2Z# = Cloth\NodeZ[ Index ] - Cloth\NodeZ[ IndexD ]

Local Length2# = Sqr( Diff2X#*Diff2X# + Diff2Y#*Diff2Y# + Diff2Z#*Diff2Z# )

Local LengthD2# = ( Length2# - Cloth\GridSpacing# )*0.5

LengthD2# = LengthD2#/Length2#

Cloth\NodeX[ IndexD ] = Cloth\NodeX[ IndexD ] + Diff2X#*LengthD2#
Cloth\NodeY[ IndexD ] = Cloth\NodeY[ IndexD ] + Diff2Y#*LengthD2#
Cloth\NodeZ[ IndexD ] = Cloth\NodeZ[ IndexD ] + Diff2Z#*LengthD2#
Cloth\NodeX[ Index ] = Cloth\NodeX[ Index ] - Diff2X#*LengthD2#
Cloth\NodeY[ Index ] = Cloth\NodeY[ Index ] - Diff2Y#*LengthD2#
Cloth\NodeZ[ Index ] = Cloth\NodeZ[ Index ] - Diff2Z#*LengthD2#
EndIf

Next
Next
Next

For Z = 0 To CLOTH_SIZE - 1
For X = 0 To CLOTH_SIZE - 1
Index = X + Z*CLOTH_SIZE

Local VX# = Cloth\NodeX[ Index ] - Cloth\OldX[ Index ]
Local VY# = Cloth\NodeY[ Index ] - Cloth\OldY[ Index ]
Local VZ# = Cloth\NodeZ[ Index ] - Cloth\OldZ[ Index ]

;If LinePick( Cloth\OldX[ Index ], Cloth\OldY[ Index ], Cloth\OldZ[ Index ], VX#, VY#, VZ# ) Then
; Cloth\NodeX[ Index ] = PickedX()
; Cloth\NodeY[ Index ] = PickedY()
; Cloth\NodeZ[ Index ] = PickedZ()
;EndIf
If objectPick( Cloth\OldX[ Index ], Cloth\OldY[ Index ], Cloth\OldZ[ Index ], VX#, VY#, VZ# ) Then
Cloth\NodeX[ Index ] = PickX()
Cloth\NodeY[ Index ] = PickY()
Cloth\NodeZ[ Index ] = PickZ()
EndIf

VertexCoords Cloth\Surface, Index, Cloth\NodeX[ Index ], Cloth\NodeY[ Index ], Cloth\NodeZ[ Index ]
Next
Next

UpdateNormalsEx Cloth\Surface

objectPick(0, 0, 0, 0, 0, 0)
End Function

Global oPickX#, oPickY#, oPickZ#
Function PickX#()
Return oPickX
End Function

Function PickY#()
Return oPickY
End Function

Function PickZ#()
Return oPickZ
End Function

Function objectPick(sX#, sY#, sZ#, dX#, dY#, dZ#)
oPickX=0
oPickY=0
oPickZ=0

Local minT#=1
Local pick=False

Local o.TObject
Local surf, vert

Local p1X#, p1Y#, p1Z#, p2X#, p2Y#, p2Z#, p3X#, p3Y#, p3Z#
Local v1X#, v1Y#, v1Z#, v2X#, v2Y#, v2Z#, nX#, nY#, nZ#, nD#
Local t#, pX#, pY#, pZ#

For o=Each TObject
For s=1 To CountSurfaces(o\Mesh)
surf=GetSurface(o\Mesh, s)

For i=0 To CountTriangles(surf)-1
vert=TriangleVertex(surf, i, 0)

p1X=VertexX(surf, vert)
p1Y=VertexY(surf, vert)
p1Z=VertexZ(surf, vert)
TFormPoint p1X, p1Y, p1Z, o\Mesh, Scale
p1X=TFormedX()
p1Y=TFormedY()
p1Z=TFormedZ()

vert=TriangleVertex(surf, i, 1)

p2X=VertexX(surf, vert)
p2Y=VertexY(surf, vert)
p2Z=VertexZ(surf, vert)
TFormPoint p2X, p2Y, p2Z, o\Mesh, Scale
p2X=TFormedX()
p2Y=TFormedY()
p2Z=TFormedZ()

vert=TriangleVertex(surf, i, 2)

p3X=VertexX(surf, vert)
p3Y=VertexY(surf, vert)
p3Z=VertexZ(surf, vert)
TFormPoint p3X, p3Y, p3Z, o\Mesh, Scale
p3X=TFormedX()
p3Y=TFormedY()
p3Z=TFormedZ()

v1X=p2X-p1X
v1Y=p2Y-p1Y
v1Z=p2Z-p1Z

v2X=p3X-p1X
v2Y=p3Y-p1Y
v2Z=p3Z-p1Z

nX=v1Y*v2Z - v1Z*v2Y
nY=v1Z*v2X - v1X*v2Z
nZ=v1X*v2Y - v1Y*v2X
nD=-nX*p1X -nY*p1Y -nZ*p1Z

t=-(sX*nX + sY*nY + sZ*nZ + nD) / (dX*nX + dY*nY + dZ*nZ)

If t>=0 And t<=minT
pX=sX+t*dX
pY=sY+t*dY
pZ=sZ+t*dZ

If pointInTrig3D(pX, pY, pZ, p1X, p1Y, p1Z, p2X, p2Y, p2Z, p3X, p3Y, p3Z)
oPickX=pX
oPickY=pY
oPickZ=pZ

minT=t

pick=True

If t=0
If Sgn(dY)=Sgn(nY)
Return False
Else
Return True
EndIf
EndIf
EndIf
EndIf
Next
Next
Next

Return pick
End Function

Function pointInTrig3D(x#, y#, z#, p1X#, p1Y#, p1Z#, p2X#, p2Y#, p2Z#, p3X#, p3Y#, p3Z#)
Local v0X#, v0Y#, v0Z#
Local v1X#, v1Y#, v1Z#
Local v2X#, v2Y#, v2Z#

v0X=p3X-p1X
v0Y=p3Y-p1Y
v0Z=p3Z-p1Z

v1X=p2X-p1X
v1Y=p2Y-p1Y
v1Z=p2Z-p1Z

v2X=x-p1X
v2Y=y-p1Y
v2Z=z-p1Z

Local dot00#, dot01#, dot02#, dot11#, dot12#

dot00=v0X*v0X + v0Y*v0Y + v0Z*v0Z
dot01=v0X*v1X + v0Y*v1Y + v0Z*v1Z
dot02=v0X*v2X + v0Y*v2Y + v0Z*v2Z
dot11=v1X*v1X + v1Y*v1Y + v1Z*v1Z
dot12=v1X*v2X + v1Y*v2Y + v1Z*v2Z

Local invDenom#=1./(dot00*dot11 - dot01*dot01)
Local u#=(dot11*dot02 - dot01*dot12)*invDenom
Local v#=(dot00*dot12 - dot01*dot02)*invDenom

Return (u>0) And (v>0) And (u+v<1)
End Function

Function pointInTrig3DExt(x#, y#, z#, normX#, normY#, normZ#, normD#, p1X#, p1Y#, p1Z#, p2X#, p2Y#, p2Z#, p3X#, p3Y#, p3Z#)
If Abs(x*normX + y*normY + z*normZ + normD)>0.1
Return False
EndIf

Local v0X#, v0Y#, v0Z#
Local v1X#, v1Y#, v1Z#
Local v2X#, v2Y#, v2Z#

v0X=p3X-p1X
v0Y=p3Y-p1Y
v0Z=p3Z-p1Z

v1X=p2X-p1X
v1Y=p2Y-p1Y
v1Z=p2Z-p1Z

v2X=x-p1X
v2Y=y-p1Y
v2Z=z-p1Z

Local dot00#, dot01#, dot02#, dot11#, dot12#

dot00=v0X*v0X + v0Y*v0Y + v0Z*v0Z
dot01=v0X*v1X + v0Y*v1Y + v0Z*v1Z
dot02=v0X*v2X + v0Y*v2Y + v0Z*v2Z
dot11=v1X*v1X + v1Y*v1Y + v1Z*v1Z
dot12=v1X*v2X + v1Y*v2Y + v1Z*v2Z

Local invDenom#=1./(dot00*dot11 - dot01*dot01)
Local u#=(dot11*dot02 - dot01*dot12)*invDenom
Local v#=(dot00*dot12 - dot01*dot02)*invDenom

Return (u>0) And (v>0) And (u+v<1)
End Function

Function UpdateNormalsEx( Surface )
TriangleCount = CountTriangles( Surface )
For Triangle = 0 To TriangleCount - 1
V1 = TriangleVertex( Surface, Triangle, 0 )
V2 = TriangleVertex( Surface, Triangle, 1 )
V3 = TriangleVertex( Surface, Triangle, 2 )

VX1# = VertexX( Surface, V2 ) - VertexX( Surface, V1 )
VY1# = VertexY( Surface, V2 ) - VertexY( Surface, V1 )
VZ1# = VertexZ( Surface, V2 ) - VertexZ( Surface, V1 )

VX2# = VertexX( Surface, V3 ) - VertexX( Surface, V1 )
VY2# = VertexY( Surface, V3 ) - VertexY( Surface, V1 )
VZ2# = VertexZ( Surface, V3 ) - VertexZ( Surface, V1 )

VX3# = VY1*VZ2 - VZ1*VY2
VY3# = VZ1*VX2 - VX1*VZ2
VZ3# = VX1*VY2 - VY1*VX2

TFormNormal VX3, VY3, VZ3, 0, 0

VertexNormal Surface, V1, TFormedX(), TFormedY(), TFormedZ()
VertexNormal Surface, V2, TFormedX(), TFormedY(), TFormedZ()
VertexNormal Surface, V3, TFormedX(), TFormedY(), TFormedZ()
Next
End Function


Ich hoffe Noobody nimmt es mir nicht übel wenn ich in seinen Codes rumspiele Smile Aber ich wollte nicht von vorne beginnen. Somit verabschiede ich mich,

MfG,
Darth
Diese Signatur ist leer.

Noobody

BeitragDi, Jul 27, 2010 6:53
Antworten mit Zitat
Benutzer-Profile anzeigen
darth hat Folgendes geschrieben:
Führt halt dazu, dass man ständig die Kollisionsboxen/-kugeln mitschleppen muss.

LinePick kann auch direkt gegen Polygone testen. Wenn man Eigenkollision will, kann man ausserdem einfach dem Cloth-Mesh einen EntityPickMode 2 verpassen Wink (man bemerke das ; ), gell Darth?). Im Beispiel hab ich aber EntityBox und EntityRadius verwendet, da es halt ein bisschen schneller ist, wenn man sowieso einen Würfel und eine Kugel vorliegen hat. Daher ist dein Code zwar beeindruckend (in sechs Stunden ein eigenes Linepick raushauen schafft auch nicht jeder), aber im Prinzip nur eine langsamere Version von Linepick.

Dass das Tuch nicht runterrutscht, sondern kleben bleibt, stört mich auch ein wenig, da es rein *theoretisch* von selber runterrutschen müsste. Ich werds mir heute nochmal anschauen.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Chrise

BeitragDi, Jul 27, 2010 11:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Darth!


Auch ein sehr schönes Ergebnis! Aber ein entscheidender UNterschied ist mir doch aufgefallen:
Dreht mal bei beiden Beispielen den Würfel. ich finde da erzielt die Version von Noobody noch etwas bessere Ergebnisse Wink

Ich bin gespannt Wink
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

darth

BeitragDi, Jul 27, 2010 12:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

erstmal: /me slaps Noobody :>

Hehe, dass Linepick auch direkt Polygone picken kann wusste ich gar nicht Very Happy Das macht meinen Code natürlich obsolet (v.a weil das native Linepick schneller sein wird). Naja, is ja auch wurst :>
(Es dauerte nicht 6 Stunden sondern etwa 2 *hust*)

Wenn du das mit dem runterrutschen noch hinkriegst dann ist das ziemlich toll, hopp arbeite!

Ich muss mal kurz Würfel drehen gehn um zu sehen was Chrise meint.
Ach, ich sehs. Wenn ich meinen Würfel um 90 Grad um die X-Achse drehe, dann schiebt sich das Tuch ein Stück in den Würfel rein und klebt an der Seite. Das war eigentlich zu erwarten :/ Meine Abstossung war etwas gepfuscht.
Ich habs bei Noobodys urpsrünglichem Code nicht ausprobiert, aber ich vermute da funktionierts besser (weil Linepick sauberer arbeiten wird..) Ich habe kurz den EntityPickMode 2 auf den Wèrfel gesetzt, und ..öh.. es geht kaputt?

BlitzBasic: [AUSKLAPPEN]
Local Cube = CreateCube()
;EntityBox Cube, -1.0, -0.2, -1.0, 2.0, 0.6, 2.0
ScaleEntity Cube, 0.9, 0.2, 0.9
TurnEntity Cube, 90, 0, 0
EntityPickMode Cube, 2


user posted image

Das Stoffstück fällt zuerst halb durch den Würfel durch :/ Mache ich etwas falsch?
Und dann hat man den Effekt den ich bei mir beschrieben habe, dass das Stoffstück "im Objekt" ist (also auf gleicher Höhe, für t=0).

MfG,
Darth
Diese Signatur ist leer.

ozzi789

BeitragDi, Jul 27, 2010 13:14
Antworten mit Zitat
Benutzer-Profile anzeigen
"habe ich in der letzten Stunde schnell eine kleine Demo zusammengeworfen"
haha, kurz mal schnell Very Happy

genial, danke
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Noobody

BeitragDi, Jul 27, 2010 16:55
Antworten mit Zitat
Benutzer-Profile anzeigen
darth hat Folgendes geschrieben:
Das Stoffstück fällt zuerst halb durch den Würfel durch :/ Mache ich etwas falsch?

Nicht du, sondern scheinbar LinePick. Wenn ich den Würfel um 90.5 Grad drehe statt um exakt 90, geht es wieder. Tatsächlich scheint LinePick den Spezialfall nicht zu beachten, wenn ein Dreieck perfekt senkrecht zur Picklinie steht, da es sich dann weigert, den Pick zu erkennen.

Prophylaktisch als Hinweis: Dass das Tuch auch bei 90.5° scheinbar zerstückelt auf dem Würfel draufliegt, ist kein wirklicher Bug. Mit Linepick werden die einzelnen Punkte perfekt auf die Oberfläche gesetzt, was dann beim Rendern von Tuch und Würfel zum altbekannten Z-Buffer-Fighting führt. Das zu fixen wird schwierig, da ich ja nicht beeinflussen kann, wie gross das Mesh von Linepick aufgefasst wird. Im Beispiel habe ich aus dem Grund die Kollisionsbox/kugel ein wenig grösser gesetzt als das eigentliche Mesh, damit das nicht passiert; bei einem Polygon-Pick aber ist das leider nicht möglich (ausser natürlich ein unsichtbares, leicht grösser skaliertes Mesh, dass für den Pick verwendet wird).
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Noobody

BeitragDi, Jul 27, 2010 18:19
Antworten mit Zitat
Benutzer-Profile anzeigen
*schamloser Doppelpost* Ich hab das Tuch nun zum Rutschen gebracht und die neue Version oben reineditiert.

Das 'Kleben' lag daran, dass ich die einzelnen Punkte direkt an den Schnittpunkt von EntityPick hingesetzt habe. Von dort kommen sie natürlich nicht wieder weg, daher werden sie jetzt einfach in Normalenrichtung aus dem Kollisionsobjekt herausgeschoben, was ja dank Verletintegration einfach die Geschwindigkeit in Normalenrichtung minimiert (was man in einer normalen Kollisionsverarbeitung auch tun sollte *hust*).
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

ozzi789

BeitragMi, Jul 28, 2010 8:57
Antworten mit Zitat
Benutzer-Profile anzeigen
nice! Very Happy

Wenn ich jedoch damit rumspiele sieht es irgendwann so aus
user posted image
wäre es möglich Kollision mit sich selber zu realisieren, sodass es sich nicht zerknüllt (also ineinander)
Dann könnt man so ein schönes Zimmerchen machen, wo man das Tuch mit der Maus bewegt und rumwirft ^_^

mfg
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Noobody

BeitragMi, Jul 28, 2010 19:00
Antworten mit Zitat
Benutzer-Profile anzeigen
ozzi789 hat Folgendes geschrieben:
Wenn ich jedoch damit rumspiele sieht es irgendwann so aus

Stellt sich nur die Frage, wie du denn damit herumgespielt hast? Die Demo bietet ja keine Interaktionsmöglichkeit. Und wenn du den Code abgeändert hast, wäre es vielleicht von Vorteil, wenn du den veränderten Code auch posten würdest, damit ich nicht schon wieder meine Kristallkugel hervorkramen muss Wink

ozzi789 hat Folgendes geschrieben:
wäre es möglich Kollision mit sich selber zu realisieren, sodass es sich nicht zerknüllt (also ineinander)

Möglich schon, aber nur sehr langsam - du kannst ja mal ein EntityPickMode Cloth\Mesh, 2 reinhauen, um die Langsamkeit zu bewundern. Das liegt daran, dass für ein funktionierendes Cloth nach jedem versetzten Knotenpunkt der zugehörige Vertex im Modell versetzt werden muss. Das ist darum schlecht, da B3D dann den Tree, den es für die Pick-Überprüfung benutzt, jedesmal neu bauen muss, wenn das Cloth einen Polygon-Pickmode gesetzt hat. Im Beispiel sind das schon 1024 mal pro Frame, weswegen das Programm dann furchtbar ausgebremst wird.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

ozzi789

BeitragDo, Jul 29, 2010 8:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe es einfach immer wieder aufgezogen, und runter gleiten lassen.
Also an GRAVITY_Y# rumgespielt.

Dachte ich mir, danke Smile
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group