UnderwareDESIGN

PlayBASIC => Resources => Source Codes => Topic started by: kevin on April 26, 2025, 01:42:07 PM

Title: 3D Cube - Filled Polygon & Wire frame Polygons
Post by: kevin on April 26, 2025, 01:42:07 PM
3D Cube - Filled Polygon & Wire frame Polygons


 This PlayBASIC program draws a spinning 3D cube on the screen. It shows two versions of the cube side-by-side — one filled with solid-colored faces (flat-shaded) and one drawn as a wireframe.

Here's how it works:

    Setup: It creates a random color palette for the cube's faces and sets up arrays to store the cube's 3D points (vertices) and the faces (which points connect to make each side).

    Scaling: The cube's points are scaled to a larger size using the SizeVerts function.

    Rotation: Every frame, the cube's points are rotated around the X, Y, and Z axes using a rotation matrix inside the RotateVerts function. This gives the cube its spinning effect.

    Projection: After rotation, the 3D points are projected onto the 2D screen so they can be drawn.

    Drawing: The DrawCube function draws each face twice:

        On the left side, it draws a filled, solid-colored polygon.

        On the right side, it draws just the wireframe (outline) of the face.

    Backface Culling: The code uses the cross product to check whether each face is pointing towards the viewer and only draws the visible ones.

    Animation: The cube keeps rotating smoothly because the tilt, turn, and roll angles are slightly increased every frame.

    Controls: Pressing the up arrow zooms the camera closer, and down arrow zooms out.



[pbcode]

 /*
This PlayBASIC program draws a spinning 3D cube using random colors. It scales the cube, rotates its points in 3D space, projects them onto the 2D screen, and draws each face as a filled shape on the left and a wireframe on the right. The cube rotates automatically and the camera distance can be adjusted with the up/down keys.

 */

    // Colour palette for the cube faces   
    dim Palette(16)
    for lp =0 to 16
            Palette(lp) = rndrgb()       
    next       

    Rem create arrays to hold the points (vertex)
  rem  and face data for our cube.
    Dim Points#(8,5)
    Dim Faces(6,5)
       
   
    Rem read in the vertex data
    For p = 1 To 8
        points#(p,1)    = ReadData()
        points#(p,2)    = ReadData()
        points#(p,3)    = ReadData()
    Next p

    Rem Read in the face Data
    For f = 1 To 6
        faces(f,1) = ReadData()
        faces(f,2) = ReadData()
        faces(f,3) = ReadData()
        faces(f,4) = ReadData()
    Next f



Rem some space To put the rotated points
    Dim rotated#(255,3)

Rem variables which control the size of the cube
    x_scale# = 200.0
    y_scale# = 200.0
    z_scale# = 200.0

