QB64 Phoenix Edition
Poor Man's 3D Wire Frame - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://qb64phoenix.com/forum/forumdisplay.php?fid=3)
+---- Forum: Help Me! (https://qb64phoenix.com/forum/forumdisplay.php?fid=10)
+---- Thread: Poor Man's 3D Wire Frame (/showthread.php?tid=2850)

Pages: 1 2


Poor Man's 3D Wire Frame - NakedApe - 07-04-2024

So, as the math midget I am, I stumbled upon a way to make 3D looking wire frames using the ATAN2 command which turns "Cartesian coordinates into global coordinates" or so I read. I don't understand why/how the position of the ship on the screen affects the rendering of the eleven 2D points I created. For example, pressing z and putting the ship on the left-hand side of the screen smooshes it flat. Can anyone explain to me on, say, an 8th grade level, what's going on triginomically here? What have I done?!  Big Grin

Code: (Select All)
OPTION _EXPLICIT
DIM AS INTEGER DTW, DTH: DTW = _DESKTOPWIDTH: DTH = _DESKTOPHEIGHT
SCREEN _NEWIMAGE(DTW, DTH, 32)
_FULLSCREEN _SQUAREPIXELS , _SMOOTH '
_MOUSEHIDE '
TYPE pnt
    x AS SINGLE
    y AS SINGLE '
    ang AS SINGLE '
    radius AS SINGLE '
END TYPE '

DIM pnt(1 TO 13) AS pnt
DIM c AS INTEGER
DIM AS DOUBLE radians
DIM AS INTEGER radius
DIM AS SINGLE adder, sizeFactor, angle, fpChange
DIM AS SINGLE shipX, shipY
DIM AS LONG starScape
DIM AS _UNSIGNED LONG yellow

yellow = _RGB32(249, 244, 17)
shipX = DTW / 2
shipY = DTH / 2

DATA 180,25
'                      1      11 POINTS TO PLAY WITH, 1 is nose point
DATA 265,30
'                      2        DATA = THETA ANGLE, RADIUS - larger radius = closer to viewer
DATA 275,30
'                      3
DATA 340,4
'                      4
DATA 0,5
'                      5
DATA 20,4
'                      6
DATA 85,30
'                      7
DATA 95,30
'                      8
DATA 130,4
'                      9
DATA 230,4
'                      10
DATA 0,0
'                      11
DATA 270,27
'              12, side panel point
DATA 90,27
'              13, other side panel
FOR c = 1 TO UBOUND(pnt) '                      init points array
    READ angle, radius
    pnt(c).ang = angle
    pnt(c).radius = radius
NEXT c

sizeChange 2.5
sizeFactor = 38 '                              start up settings
adder = .25
angle = 270
fpChange = 66 '                                the nose point
pnt(1).radius = pnt(1).radius + fpChange
drawStars

DO
    CLS
    FOR c = 1 TO UBOUND(pnt) '                  rotate ship
        pnt(c).ang = pnt(c).ang + adder
        radians = _D2R(pnt(c).ang)
        pnt(c).x = pnt(c).radius * COS(radians) + shipX '                  atan2 subbed for x/cos value spins in Y axis, neg for left side, pos for right
        pnt(c).y = pnt(c).radius * _ATAN2(pnt(c).x, pnt(c).y) + shipY '  atan2 subbed for y/sin value spins in X axis, upside down, rightside up...
    NEXT c

    _PUTIMAGE , starScape, 0
    ' -----------------------------*******************
    LINE (pnt(1).x, pnt(1).y)-(pnt(2).x, pnt(2).y), yellow '      draw ship
    FOR c = 3 TO 8
        LINE -(pnt(c).x, pnt(c).y), yellow
    NEXT c
    LINE (pnt(8).x, pnt(8).y)-(pnt(1).x, pnt(1).y), yellow
    LINE (pnt(3).x, pnt(3).y)-(pnt(1).x, pnt(1).y), yellow
    LINE (pnt(7).x, pnt(7).y)-(pnt(1).x, pnt(1).y), yellow
    LINE (pnt(2).x, pnt(2).y)-(pnt(10).x, pnt(10).y), yellow
    LINE (pnt(8).x, pnt(8).y)-(pnt(9).x, pnt(9).y), yellow
    LINE (pnt(10).x, pnt(10).y)-(pnt(11).x, pnt(11).y), yellow
    LINE (pnt(9).x, pnt(9).y)-(pnt(11).x, pnt(11).y), yellow
    LINE (pnt(5).x, pnt(5).y)-(pnt(11).x, pnt(11).y), yellow

    IF sizeFactor > 10 AND sizeFactor < 80 AND fpChange > -20 AND shipX = DTW / 2 AND shipY = DTH / 2 THEN
        IF angle < 80 OR angle > 287 THEN PAINT (_WIDTH / 2, _HEIGHT / 2 + 40), _RGB32(250, 50, 150, 60), yellow
        IF angle > 77 AND angle < 255 THEN PAINT (_WIDTH / 2, _HEIGHT / 2 + 40), _RGB32(100, 190, 0, 90), yellow
    END IF
    IF sizeFactor > -50 THEN
        CIRCLE (pnt(12).x, pnt(12).y), 2, _RGB32(249, 249, 0) '    side panel
        PAINT (pnt(12).x, pnt(12).y), _RGB32(255, 0, 0), _RGB32(249, 249, 0)
        CIRCLE (pnt(13).x, pnt(13).y), 2, _RGB32(249, 250, 0)
        PAINT (pnt(13).x, pnt(13).y), _RGB32(255, 0, 0), _RGB32(249, 250, 0)
    END IF
    ' -----------------------------*******************                          user input
    IF _KEYDOWN(122) THEN shipX = shipX - 2
    IF _KEYDOWN(120) THEN shipX = shipX + 2
    IF _KEYDOWN(99) THEN shipY = shipY - 1.554
    IF _KEYDOWN(118) THEN shipY = shipY + 1.554

    IF _KEYDOWN(19200) THEN
        IF fpChange > -500 THEN
            pnt(1).radius = pnt(1).radius - 1 '                                far point changes
            fpChange = fpChange - 1
        END IF
    END IF
    IF _KEYDOWN(19712) THEN
        IF fpChange < 500 THEN
            pnt(1).radius = pnt(1).radius + 1
            fpChange = fpChange + 1
        END IF
    END IF
    IF _KEYDOWN(97) THEN adder = -.5 '                                                                  angle changes
    IF _KEYDOWN(100) THEN adder = .5
    IF _KEYDOWN(18432) THEN IF sizeFactor < 150 THEN sizeChange 1.01: sizeFactor = sizeFactor + .5 '    size changes
    IF _KEYDOWN(20480) THEN IF sizeFactor > -250 THEN sizeChange .99: sizeFactor = sizeFactor - .5
    IF _KEYDOWN(114) THEN adder = .2 '      r to rotate
    IF _KEYDOWN(115) THEN adder = 0 '      s to stop
    angle = angle + adder '                auto-spin
    IF angle > 359 THEN angle = 0 '        mind the angle
    IF angle < 0 THEN angle = 359

    PRINT "Angle:"; INT(angle)
    PRINT "Size Factor:"; sizeFactor
    PRINT "Far Point Change:"; fpChange
    PRINT
    PRINT "up arrow = ENLARGE SHIP"
    PRINT "down arrow = SHRINK SHIP"
    PRINT "left arrow = 'PULL' NOSE POINT"
    PRINT "right arrow = 'PUSH' NOSE POINT"
    PRINT "d = spin fast clockwise"
    PRINT "a = spin fast counterclockwise"
    PRINT "r = back to slow rotate"
    PRINT "s = stop rotation"
    PRINT "z = LEFT"
    PRINT "x = RIGHT"
    PRINT "c = UP"
    PRINT "v = DOWN"
    _DISPLAY
    _LIMIT 200
LOOP UNTIL _KEYDOWN(27)
SYSTEM
' ------------------------------------
SUB sizeChange (r AS SINGLE)
    DIM c AS INTEGER
    SHARED AS pnt pnt()
    FOR c = 1 TO UBOUND(pnt)
        pnt(c).radius = pnt(c).radius * r
    NEXT c
END SUB
' ------------------------------------
SUB drawStars () '                              starscape backdrop
    DIM c AS INTEGER
    DIM AS LONG virtual
    SHARED AS LONG starScape
    virtual = _NEWIMAGE(1280, 720, 32) '
    _DEST virtual
    c = 0
    DO
        c = c + 1
        PSET ((INT(RND * _WIDTH)), INT(RND * _HEIGHT)), _RGB32(200) '              whites
    LOOP UNTIL c = 2000 ' was 3600
    c = 0
    DO
        c = c + 1
        PSET ((INT(RND * _WIDTH)), INT(RND * _HEIGHT)), _RGB32(70) '                grays
    LOOP UNTIL c = 6000 ' was 3600
    c = 0
    DO
        c = c + 1
        PSET ((INT(RND * _WIDTH)), INT(RND * _HEIGHT)), _RGB32(255, 67, 55, 124) '  reddies
        DRAW "S2U1R1D1L1"
    LOOP UNTIL c = 26
    c = 0
    DO
        c = c + 1
        PSET ((INT(RND * _WIDTH)), INT(RND * _HEIGHT)), _RGB32(0, 255, 0, 116) '    greenies
        DRAW "S2U1R1D1L1"
    LOOP UNTIL c = 86
    c = 0
    DO
        c = c + 1
        PRESET ((INT(RND * _WIDTH)), INT(RND * _HEIGHT)), _RGB32(255, 255, 183, 120) '  big yellows
        DRAW "S4U1R1D1L1"
    LOOP UNTIL c = 130
    starScape = _COPYIMAGE(virtual, 32) ' software image
    _DEST 0
    _FREEIMAGE virtual
END SUB
' -----------------------------------------



RE: Poor Man's 3D Wire Frame - Pete - 07-04-2024

My guess is you inadvertently coded a black hole just off the left side of the screen, and your ship is spaghettifying.

It's a beautifully running program with that one exception, even though it doesn't take advantage of SCREEN 0.

Mark and a handful of others are real math giants, so I anticipate you'll get some useful help soon.

Pete


RE: Poor Man's 3D Wire Frame - bplus - 07-04-2024

Don't know why you are using _atan2 that is good for finding angle from one point and another so you would use _atan2(y1-y2, x1-x2) for the angle of point x1, y1 to point x2, y2 and vice versa for angle p2 to p1 = _atan2(y2-y1, x2-x1) in radians of course.

I converted back to what I consider normal sin and cos usage, maybe the ship looks better???

Code: (Select All)
For c = 1 To UBound(pnt) '                  rotate ship
        pnt(c).ang = pnt(c).ang + adder
        radians = _D2R(pnt(c).ang)
        pnt(c).x = pnt(c).radius * Cos(radians) + shipX ' ????  atan2 subbed for x/cos value spins in Y axis, neg for left side, pos for right
        pnt(c).y = pnt(c).radius * Sin(radians) + shipY ' ???? atan2 subbed for y/sin value spins in X axis, upside down, rightside up...
    Next c



RE: Poor Man's 3D Wire Frame - bplus - 07-04-2024

do you happen to have an image of a proper looking ship or sketch maybe?


RE: Poor Man's 3D Wire Frame - Pete - 07-04-2024

@bplus

Mark, do this.

1) Press the s key to stop it from spinning.

