Animated 3D gears

Here you can link to screenshots and demos etc. of programs made using BBC BASIC
Hated Moron

Animated 3D gears

Post by Hated Moron »

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
DDRM

Re: Animated 3D gears

Post by DDRM »

Hi Richard,

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

:-)

D
Hated Moron

Re: Animated 3D gears

Post by Hated Moron »

DDRM wrote: Thu 28 Dec 2023, 10:17 Very nice - yes, I'd be interested to see the code. Can you make a clock now?
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