I saw Petr's dice simulation here not long ago. I really liked it. I was inspired and tried to solve it with rigid-body physics to make the cube's movement realistic. Unfortunately, I couldn't do it with classic rigid-body physics (i.e. 1 center point, angular velocity, linear force, etc.) because it all became chaotic when calculating the angles. Instead, I tried with elastic-body physics. All 8 corners of the cube live an independent life. With their own inertia, direction. Each point is connected by an invisible spring. Therefore, if I apply a force to one point of the cube, it affects the entire system, and a real center-of-mass angular velocity is created. It's like poking one corner of a dice with a pencil, and it will move in a straight line, and it will also turn in the process.
OpenGL, with lights, and the cube will cast a shadow on the ground.
No external file is needed.
OpenGL, with lights, and the cube will cast a shadow on the ground.
No external file is needed.
Code: (Select All)
Dim Shared Gl_ena, mon As Long: mon = _NewImage(800, 800 / 16 * 9, 32): Screen mon: _FullScreen , _Smooth: _DisplayOrder _GLRender , _Software: _MouseHide
Dim Shared Start_values
Dim Shared Dice_size: Dice_size = .8
Const pip180 = 3.141592 / 180
Dim Shared Body(20)
ReDim Shared Points(999, 19), conn(999, 9), Conn_c, Points_c
Dim Shared cam(9)
Dim Shared lamp(3) 'light point XYZ,angle
lookspeed = .3
cam(6) = .5 'start zoom
cam(8) = -25 'start pitch
Cls , 0
Color _RGBA32(255, 255, 255, 200), _RGBA32(0, 0, 0, 200)
Print "Looking with Mouse New Roll with SPACE key Zoom with Mousewheel"
Do: _Limit 60
Select Case InKey$
Case " ": Start_values = 0
Case Chr$(27): End
End Select
While _MouseInput
cam(3) = cam(3) + _MouseMovementX * lookspeed
cam(8) = cam(8) + _MouseMovementY * lookspeed '-80,+80
cam(6) = cam(6) - _MouseWheel * .03 'zoom
Wend
cam(8) = Sgn(cam(8)) * _Min(Abs(cam(8)), 89.5)
cam(6) = norm(cam(6))
dis = interpolate(4, 25, cam(6)) * Dice_size
ang1 = -cam(3) * pip180
ang2 = -cam(8) * pip180
cam(0) = Cos(ang2) * Sin(ang1) * dis + Body(0)
cam(1) = Sin(ang2) * dis + Body(1)
cam(2) = Cos(ang2) * Cos(ang1) * dis + Body(2)
cam(1) = _Max(cam(1), .1)
'cam4 kiszamitasa
dx = Body(0) - cam(0)
dy = Body(1) - cam(1)
dz = Body(2) - cam(2)
distXZ = Sqr(dx * dx + dz * dz)
cam(4) = Atn(dy / distXZ) / pip180
'LAMP
lamp(3) = Timer * .1: dis = 400
lamp(0) = Sin(lamp(3)) * dis: lamp(1) = 150: lamp(2) = Cos(lamp(3)) * dis
Gl_ena = 1
'_Display
Loop
Sub movedice
'POINTS array
'0,1,2 : XYZ
'3,4,5 : XYZ vector
'6:active 7:identifier
'8,9,10 :XYZ calculated to maptriangle
'11,12,13 :XYZ moving temporary calculating
'14: 0:FIX 1:MOVING
'15,16,17 2D-X,Y, greyscale
'CONN array
'0:point#1
'1:point#2
'2:distance
'3:active
'4:disX
'5:disY
'6:disZ
If Start_values = 0 Then
Gl_ena = 0
Points_c = 0
Conn_c = 0
Randomize Timer
x = 0
y = 10
z = 0
For t = 0 To 7: l = Points_c + t
Points(l, 0) = ((t And 1) * 2 - 1) * Dice_size / 2 + x
Points(l, 1) = ((t And 2) - 1) * Dice_size / 2 + y
Points(l, 2) = ((t And 4) / 2 - 1) * Dice_size / 2 + z
Points(l, 6) = 1
Points(l, 7) = acc
Points(l, 14) = 1
Next t
Points_c = Points_c + 8
For t1 = 0 To 7
For t2 = 0 To 7
conn_add t1, t2, 1
Next t2, t1
Start_values = 1
'Points(0, 14) = 0
'Points(0, 5) = .5
speed = interpolate(.02, .06, Rnd)
For t = 0 To 7
Points(t, 3) = speed
Next t
Points(0, 3) = speed - Rnd * .008
Points(0, 5) = -(speed - Rnd * .008)
End If
tightness = 1
gravity = .0001 '005
lass = .9995
lass = .9996
power = -.3
ReDim vec(2)
For cyc = 0 To 30
For a = 0 To Points_c - 1: For t = 0 To 2: Points(a, 11 + t) = Points(a, t): Next t
If (Points(a, 14) = 0 Or Points(a, 6) = 0) Then _Continue
'connections vector
vec(0) = 0: vec(1) = 0: vec(2) = 0: vec_c = 0
For t = 0 To Conn_c - 1: If conn(t, 3) = 0 Then _Continue
x = -1: For t2 = 0 To 1: If conn(t, t2) = a Then x = conn(t, t2 Xor 1)
Next t2
If x <> -1 Then
dx = Points(a, 0) - Points(x, 0)
dy = Points(a, 1) - Points(x, 1)
dz = Points(a, 2) - Points(x, 2)
dis = Sqr(dx * dx + dy * dy + dz * dz)
If dis > 0.00001 Then
diff = dis - conn(t, 2) ' REST LENGTH (nem X/Y/Z!)
f = diff * power
nx = dx / dis
ny = dy / dis
nz = dz / dis
vec(0) = vec(0) + nx * f
vec(1) = vec(1) + ny * f
vec(2) = vec(2) + nz * f
End If
vec_c = vec_c + 1
' For av = 0 To 2: disv = points(a, av) - points(x, av): vec(av) = vec(av) + ((Abs(disv) - conn(t, 4 + av))) * Sgn(disv) * power
' Next av: vec_c = vec_c + 1
End If
Next t
For av = 0 To 2: Points(a, 3 + av) = (Points(a, 3 + av) + vec(av) / vec_c) * lass: Next av
For av = 0 To 2: Points(a, 11 + av) = Points(a, av) + Points(a, 3 + av): Next av
'utkozes
If Points(a, 12) < 0 Then
Points(a, 12) = 0
Points(a, 4) = Abs(Points(a, 4)) * .95
Points(a, 3) = Points(a, 3) / 2
Points(a, 5) = Points(a, 5) / 2
Else If cyc = 0 Then Points(a, 4) = Points(a, 4) - gravity
End If
Next a
For a = 0 To Points_c - 1: For t = 0 To 2: Points(a, t) = Points(a, 11 + t): Next t, a
Next cyc
Body(0) = 0: Body(1) = 0: Body(2) = 0 'kozeppont
For t = 0 To 7
Body(0) = Body(0) + Points(t, 0)
Body(1) = Body(1) + Points(t, 1)
Body(2) = Body(2) + Points(t, 2)
Next t
Body(0) = Body(0) / 8
Body(1) = Body(1) / 8
Body(2) = Body(2) / 8
End Sub
Sub conn_add (p1, p2, tightness): If p1 = p2 Then Exit Sub
For t = 0 To Conn_c - 1: If (conn(t, 0) = p1 And conn(t, 1) = p2) Or (conn(t, 0) = p2 And conn(t, 1) = p1) Then Exit Sub
Next t
conn(Conn_c, 0) = p1: conn(Conn_c, 1) = p2
For t = 0 To 2: conn(Conn_c, 4 + t) = (Abs(Points(p1, t) - Points(p2, t))) * tightness: Next t
conn(Conn_c, 2) = dist(conn(Conn_c, 4), conn(Conn_c, 5), conn(Conn_c, 6)): conn(Conn_c, 3) = 1
'For t = 0 To 2: conn(conn_c, 4 + t) = 0: Next t
Conn_c = Conn_c + 1
End Sub
Function dist (a, b, c): dist = Sqr(a * a + b * b + c * c): End Function
Sub _GL
If Gl_ena Then
movedice
_glMatrixMode _GL_PROJECTION
_glLoadIdentity
_gluPerspective 50, _Width(mon) / _Height(mon), .2, 500
_glMatrixMode _GL_MODELVIEW
_glClear _GL_COLOR_BUFFER_BIT Or _GL_DEPTH_BUFFER_BIT
multi = interpolate(1, 5, 1 / 180 * Abs(Dif_Ang(-cam(3), lamp(3) / pip180)))
_glClearColor .2 * multi, .6 * multi, .8 * multi, 1
_glEnable _GL_DEPTH_TEST
_glEnable _GL_LIGHTING
_glEnable _GL_LIGHT0
set_camera1
_glLightfv _GL_LIGHT0, _GL_POSITION, glVec4(lamp(0), lamp(1), lamp(2), 1) 'ha tolem vilagit
multi = .1: _glLightfv _GL_LIGHT0, _GL_AMBIENT, glVec3(multi, multi, multi)
multi = 1: _glLightfv _GL_LIGHT0, _GL_DIFFUSE, glVec3(multi, multi, multi)
draw_field
draw_diceshadow
draw_cube
_glFlush
End If
End Sub
Sub set_camera1: _glLoadIdentity: _glRotatef -cam(4), 1, 0, 0: _glRotatef cam(3), 0, 1, 0: End Sub
Sub set_camera2: set_camera1: _glTranslatef -cam(0), -cam(1), -cam(2): End Sub
Sub draw_field
Static install As Integer, GLlist As Long
If install = 0 Then
field_size = 500
field_res = 140
half_size = field_size / 2
cell_size = field_size / field_res
Dim col(1, 2) As Single
col(0, 0) = 0.82: col(0, 1) = 0.71: col(0, 2) = 0.55 ' RGB1
col(1, 0) = 0.55: col(1, 1) = 0.42: col(1, 2) = 0.26 ' RGB2
GLlist = _glGenLists(1)
_glNewList GLlist, _GL_COMPILE
_glDisable _GL_TEXTURE_2D
For i = 0 To field_res - 1
For j = 0 To field_res - 1
Actcol = Abs((i + j) Mod 2 = 0)
multi = .1: _glMaterialfv _GL_FRONT_AND_BACK, _GL_AMBIENT, glVec4(col(Actcol, 0), col(Actcol, 1), col(Actcol, 2), 1)
multi = 2: _glMaterialfv _GL_FRONT_AND_BACK, _GL_DIFFUSE, glVec4(col(Actcol, 0), col(Actcol, 1), col(Actcol, 2), 1)
x0 = -half_size + i * cell_size
x1 = x0 + cell_size
z0 = -half_size + j * cell_size
z1 = z0 + cell_size
_glBegin _GL_QUADS
_glNormal3f 0, 1, 0
_glVertex3f x0, 0, z0
_glVertex3f x1, 0, z0
_glVertex3f x1, 0, z1
_glVertex3f x0, 0, z1
_glEnd
Next j, i
_glEndList
install = 1
End If
set_camera2
_glCallList GLlist
End Sub
Sub draw_cube
Static install As Integer, GLlist As Long, text(5) As Long
If install = 0 Then
'textures
Dim Dice_bg As Long: Dice_bg = _RGB32(220, 220, 220)
Dim Dice_pt As Long: Dice_pt = _RGB32(30, 30, 30)
size = 600 'kep meret
dis = size * .25 'tavolsag
rad = size * .09 'potty sugara
For t = 0 To 5
pic = _NewImage(size, size, 32)
_Dest pic
Cls , Dice_bg
For ty = 0 To 2: For tx = 0 To 2
If Mid$("....*...." + "..*...*.." + "..*.*.*.." + "*.*...*.*" + "*.*.*.*.*" + "***...***", t * 9 + ty * 3 + tx + 1, 1) = "*" Then
py = size / 2 + (ty - 1) * dis: px = size / 2 + (tx - 1) * dis
Circle (px, py), rad, Dice_pt: Paint (px, py), Dice_pt, Dice_pt
End If
Next tx, ty
text(t) = GenerateGLTexture&(pic): _Dest 0: _FreeImage pic
Next t
install = 1
End If
'draw
set_camera2
_glEnable _GL_TEXTURE_2D
Dim col(2): col(0) = .8: col(1) = .8: col(2) = 1 'light color
multi = .1: _glMaterialfv _GL_FRONT_AND_BACK, _GL_AMBIENT, glVec4(col(0), col(1), col(2), 1)
multi = 2: _glMaterialfv _GL_FRONT_AND_BACK, _GL_DIFFUSE, glVec4(col(0), col(1), col(2), 1)
ReDim p(2) As Integer, Q(2, 2) As Single
cs$ = "2376 4510 2640 6754 7315 3201": ct$ = "031 132": ctx$ = "00101101" ': cn$ = "11 10 00 21 01 20"
_glEnable _GL_NORMALIZE
For t = 0 To 5: sq$ = Mid$(cs$, t * 5 + 1, 4) ' négyszög oldalai
_glBindTexture _GL_TEXTURE_2D, text(t)
For t2 = 0 To 1: tr$ = Mid$(ct$, t2 * 4 + 1, 3) ' 1 háromszög 3 vertexe
For t3 = 0 To 2: Ap = Val(Mid$(sq$, Val(Mid$(tr$, t3 + 1, 1)) + 1, 1))
For t4 = 0 To 2: Q(t3, t4) = Points(Ap, t4)
Next t4, t3
UX = Q(1, 0) - Q(0, 0): UY = Q(1, 1) - Q(0, 1): UZ = Q(1, 2) - Q(0, 2)
VX = Q(2, 0) - Q(0, 0): VY = Q(2, 1) - Q(0, 1): VZ = Q(2, 2) - Q(0, 2)
NormX = UY * VZ - UZ * VY: NormY = UZ * VX - UX * VZ: NormZ = UX * VY - UY * VX 'cross multi
_glBegin _GL_TRIANGLES
For t3 = 0 To 2
Ap = Val(Mid$(tr$, t3 + 1, 1))
_glTexCoord2f Val(Mid$(ctx$, Ap * 2 + 1, 1)), Val(Mid$(ctx$, Ap * 2 + 2, 1))
_glNormal3f NormX, NormY, NormZ
Ap2 = Val(Mid$(sq$, Ap + 1, 1))
_glVertex3f Points(Ap2, 0), Points(Ap2, 1), Points(Ap2, 2)
Next t3
_glEnd
Next t2, t
End Sub
Sub draw_diceshadow
Dim sp(7, 1) As Single ' 8 pont vetítve XZ síkra
Dim t As Integer
Dim x1, y1, z1, x2, y2, z2, t2 As Single
Dim hull(7) As Integer ' konvex hull indexei
Dim hullCount As Integer
'8 point vetulet
l0 = lamp(0) + cam(0): l2 = lamp(2) + cam(2)
For t = 0 To 7
t2 = -lamp(1) / (Points(t, 1) - lamp(1))
sp(t, 0) = l0 + t2 * (Points(t, 0) - l0) ' X vetulet
sp(t, 1) = l2 + t2 * (Points(t, 2) - l2) ' Z vetulet
Next t
'gift-wrapping
hullCount = 0
minX = sp(0, 0): minIdx = 0
For t = 1 To 7: If sp(t, 0) < minX Then minX = sp(t, 0): minIdx = t
Next t
p0 = minIdx
Do
hull(hullCount) = p0
hullCount = hullCount + 1
p1 = -1
For t = 0 To 7
If t <> p0 Then
If p1 = -1 Then
p1 = t
Else
dx1 = sp(p1, 0) - sp(p0, 0)
dz1 = sp(p1, 1) - sp(p0, 1)
dx2 = sp(t, 0) - sp(p0, 0)
dz2 = sp(t, 1) - sp(p0, 1)
If dx1 * dz2 - dz1 * dx2 < 0 Then p1 = t
End If
End If
Next t
p0 = p1
Loop While p0 <> hull(0) And hullCount < 8 ' maximum 8 pont
'--------------------------------------
set_camera2
_glDisable _GL_DEPTH_TEST
_glEnable _GL_BLEND
_glBlendFunc _GL_SRC_ALPHA, _GL_ONE_MINUS_SRC_ALPHA
_glDisable _GL_TEXTURE_2D
_glDisable _GL_LIGHTING
_glColor4f 0, 0, 0, 0.7
_glBegin _GL_TRIANGLE_FAN
_glNormal3f 0, 1, 0
cx = 0: cz = 0
For t = 0 To hullCount - 1
cx = cx + sp(hull(t), 0)
cz = cz + sp(hull(t), 1)
Next t
cx = cx / hullCount: cz = cz / hullCount
_glVertex3f cx, 0, cz
For t = 0 To hullCount - 1: _glVertex3f sp(hull(t), 0), 0, sp(hull(t), 1): Next t
_glVertex3f sp(hull(0), 0), 0, sp(hull(0), 1)
_glEnd
_glEnable _GL_DEPTH_TEST
_glEnable _GL_TEXTURE_2D
_glEnable _GL_LIGHTING
End Sub
Function GenerateGLTexture& (imgHandle)
Dim texID&, level&, w&, h&, tmpImg&, m As _MEM
_glGenTextures 1, _Offset(texID&)
_glBindTexture _GL_TEXTURE_2D, texID&
w& = _Width(imgHandle): h& = _Height(imgHandle)
tmpImg& = _CopyImage(imgHandle, 32) ' 32-bites másolat
level& = 0
Do
m = _MemImage(tmpImg&)
_glTexImage2D _GL_TEXTURE_2D, level&, _GL_RGBA, w&, h&, 0, _GL_BGRA_EXT, _GL_UNSIGNED_BYTE, m.OFFSET
_MemFree m
If w& <= 1 Or h& <= 1 Then Exit Do
w& = Int(w& * .5): h& = Int(h& * .5): level& = level& + 1
nextImg& = _NewImage(w&, h&, 32)
_Dest nextImg&
_PutImage (0, 0)-(w& - 1, h& - 1), tmpImg&
_Dest 0
_FreeImage tmpImg&
tmpImg& = nextImg&
Loop
_FreeImage tmpImg&
_glTexParameteri 3553, 10242, 33071 ''_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_WRAP_S, _GL_CLAMP_TO_EDGE
_glTexParameteri 3553, 10243, 33071 ''_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_WRAP_T, _GL_CLAMP_TO_EDGE
_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MIN_FILTER, _GL_LINEAR_MIPMAP_LINEAR
_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MAG_FILTER, _GL_LINEAR
GenerateGLTexture& = texID&
End Function
Function interpolate (a, b, c): interpolate = a + (b - a) * c: End Function
Function norm (x): norm = _Max(_Min(x, 1), 0): End Function
Function glVec3%& (x, y, z): Static internal_vec3(2): internal_vec3(0) = x: internal_vec3(1) = y: internal_vec3(2) = z: glVec3%& = _Offset(internal_vec3()): End Function
Function glVec4%& (x, y, z, w): Static internal_vec4(3): internal_vec4(0) = x: internal_vec4(1) = y: internal_vec4(2) = z: internal_vec4(3) = w: glVec4%& = _Offset(internal_vec4()): End Function
Function Dif_Ang (angle1, angle2): diff = angle2 - angle1: Do While diff > 180: diff = diff - 360: Loop: Do While diff < -180: diff = diff + 360: Loop: Dif_Ang = diff: End Function


