Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
3D Rolling Sphere
#1
This is a simulation of a solid ball rolling on an inclined slope.  The physics is straightforward Newtonian gravitation and laws of motion.  The ball rolls as it moves along the slope and this adjusts the rate at which gravitational potential energy is exchanged for kinetic energy.  The rolling in this simulation is done with zero friction loss.
The ball is rolling on a circular path, and it thus oscillates from one side to the other.  The mathematics to generate the acceleration uses the formula for a simple constant slope, but here the ball position is forced onto the curved slope at every point.  This leads to a slight deviation from true energy conservation, and the motion data are reset at each end to keep the ball within stable bounds.  In fact this correction is unnoticeable.
The ball, moving to and fro along the curved path, is displayed in the 3D _MAPTRIANGLE space.  The y- and z- viewing angles are rotated for a more interesting view.
QB64 3D _MAPTRIANGLE is a method which gives excellent 3D simulation - in this case the ball as well as travelling horizontally is actually moving towards and away from the viewer somewhat.  I salute both Mr Newton for his easy-to-use motion equations and the QB64 guru who produced 3D _MAPTRIANGLE, where the programmer does not have to do any of the 3D positional and occluding calculations.
The 3D display mapping is done via two hemispherical surfaces: a near-facing and a far-facing hemisphere, this latter is generally much occluded (but not completely because of the viewing angle).  The far-facing hemisphere is a reversed 'copy' of the forward-facing one.
There is a fair bit of calculation effort going on during the running program, and on my Core i5 laptop the CPU and graphics card have a moderate work-out.
The program comes with the Earth as the default sphere, but there are a few others should the user wish to try.
Unzip the contents into a QB64 sub-folder.

   


.zip   Rolling Sphere.zip (Size: 435.29 KB / Downloads: 24)

Code: (Select All)
'Rolling Ball Simulation 08/10/25 by Magdha QB64 v2.0
'Ball rolls on a semicircular track under gravity
'Motion governed by Newtonian gravity without friction
'The ball rolls as it moves along
'The display is mapped to the 3D _MAPTRIANGLE space

'Constants and arrays
CONST False = 0, True = NOT False
CONST g# = 9.81, R% = 850, deltaT# = 0.02
CONST Uscreen% = 940, Vscreen% = 800, NoPhis%% = 32, NoAlphas%% = 32
CONST BallRad%% = 70, PerspDist% = 600, YDisp% = 150, XDisp% = 80
CONST Alpha! = _PI / (2 * NoAlphas%%), Phi! = 2 * _PI / NoPhis%%, ImageSize% = 271, YAngle! = 0.25, ZAngle! = 0.1
CONST Utrack% = 12, VTrack% = 200, UStart% = -570, TracksNo% = 110
DIM MapTo3D!(NoPhis%%, 2 * NoAlphas%%, 1, 2)

_TITLE "Rolling Ball Esc to Quit"

'Conversion from 2D into 3D _MAPTRIANGLE co-ordinates
FOR N%% = 0 TO NoPhis%%
    FOR M%% = 0 TO NoAlphas%%
        'Where it's from (2D)
        MapTo3D!(N%%, M%%, 0, 0) = ((ImageSize% - 1) / 2) + ((ImageSize% - 1) / 2) * SIN((_PI / 2) - M%% * Alpha!) * COS(N%% * Phi!)
        MapTo3D!(N%%, M%%, 0, 1) = ((ImageSize% - 1) / 2) + ((ImageSize% - 1) / 2) * SIN((_PI / 2) - M%% * Alpha!) * SIN(N%% * Phi!)
        'Where it's going to (3D)
        MapTo3D!(N%%, M%%, 1, 0) = BallRad%% * SIN((_PI / 2) - M%% * Alpha!) * COS(N%% * Phi!)
        MapTo3D!(N%%, M%%, 1, 1) = BallRad%% * SIN((_PI / 2) - M%% * Alpha!) * SIN(N%% * Phi!)
        MapTo3D!(N%%, M%%, 1, 2) = BallRad%% * COS((_PI / 2) - M%% * Alpha!)
    NEXT M%%