Rem set the initial rotation angles To 0
    tilt#=0.0
    turn#=0.0
    roll#=0.0


    SizeVerts(Points#(),x_scale#,y_scale#,z_scale#)

    // distance from the viewer
    Zdepth#=1000


  Do

        // clear the screen to rgb colour
        cls $334455

        // Rotate vertex               
        RotateVerts(points#(),Rotated#(),8,Tilt#,turn#,roll#,Zdepth#)

        // Draw the cube projected to the screen
        DrawCube()
       
        Rem animate the tilt, turn And roll values
        tilt# = tilt#+1.31
        turn# = turn#+0.42   
        roll# = roll#+0.53

        if upkey() and zdepth#>400 then Zdepth#=Zdepth#-20
        if downkey() then Zdepth#=Zdepth#+20

        //  Flip the buffer to show user the frame and start rendering
        // the new frame
        Sync
loop





Function RotateVerts(Pts#(),RotatedPts#(),NumbOfVerts,Tilt#,turn#,roll#,ObjectDistance#)

    ProjectionX#=400
    ProjectionY#=400

    cx=getscreenwidth()/2
    cy=getscreenheight()/2
   

    Rem prepare the rotation matrix
        A#=Cos(tilt#):B#=Sin(tilt#)
        C#=Cos(turn#):D#=Sin(turn#)
        E#=Cos(roll#):F#=Sin(roll#)
        AD#=A#*D#
        BD#=B#*D#

    ; Calc Rotation Matrix 
          m11#=C#*E#
        m21#=-1*C#*F#
        m31#=D#
        m12#=BD#*E#+A#*F#
        m22#=-1*BD#*F#+A#*E#
        m32#=-1*B#*C#
        m13#=-1*AD#*E#+B#*F#
        m23#=AD#*F#+B#*E#
        m33#=A#*C#

    Rem rotate all the points using the matrix
        For p=1 To NumbOfVerts

              pointx#=pts#(p,1)
              pointy#=pts#(p,2)
              pointz#=pts#(p,3)

            rotatedPts#(p,1) = (m11# * pointx#) + (m12# * pointy#) + (m13# * pointz#)
            rotatedPts#(p,2) = (m21# * pointx#) + (m22# * pointy#) + (m23# * pointz#)
            rotatedPts#(p,3) = (m31# * pointx#) + (m32# * pointy#) + (m33# * pointz#)
           
            Rem Now Do the perspective calculation
            z# = rotatedPts#(p,3) + ObjectDistance#
          rotatedPts#(p,1) = cx+ ((rotatedPts#(p,1)*ProjectionX# ) / z#)
            rotatedPts#(p,2) = cy+ ((rotatedpts#(p,2)*ProjectionY# )/ z#)
        Next p


   
Endfunction
   



Function DrawCube()
    lockbuffer
        For f=1 To 6
          Rem p1 -> p4 are the points On the face
          p1 = faces(f,1)
          p2 = faces(f,2)
          p3 = faces(f,3)
          p4 = faces(f,4)

            vx1#=rotated#(p1,1)
            vy1#=rotated#(p1,2)

            vx2#=rotated#(p2,1)
            vy2#=rotated#(p2,2)
   
            vx3#=rotated#(p3,1)
            vy3#=rotated#(p3,2)

            ; Use Cross product to check if the face is pointing towards the camera
          If (((vx2#-vx1#)*(vy3#-vy1#))-((vx3#-vx1#)*(vy2#-vy1#)))>0
     
                vx4#=rotated#(p4,1)
                vy4#=rotated#(p4,2)

                pad=200
                   
                // draw this face was wire frame
                vx1#-=pad       
                vx2#-=pad       
                vx3#-=pad       
                vx4#-=pad       

                quadc vx1#,vy1#,vx2#,vy2#,vx3#,vy3#,vx4#,vy4#,Palette(f)

                pad*=2
                // draw this face was wire frame
                vx1#+=pad       
                vx2#+=pad       
                vx3#+=pad       
                vx4#+=pad       

                ThisRGB =Palette(f)
                linec vx1#,vy1#,vx2#,vy2#,ThisRGB
                linec vx2#,vy2#,vx3#,vy3#,ThisRGB
                linec vx3#,vy3#,vx4#,vy4#,ThisRGB
                linec vx4#,vy4#,vx1#,vy1#,ThisRGB

            EndIf
    Next f
    unlockbuffer
EndFunction

   



Function SizeVerts(Pts#(),x_scale#,y_scale#,z_scale#)
    Rem rotate all the points using the matrix
        For p=1 To getArrayelements(pts#(),1)
              pts#(p,1)=pts#(p,1)* x_scale#
              pts#(p,2)=pts#(p,2)* Y_scale#
              pts#(p,3)=pts#(p,3)* Z_scale#
        Next p
Endfunction
   



Rem vertex Data

Data -1,-1,-1
Data 1,-1,-1
Data 1,1,-1
Data -1,1,-1

Data -1,-1,1
Data 1,-1,1
Data 1,1,1
Data -1,1,1



Rem face Data

;right/left
Data 2,6,7,3
Data 5,1,4,8
   
Data 1,2,3,4
Data 6,5,8,7

; top /bot
Data 5,6,2,1
Data 4,3,7,8


[/pbcode]