This 3D animation was rendered in BBC BASIC for SDL 2.0 (although the program is compatible with BBC BASIC for Windows if you have the WEBGLLIB library). You can run it 'live' in your browser here.
Like all the other 3D animations this was very easy to create, because it uses the standard boilerplate with very little custom code. The 3D models of the gears were from turbosquid.com ($10 for the set).
One aspect that was a little more tricky than usual was the lighting, because of wanting to highlight all the individual cogs. I ended up using six lights, which I think is more than I've used before.
If you would be interested to see the code let me know and I'll post it here.
https://youtu.be/DSUOqfnQJnI
Animated 3D gears
Re: Animated 3D gears
Hi Richard,
Very nice - yes, I'd be interested to see the code. Can you make a clock now?

D
Very nice - yes, I'd be interested to see the code. Can you make a clock now?

D
Re: Animated 3D gears
What makes a clock more difficult, apart from the sheer complexity, is the power source (e.g. spring or weight), time-keeping element (e.g. pendulum) and escapement. In practice, unless you cheat, that means using a physics engine like Box2D to simulate those features.
Of course combining Box2D and 3D rendering is already something that we've done successfully in the Pinball program, but it makes everything considerably more involved.
By all means try it if you are keen (I'd be inclined to build the Box2D simulation and the 3D gearing separately, to start with, and then join them together). I expect you'll find that it's been done before (but probably not in BBC BASIC)
Listing of the gears program below, it's mostly the standard 3D boilerplate, with only the gear positioning and rotation needing 'custom' code:
Code: Select all
REM 'Gears' by Richard Russell, http://www.rtrussell.co.uk/, 26-Dec-2023
REM 'Precision Gears' model from turbosquid.com
REM MAY NOT BE REUSED WITHOUT BEING REPURCHASED!
REM!Embed @dir$+"gear1.fvf", @dir$+"gear2.fvf", @dir$+"gear3.fvf", @dir$+"gear4.fvf",
REM!Embed @dir$+"gear5.fvf", @dir$+"gear6.fvf", @dir$+"gear7.fvf", @dir$+"gear8.fvf",
REM!Embed @dir$+"gear9.fvf", @dir$+"gear10.fvf", @dir$+"gear11.fvf", @lib$+"webgllib"
REM This program is compatible with BBCSDL and BB4W + WEBGLLIB library
VDU 23,22,1024;576;16,20,16,0
INSTALL @lib$+"webgllib"
nObj% = 11
DIM Object%(nObj%-1), nVert%(nObj%-1), vFormat%(nObj%-1), vSize%(nObj%-1)
DIM Texture%(nObj%-1), Material%(nObj%-1), Pan(nObj%-1), Tilt(nObj%-1)
DIM Roll(nObj%-1), Xpos(nObj%-1), Ypos(nObj%-1), Zpos(nObj%-1), nTeeth(nObj%-1)
nLights% = 6
DIM Light{(nLights%-1)Type%, Diffuse{r%,g%,b%,a%}, Specular{r%,g%,b%,a%}, \
\ Ambient{r%,g%,b%,a%}, Position{x%,y%,z%}, Direction{x%,y%,z%}, \
\ Range%, Falloff%, Attenuation0%, Attenuation1%, Attenuation2%, \
\ Theta%, Phi%}
DIM Light%(nLights%-1)
DIM Material{Diffuse{r%,g%,b%,a%}, Ambient{r%,g%,b%,a%}, \
\ Specular{r%,g%,b%,a%}, Emissive{r%,g%,b%,a%}, Power%}
ON CLOSE PROCcleanup : QUIT
ON ERROR PROCcleanup : IF ERR=17 CHAIN @lib$+"../examples/tools/touchide" ELSE MODE 3 : PRINT REPORT$ : END
ON MOVE Resize% OR= (@msg% = 5) : RETURN
Device% = 0
Object% = 0
Resize% = FALSE
PROCinitrender
REPEAT
WAIT 1
PROCanimate
UNTIL FALSE
END
DEF PROCanimate
LOCAL bgcolour%, viewangle, aspectratio, mindist, maxdist, cameraroll
LOCAL camera(), lookat(), temp() : DIM camera(2), lookat(2), temp(nObj% - 1)
lookat() = 0, 0, 0
bgcolour% = &FF406080
viewangle = RAD(40)
aspectratio = @size.x%/@size.y%
mindist = 3.0
maxdist = 300.0
cameraroll = 0
camera() = 60*COS(TIME/1000), 20+60*COS(TIME/600), 60*SIN(TIME/1000)
Pan() = TIME / 4 / nTeeth()
Ypos() = 100
REM Middle layer:
Ypos(5) = 0 : Pan(5) += PI/40 : REM 40 teeth
Ypos(8) = 0 : Xpos(8) = 18 : REM 32 teeth
Ypos(6) = 0 : Xpos(6) = -16 : REM 24 teeth
Ypos(0) = 0 : Xpos(0) = 2 : REM 96 teeth (internal)
REM Bottom layer:
Ypos(4) = -5 : Xpos(4) = Xpos(8) : Pan(4) = Pan(8) : REM 56 teeth
Ypos(9) = -5 : Xpos(9) = Xpos(6) : Pan(9) = Pan(6) : REM 48 teeth
Ypos(1) = -5 : Xpos(1) = 24 : Pan(1) = Pan(4) * 56/80 : REM 80 teeth (internal)
Ypos(2) = -5 : Xpos(2) = -20 : Pan(2) = Pan(8) : REM 64 teeth (internal)
REM Top layer:
Ypos(7) = 5 : Pan(7) = Pan(5) : REM 16 teeth
Ypos(10) = 5 : Zpos(10) = 20 : Pan(10) = -Pan(7) / 4 + PI / 64 : REM 64 teeth
Ypos(3) = 5 : Zpos(3) =-22 : Pan(3) = -Pan(7) * 16 / 72 + PI / 72 : REM 72 teeth
PROC_render(Device%, bgcolour%, nLights%, Light%(), nObj%, Material%(), Texture%(), \
\ Object%(), nVert%(), vFormat%(), vSize%(), Pan(), Tilt(), Roll(), Xpos(), Ypos(), Zpos(), \
\ camera(), lookat(), viewangle, aspectratio, mindist, maxdist, cameraroll)
IF Resize% Resize% = FALSE : PROCcleanup : PROCinitrender
ENDPROC
DEF PROCinitrender
LOCAL I%
VDU 26
IF POS REM SDL thread sync
PRINT "Please wait..."
*REFRESH OFF
*REFRESH
Device% = FN_initgl(@hwnd%, 0, 3)
IF Device% = 0 ERROR 100, "Can't initialise 3D library"
REM Load the 3D objects:
RESTORE +1
FOR I% = 0 TO nObj% - 1
Object%(I%) = FN_load3d(Device%, @dir$+"gear" + STR$(I%+1) + ".fvf", nVert%(I%), vFormat%(I%), vSize%(I%))
IF Object%(I%) = 0 ERROR 100, "Can't load gear" + STR$(I%+1) + ".fvf"
READ nTeeth(I%)
NEXT
DATA 96, 80, 64, 72, 56, -40, 24, 16, 32, 48, 64
REM Brass-coloured material:
Material.Diffuse.r% = FN_f4(0.882)
Material.Diffuse.g% = FN_f4(0.757)
Material.Diffuse.b% = FN_f4(0.431)
Material.Specular.r% = FN_f4(1.0)
Material.Specular.g% = FN_f4(1.0)
Material.Specular.b% = FN_f4(1.0)
Material.Power% = FN_f4(50.0)
Material%() = Material{} - PAGE + !340
REM Three point-source lights above:
Light{(0)}.Type% = 1 : REM point source
Light{(0)}.Diffuse.r% = FN_f4(0.3) : REM diffuse colour RGB
Light{(0)}.Diffuse.g% = FN_f4(0.3)
Light{(0)}.Diffuse.b% = FN_f4(0.3)
Light{(0)}.Diffuse.a% = FN_f4(1)
Light{(0)}.Specular.r% = FN_f4(1.3) : REM specular colour RGB
Light{(0)}.Specular.g% = FN_f4(1.3)
Light{(0)}.Specular.b% = FN_f4(1.3)
Light{(0)}.Position.x% = FN_f4(150) : REM position XYZ
Light{(0)}.Position.y% = FN_f4(100)
Light{(0)}.Position.z% = FN_f4(0)
Light{(0)}.Range% = FN_f4(500)
Light{(0)}.Attenuation0% = FN_f4(1)
Light%(0) = Light{(0)} - PAGE + !340
REM Second light at +120 degrees:
Light{(1)} = Light{(0)}
Light{(1)}.Position.x% = FN_f4(150 * COSRAD120)
Light{(1)}.Position.z% = FN_f4(150 * SINRAD120)
Light%(1) = Light{(1)} - PAGE + !340
REM Third light at -120 degrees:
Light{(2)} = Light{(0)}
Light{(2)}.Position.x% = FN_f4(150 * COSRAD-120)
Light{(2)}.Position.z% = FN_f4(150 * SINRAD-120)
Light%(2) = Light{(2)} - PAGE + !340
REM Three point-source lights below:
Light{(3)} = Light{(0)}
Light{(3)}.Position.y% = FN_f4(-100)
Light%(3) = Light{(3)} - PAGE + !340
Light{(4)} = Light{(1)}
Light{(4)}.Position.y% = FN_f4(-100)
Light%(4) = Light{(4)} - PAGE + !340
Light{(5)} = Light{(2)}
Light{(5)}.Position.y% = FN_f4(-100)
Light%(5) = Light{(5)} - PAGE + !340
ENDPROC
DEF PROCcleanup
Object% += 0 : IF Object% PROC_release(Object%) : Object% = 0
Device% += 0 : IF Device% PROC_release(Device%) : Device% = 0
*REFRESH ON
ENDPROC