NEXT N%%

'Screen Background
TempImage& = _NEWIMAGE(Uscreen%, Vscreen%, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGB32(10, 60, 60)
CLS
FOR UCol% = 0 TO Uscreen% - 1
    FOR VCol% = 0 TO Vscreen% - 1
        PSET (UCol%, VCol%), _RGB(100, INT(180 * UCol% / Uscreen%), INT(180 * VCol% / Vscreen%))
    NEXT VCol%
NEXT UCol%
Background& = MakeHardware&(TempImage&)

'Track Image
TempImage& = _NEWIMAGE(Utrack%, VTrack%, 32) '!!! TBF
_DEST TempImage&
FOR UCol% = 0 TO Utrack% - 1
    FOR VCol% = 0 TO VTrack% - 1
        PSET (UCol%, VCol%), _RGB(255 - INT(30 * (SIN(UCol% * _PI / (2 * Utrack%))) * (VCol% / VTrack%)), 253 - INT(30 * (SIN(UCol% * _PI / (2 * Utrack%))) * (VCol% / VTrack%)), 208 - INT(30 * (SIN(UCol% * _PI / (2 * Utrack%))) * (VCol% / VTrack%)))
    NEXT VCol%
NEXT UCol%
HalfPipe& = MakeHardware&(TempImage&)

'Sphere images:
Football& = _LOADIMAGE("Football clipart.png", 32)
Stoneball& = _LOADIMAGE("Stone Sphere.png", 32)
Ironball& = _LOADIMAGE("Metal Sphere.png", 32)
Whiteball& = _LOADIMAGE("White Ball.png", 32)
Blueball& = _LOADIMAGE("Blue Ball.png", 32)
Earthball& = _LOADIMAGE("Earth.png", 32)
Spotball& = _NEWIMAGE(271, 271, 32) 'Spotball& was used in testing the program
_DEST Spotball&
COLOR _RGB32(255, 255, 255), _RGB32(90, 0, 90)
CLS
CIRCLE (50, 135), 30
PAINT (50, 135)
CIRCLE (135, 50), 20
PAINT (135, 50)
CIRCLE (135, 135), 30
CIRCLE (135, 135), 60
CIRCLE (135, 135), 90
CIRCLE (135, 135), 120
CIRCLE (135, 135), 133

TempImage& = _NEWIMAGE(ImageSize%, ImageSize%, 32)
_DEST TempImage&
'Choose which image you want (Default is Earth):
'_PUTIMAGE , Spotball&
'_PUTIMAGE , Football&
'_PUTIMAGE , Stoneball&
'_PUTIMAGE , Ironball&
'_PUTIMAGE , Whiteball&
'_PUTIMAGE , Blueball&
_PUTIMAGE , Earthball&
SolidSphere& = MakeHardware&(TempImage&)

'Ball Start Position, Velocity and Rolling Rotation:
Xpos# = 500
Ypos# = R% - SQR((R% * R%) - (Xpos# * Xpos#))
VBall# = 0
BallTwist! = 0

'Screen
SCREEN _NEWIMAGE(Uscreen%, Vscreen%, 32)
_SCREENMOVE 50, 0
_DEST 0
'_DISPLAYORDER _HARDWARE , _SOFTWARE
_DISPLAYORDER _HARDWARE 'Hardware images only

WHILE _KEYHIT <> 27 'Esc to quit
    _LIMIT 120 'Frames/Second Rate

    'Background
    _PUTIMAGE (0, 0), Background&

    'Track Image
    FOR H% = 0 TO TracksNo%
        Ax12! = UStart% + H% * Utrack%
        Ay12! = R% - SQR((R% * R%) - (Ax12! * Ax12!))
        ThetaTrack! = ATN(Ay12! / Ax12!)
        Az11! = -VTrack% / 2
        Ax11! = Ax12! + BallRad% * SIN(ThetaTrack!) + XDisp%
        Ay11! = Ay12! - BallRad% * COS(ThetaTrack!) - YDisp%
        Bx12! = Ax12! + Utrack%
        By12! = R% - SQR((R% * R%) - (Bx12! * Bx12!))
        ThetaTrack! = ATN(By12! / Bx12!)
        Bx11! = Bx12! + BallRad% * SIN(ThetaTrack!) + XDisp%
        By11! = By12! - BallRad% * COS(ThetaTrack!) - YDisp%
        Bz11! = -VTrack% / 2
        Cx11! = Bx11!
        Cy11! = By11!
        Cz11! = VTrack% / 2
        Dx11! = Ax11!
        Dy11! = Ay11!
        Dz11! = VTrack% / 2
        'Rotate around Y-axis
        Ax1! = Ax11! * COS(YAngle!) + Az11! * SIN(YAngle!)
        Az1! = Az11! * COS(YAngle!) - Ax11! * SIN(YAngle!)
        Bx1! = Bx11! * COS(YAngle!) + Bz11! * SIN(YAngle!)
        Bz1! = Bz11! * COS(YAngle!) - Bx11! * SIN(YAngle!)
        Cx1! = Cx11! * COS(YAngle!) + Cz11! * SIN(YAngle!)
        Cz1! = Cz11! * COS(YAngle!) - Cx11! * SIN(YAngle!)
        Dx1! = Dx11! * COS(YAngle!) + Dz11! * SIN(YAngle!)
        Dz1! = Dz11! * COS(YAngle!) - Dx11! * SIN(YAngle!)
        'Rotate around Z-axis
        Ax2! = Ax1! * COS(ZAngle!) + Ay11! * SIN(ZAngle!)
        Ay2! = Ay11! * COS(ZAngle!) - Ax1! * SIN(ZAngle!)
        Bx2! = Bx1! * COS(ZAngle!) + By11! * SIN(ZAngle!)
        By2! = By11! * COS(ZAngle!) - Bx1! * SIN(ZAngle!)
        Cx2! = Cx1! * COS(ZAngle!) + Cy11! * SIN(ZAngle!)
        Cy2! = Cy11! * COS(ZAngle!) - Cx1! * SIN(ZAngle!)
        Dx2! = Dx1! * COS(ZAngle!) + Dy11! * SIN(ZAngle!)
        Dy2! = Dy11! * COS(ZAngle!) - Dx1! * SIN(ZAngle!)
        _MAPTRIANGLE (0, 0)-(Utrack% - 1, 0)-(Utrack% - 1, VTrack% - 1), HalfPipe& TO(Ax2!, Ay2!, Az1! - PerspDist%)-(Bx2!, By2!, Bz1! - PerspDist%)-(Cx2!, Cy2!, Cz1! - PerspDist%)
        _MAPTRIANGLE (Utrack% - 1, VTrack% - 1)-(0, VTrack% - 1)-(0, 0), HalfPipe& TO(Cx2!, Cy2!, Cz1! - PerspDist%)-(Dx2!, Dy2!, Dz1! - PerspDist%)-(Ax2!, Ay2!, Az1! - PerspDist%)
    NEXT H%

    'Map & Display Ball
    FOR N%% = 0 TO NoPhis%% - 1 'STEP 2
        FOR M%% = 0 TO 2 * NoAlphas%% - 2 'STEP 2
            'Map to 3D
            Ax11! = MapTo3D!(N%%, M%%, 1, 0)
            Ay11! = MapTo3D!(N%%, M%%, 1, 1)
            Bx11! = MapTo3D!(N%%, M%% + 1, 1, 0)
            By11! = MapTo3D!(N%%, M%% + 1, 1, 1)
            Cx11! = MapTo3D!(N%% + 1, M%% + 1, 1, 0)
            Cy11! = MapTo3D!(N%% + 1, M%% + 1, 1, 1)
            Dx11! = MapTo3D!(N%% + 1, M%%, 1, 0)
            Dy11! = MapTo3D!(N%% + 1, M%%, 1, 1)
            Ex11! = MapTo3D!(N%%, M%%, 1, 0)
            Ey11! = MapTo3D!(N%%, M%%, 1, 1)
            Fx11! = MapTo3D!(N%%, M%% + 1, 1, 0)
            Fy11! = MapTo3D!(N%%, M%% + 1, 1, 1)
            Gx11! = MapTo3D!(N%% + 1, M%% + 1, 1, 0)
            Gy11! = MapTo3D!(N%% + 1, M%% + 1, 1, 1)
            Hx11! = MapTo3D!(N%% + 1, M%%, 1, 0)
            Hy11! = MapTo3D!(N%% + 1, M%%, 1, 1)
            'Rotate ball about rolling axis
            Ax0! = Ax11! * COS(BallTwist!) + Ay11! * SIN(BallTwist!) + Xpos# + XDisp%
            Ay0! = Ay11! * COS(BallTwist!) - Ax11! * SIN(BallTwist!) + Ypos# - YDisp%
            Az0! = MapTo3D!(N%%, M%%, 1, 2)
            Bx0! = Bx11! * COS(BallTwist!) + By11! * SIN(BallTwist!) + Xpos# + XDisp%
            By0! = By11! * COS(BallTwist!) - Bx11! * SIN(BallTwist!) + Ypos# - YDisp%
            Bz0! = MapTo3D!(N%%, M%% + 1, 1, 2)
            Cx0! = Cx11! * COS(BallTwist!) + Cy11! * SIN(BallTwist!) + Xpos# + XDisp%
            Cy0! = Cy11! * COS(BallTwist!) - Cx11! * SIN(BallTwist!) + Ypos# - YDisp%
            Cz0! = MapTo3D!(N%% + 1, M%% + 1, 1, 2)
            Dx0! = Dx11! * COS(BallTwist!) + Dy11! * SIN(BallTwist!) + Xpos# + XDisp%
            Dy0! = Dy11! * COS(BallTwist!) - Dx11! * SIN(BallTwist!) + Ypos# - YDisp%
            Dz0! = MapTo3D!(N%% + 1, M%%, 1, 2)
            Ex0! = Ex11! * COS(BallTwist!) + Ey11! * SIN(BallTwist!) + Xpos# + XDisp%
            Ey0! = Ey11! * COS(BallTwist!) - Ex11! * SIN(BallTwist!) + Ypos# - YDisp%
            Ez0! = -MapTo3D!(N%%, M%%, 1, 2)
            Fx0! = Fx11! * COS(BallTwist!) + Fy11! * SIN(BallTwist!) + Xpos# + XDisp%
            Fy0! = Fy11! * COS(BallTwist!) - Fx11! * SIN(BallTwist!) + Ypos# - YDisp%
            Fz0! = -MapTo3D!(N%%, M%% + 1, 1, 2)
            Gx0! = Gx11! * COS(BallTwist!) + Gy11! * SIN(BallTwist!) + Xpos# + XDisp%
            Gy0! = Gy11! * COS(BallTwist!) - Gx11! * SIN(BallTwist!) + Ypos# - YDisp%
            Gz0! = -MapTo3D!(N%% + 1, M%% + 1, 1, 2)
            Hx0! = Hx11! * COS(BallTwist!) + Hy11! * SIN(BallTwist!) + Xpos# + XDisp%
            Hy0! = Hy11! * COS(BallTwist!) - Hx11! * SIN(BallTwist!) + Ypos# - YDisp%
            Hz0! = -MapTo3D!(N%% + 1, M%%, 1, 2)
            'Then do orientation rotations:
            'Rotate around Y-axis
            Ax1! = Ax0! * COS(YAngle!) + Az0! * SIN(YAngle!)
            Az1! = Az0! * COS(YAngle!) - Ax0! * SIN(YAngle!)
            Bx1! = Bx0! * COS(YAngle!) + Bz0! * SIN(YAngle!)
            Bz1! = Bz0! * COS(YAngle!) - Bx0! * SIN(YAngle!)
            Cx1! = Cx0! * COS(YAngle!) + Cz0! * SIN(YAngle!)
            Cz1! = Cz0! * COS(YAngle!) - Cx0! * SIN(YAngle!)
            Dx1! = Dx0! * COS(YAngle!) + Dz0! * SIN(YAngle!)
            Dz1! = Dz0! * COS(YAngle!) - Dx0! * SIN(YAngle!)
            Ex1! = Ex0! * COS(YAngle!) + Ez0! * SIN(YAngle!)
            Ez1! = Ez0! * COS(YAngle!) - Ex0! * SIN(YAngle!)
            Fx1! = Fx0! * COS(YAngle!) + Fz0! * SIN(YAngle!)
            Fz1! = Fz0! * COS(YAngle!) - Fx0! * SIN(YAngle!)
            Gx1! = Gx0! * COS(YAngle!) + Gz0! * SIN(YAngle!)
            Gz1! = Gz0! * COS(YAngle!) - Gx0! * SIN(YAngle!)
            Hx1! = Hx0! * COS(YAngle!) + Hz0! * SIN(YAngle!)
            Hz1! = Hz0! * COS(YAngle!) - Hx0! * SIN(YAngle!)
            'Rotate around Z-axis
            Ax2! = Ax1! * COS(ZAngle!) + Ay0! * SIN(ZAngle!)
            Ay2! = Ay0! * COS(ZAngle!) - Ax1! * SIN(ZAngle!)
            Bx2! = Bx1! * COS(ZAngle!) + By0! * SIN(ZAngle!)
            By2! = By0! * COS(ZAngle!) - Bx1! * SIN(ZAngle!)
            Cx2! = Cx1! * COS(ZAngle!) + Cy0! * SIN(ZAngle!)
            Cy2! = Cy0! * COS(ZAngle!) - Cx1! * SIN(ZAngle!)
            Dx2! = Dx1! * COS(ZAngle!) + Dy0! * SIN(ZAngle!)
            Dy2! = Dy0! * COS(ZAngle!) - Dx1! * SIN(ZAngle!)
            Ex2! = Ex1! * COS(ZAngle!) + Ey0! * SIN(ZAngle!)
            Ey2! = Ey0! * COS(ZAngle!) - Ex1! * SIN(ZAngle!)
            Fx2! = Fx1! * COS(ZAngle!) + Fy0! * SIN(ZAngle!)
            Fy2! = Fy0! * COS(ZAngle!) - Fx1! * SIN(ZAngle!)
            Gx2! = Gx1! * COS(ZAngle!) + Gy0! * SIN(ZAngle!)
            Gy2! = Gy0! * COS(ZAngle!) - Gx1! * SIN(ZAngle!)
            Hx2! = Hx1! * COS(ZAngle!) + Hy0! * SIN(ZAngle!)
            Hy2! = Hy0! * COS(ZAngle!) - Hx1! * SIN(ZAngle!)
            'Now map ball co-ordinates to 3D _MAPTRIANGLE space
            'Near hemisphere:
            _MAPTRIANGLE (MapTo3D!(N%%, M%%, 0, 0), MapTo3D!(N%%, M%%, 0, 1))-(MapTo3D!(N%%, M%% + 1, 0, 0), MapTo3D!(N%%, M%% + 1, 0, 1))-(MapTo3D!(N%% + 1, M%% + 1, 0, 0), MapTo3D!(N%% + 1, M%% + 1, 0, 1)), SolidSphere& TO(Ax2!, Ay2!, Az1! - PerspDist%)-(Bx2!, By2!, Bz1! - PerspDist%)-(Cx2!, Cy2!, Cz1! - PerspDist%)
            _MAPTRIANGLE (MapTo3D!(N%% + 1, M%% + 1, 0, 0), MapTo3D!(N%% + 1, M%% + 1, 0, 1))-(MapTo3D!(N%% + 1, M%%, 0, 0), MapTo3D!(N%% + 1, M%%, 0, 1))-(MapTo3D!(N%%, M%%, 0, 0), MapTo3D!(N%%, M%%, 0, 1)), SolidSphere& TO(Cx2!, Cy2!, Cz1! - PerspDist%)-(Dx2!, Dy2!, Dz1! - PerspDist%)-(Ax2!, Ay2!, Az1! - PerspDist%)
            'Far hemisphere:
            _MAPTRIANGLE (MapTo3D!(N%%, M%%, 0, 0), MapTo3D!(N%%, M%%, 0, 1))-(MapTo3D!(N%%, M%% + 1, 0, 0), MapTo3D!(N%%, M%% + 1, 0, 1))-(MapTo3D!(N%% + 1, M%% + 1, 0, 0), MapTo3D!(N%% + 1, M%% + 1, 0, 1)), SolidSphere& TO(Ex2!, Ey2!, Ez1! - PerspDist%)-(Fx2!, Fy2!, Fz1! - PerspDist%)-(Gx2!, Gy2!, Gz1! - PerspDist%)
            _MAPTRIANGLE (MapTo3D!(N%% + 1, M%% + 1, 0, 0), MapTo3D!(N%% + 1, M%% + 1, 0, 1))-(MapTo3D!(N%% + 1, M%%, 0, 0), MapTo3D!(N%% + 1, M%%, 0, 1))-(MapTo3D!(N%%, M%%, 0, 0), MapTo3D!(N%%, M%%, 0, 1)), SolidSphere& TO(Gx2!, Gy2!, Gz1! - PerspDist%)-(Hx2!, Hy2!, Hz1! - PerspDist%)-(Ex2!, Ey2!, Ez1! - PerspDist%)
        NEXT M%%
    NEXT N%%

    _DISPLAY

    'Ball position/speed
    Theta# = ATN(Ypos# / Xpos#)
    Accn# = 5 * g# * SIN(2 * Theta#) / 7
    deltaV# = Accn# * deltaT#
    AveV# = VBall# - (deltaV# / 2)
    VBall# = VBall# - deltaV#
    'Index ball position:
    Xpos# = Xpos# + (AveV# * deltaT#) * COS(2 * Theta#)
    'Forcing the ball to follow the circular curve does not properly conserve enegy (expected this to be the case)
    'So at the extremes, the position and velocity are manually reset:
    IF Xpos# < -500 THEN
        Xpos# = -500
        VBall# = 0
    ELSEIF Xpos# > 500 THEN
        Xpos# = 500
        VBall# = 0
    END IF
    Ypos# = R% - SQR((R% * R%) - (Xpos# * Xpos#))
    'Ball rolling:
    BallTwist! = BallTwist! + ((AveV# * deltaT#) / BallRad%%)
    IF BallTwist! < -_PI THEN
        BallTwist! = _PI
    ELSEIF BallTwist! > _PI THEN
        BallTwist! = -_PI
    END IF

WEND

SYSTEM

FUNCTION MakeHardware& (Imagename&)
    MakeHardware& = _COPYIMAGE(Imagename&, 33)
    _FREEIMAGE Imagename&
END FUNCTION
Reply


Messages In This Thread
3D Rolling Sphere - by Magdha - 10-29-2025, 10:59 AM
RE: 3D Rolling Sphere - by Unseen Machine - 10-29-2025, 11:23 PM
RE: 3D Rolling Sphere - by Magdha - 10-30-2025, 09:54 AM
RE: 3D Rolling Sphere - by Unseen Machine - 11-01-2025, 12:24 AM
RE: 3D Rolling Sphere - by Magdha - 11-01-2025, 10:53 AM

Forum Jump:


Users browsing this thread: 1 Guest(s)