2) Keep pressing the z key and notice when it moves to the left, the size gets progressively squashed down.

It seems OK when moving from the center to the right with the x key, but the z key, which produces a ShipX = ShipX - 2 change each time it is pressed, is somehow messed up when used in the pnt(c).x = pnt(c).radius * Cos(radians) + shipx2 equation.

Edit: Just tried your math substitution. I think it changed the shape of the original ship, but it did solve the distortion effect when moving to the left.

Pete


RE: Poor Man's 3D Wire Frame - bplus - 07-04-2024

@Pete did you try what you told me to do with my mod, replace the _ATAN2 stuff in that little loop?
update: Smile

s then z just moves ship? off screen no deformities at all! then x moves it back into view still no deformities.

BTW there is a painting problem, I suspect the paint points are NOT moving with the ship and ship rotation.


RE: Poor Man's 3D Wire Frame - NakedApe - 07-04-2024

Thanks, @bplus  The rotation code you posted is what I started with, but I wanted to rotate the points along a different axis and I landed on ATAN2 which does exactly what I wanted - except for the screen location distortions. The "ship" is a 3D-ish view of the little triangular ship from my game, Rock Jockey. I attached the crude sketch that I made to find the points...


[Image: sketch.jpg]

The paint points are just for fun for now. The ATAN2 command takes the normally-rendered ship and "cracks its back" somehow. I like the weird shape, but I don't get what's really happening... And, yeh, there's no distortion when ATAN2 is removed and replaced with Sin(radians).


RE: Poor Man's 3D Wire Frame - bplus - 07-04-2024

OK you want to rotate on the z axis, thats allot of math if you also want fore-shortening I think it's called ie the closer sections to your POV the bigger the farther the smaller. But we might just need to swicth to 3d points and maintain lengths between points.

Do you want to go there? not sure I do, LOL


RE: Poor Man's 3D Wire Frame - NakedApe - 07-04-2024

Haha, no, I want the EZ, pea-brained method. I have a 3D graphics book, but I quickly got lost as the lessons got harder. ...And that's why I liked this little cheater of a program. Maybe I'll just stick to the "safe" right side of the screen where there's not much distortion, LOL. Thnx


RE: Poor Man's 3D Wire Frame - bplus - 07-04-2024

@NakedApe give this code a look see. It is constantly rotating over z axis, it's also painting panels pretty well. Easy pea brain plus method Smile you wouldn't need data for the points, they would be a square in a circle
Code: (Select All)
_Title "Diamond Spaceship" 'b+ 2022-07-23
' 2022-7-24 fixed panel problems and added PolyFill routine for rise and fall glowing

'spinning diamond mini-micro script in micro(A)
' from Aurel Micro A trans:  http://basic4all.epizy.com/index.php?topic=199.new#new

Screen _NewImage(800, 600, 32)
_ScreenMove 200, 0
Dim pi, p6, t, m, dir, glow, i, x, a, y, b, lx, ly, la, lb
pi = _Pi
p6 = pi / 6
t = 0
m = 400
dir = 1
glow = 50
Color _RGB32(200, 200, 240), _RGB32(0, 0, 0)
Dim As _Unsigned Long colr, edge
Dim poly(25)
edge = &H99AAAAFF
Do Until _KeyDown(27)
    Cls
    t = (t + 0.01)
    i = 0
    While i <= 12
        r = Cos(p6 * i + t + ao)
        x = m - 300 * r
        a = m - 250 * r
        y = 400 - 40 * Cos(p6 * (i - 3) + t + ao) - 140 + glow ' y
        b = y + 50
        Color _RGB32(200, 200, 240)
        Line (m, 100 - 140 + glow)-(x, y), edge
        Line (x, y)-(a, b), edge
        If i Mod 2 Then colr = &H220000FF Else colr = &H2200FFFF
        If i > 0 Then
            Line (a, b)-(la, lb), edge ' bottom disk
            Line (x, y)-(lx, ly), edge ' top disk
            ftri lx, ly, x, y, a, b, colr
            ftri a, b, la, lb, lx, ly, colr
            ftri m, 100 - 140 + glow, lx, ly, x, y, colr
        End If
        poly(2 * i) = a
        poly(2 * i + 1) = b
        lx = x: ly = y
        la = a: lb = b
        i = i + 1
    Wend
    glow = glow + dir
    If glow >= 256 Then dir = -dir: glow = 255
    If glow <= 49 Then dir = -dir: glow = 50
    PolyFill m, 450 - 140 + glow, poly(), _RGB32(200, 200, 255, glow)
    _Display
    _Limit 30
Loop

Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
    Dim D As Long
    Static a&
    D = _Dest
    If a& = 0 Then a& = _NewImage(1, 1, 32)
    _Dest a&
    _DontBlend a& '  '<<<< new 2019-12-16 fix
    PSet (0, 0), K
    _Blend a& '<<<< new 2019-12-16 fix
    _Dest D
    _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
End Sub

Sub PolyFill (xc, yc, poly(), K As _Unsigned Long) ' closed poly the last point repeats the first to close loop
    Dim i
    For i = LBound(poly) + 2 To UBound(poly) Step 2
        ftri xc, yc, poly(i - 2), poly(i - 1), poly(i), poly(i + 1), K
    Next
End Sub

You only have 4 points at base of pyramid instead of this 12 point base.
update see next reply!