Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Wanted: Very Simple 3D system
#1
By very simple I mean convert and x,y,z coordinate in 3D array to an x,y screen coordinate such that we sim a 3D
eg,
SUB Sim3D(xyzPointInFromArray, xyPointOutToScreenGraph)

Mainly we need this to use for _MapTriangle to wall cubes with triangles (2 per face)

I think there is some simple formula that does sin and/or cos with x combined with z and another for y combined with z.
b = b + ...
Reply
#2
Hey @bplus, I don't know if this is exactly what you are looking for or not, but I was reminded of this 3D library that someone in the QB64 community created:

https://github.com/creamcast/3D-Library-for-QB64

I haven't used it myself but it looks like it provides a relatively easy to use API that can load 3d objects and manipulate the camera more easily that using straight _MapTriangle or _gl* calls.
Reply
#3
+1 Great link, thanks @dbox

Wow look at those screen shots!

Yikes .bm alone 600+ LOC Dang, I was hoping for something simpler but I do see possibles there.
b = b + ...
Reply
#4
hello B+,

there are two options, the easiest is parallel projection and the trickier but more realistic one is perspective projection

say you have 3D coord variables x, y, z and you wish to convert them to 2D coords, lets call them p, q

for parallel:

p = x + 0.7*z
q = y + 0.7*z

where 0.7 is a kind of arbitrary number which you can mod until it looks right

for perspective

p = x * d/z
q = y * d/z

where d is like a field of vision value that corresponds to the relative distance between your eye and the monitor (the plane of projection) and getting these values correct requires a bit of math or a lot of modding -- consider an offset to prevent negative z or a division by zero.  I usually use the former to do something like a quick plot to get an idea and will mod my way to the latter for more serious mods.

see SUB proj in the following example
Code: (Select All)
defdbl a-z

const d = 300
const z0 = 550
const oy = 00

dim shared pi
pi = 4*atn(1)

dim x(5), y(5), z(5)
x( 0) =  0:  y( 0) = 70:  z( 0) =  0
x( 1) = 70:  y( 1) =-70:  z( 1) = 70
x( 2) =-70:  y( 2) =-70:  z( 2) = 70
x( 3) =-70:  y( 3) =-70:  z( 3) =-70
x( 4) = 70:  y( 4) =-70:  z( 4) =-70
x( 5) = 70:  y( 5) =-70:  z( 5) = 70

zoom = 4

sw = 640
sh = 480

screen _newimage(sw,sh,32)

a = 0
do
    cls

    a = a + 0.01

    xx = x(0)
    yy = y(0)
    zz = z(0)

    rot yy, zz, a
    rot xx, zz, a

    proj p0, q0, xx, yy, zz

    'draw all triangles
    for i=1 to 4
        x1 = x(i)
        y1 = y(i)
        z1 = z(i)

        rot y1, z1, a
        rot x1, z1, a
       

        x2 = x(i + 1)
        y2 = y(i + 1)
        z2 = z(i + 1)

        rot y2, z2, a
        rot x2, z2, a

        c = _rgb(35,35,35)

        proj p, q, x1, y1, z1
        pset (sw/2 + zoom*p0, sh/2 - zoom*q0 + oy), c
        line -(sw/2 + zoom*p, sh/2 - zoom*q + oy), c

        proj p, q, x2, y2, z2
        line -(sw/2 + zoom*p, sh/2 - zoom*q + oy), c
        line -(sw/2 + zoom*p0, sh/2 - zoom*q0 + oy), c
    next

    'draw the visible triangles
    for i=1 to 4
        x1 = x(i)
        y1 = y(i)
        z1 = z(i)

        rot y1, z1, a
        rot x1, z1, a

        x2 = x(i + 1)
        y2 = y(i + 1)
        z2 = z(i + 1)

        rot y2, z2, a
        rot x2, z2, a

        'vector cross product
        cz = (x1 - xx)*(y2 - yy) - (y1 - yy)*(x2 - xx)

        if cz > 0 then
            c = _rgb(255,255,255)

            proj p, q, x1, y1, z1
            pset (sw/2 + zoom*p0, sh/2 - zoom*q0 + oy), c
            line -(sw/2 + zoom*p, sh/2 - zoom*q + oy), c

            proj p, q, x2, y2, z2
            line -(sw/2 + zoom*p, sh/2 - zoom*q + oy), c
            line -(sw/2 + zoom*p0, sh/2 - zoom*q0 + oy), c
        end if
    next

    'draw the base
    xx = x(1)
    yy = y(1)
    zz = z(1)
    rot yy, zz, a
    rot xx, zz, a

    x1 = x(2)
    y1 = y(2)
    z1 = z(2)
    rot y1, z1, a
    rot x1, z1, a

    x2 = x(3)
    y2 = y(3)
    z2 = z(3)
    rot y2, z2, a
    rot x2, z2, a

    cz = (x1 - xx)*(y2 - yy) - (y1 - yy)*(x2 - xx)

    if cz < 0 then
        c = _rgb(255,255,255)
        proj p0, q0, xx, yy, zz
        pset (sw/2 + zoom*p0, sh/2 - zoom*q0 + oy), c
        for i=2 to 5
            xx = x(i)
            yy = y(i)
            zz = z(i)

            rot yy, zz, a
            rot xx, zz, a

            proj p, q, xx, yy, zz
            line -(sw/2 + zoom*p, sh/2 - zoom*q + oy), c
        next
    end if

    _display
    _limit 30
loop until _keyhit = 27
sleep
system

'rotate
sub rot(x, y, a)
    xx = x*cos(a) - y*sin(a)
    yy = x*sin(a) + y*cos(a)
    x = xx
    y = yy
end sub

'perspective projection
sub proj(p, q, x, y, z)
    dz = z0 + z
    p = x*d/dz
    q = y*d/dz

end sub
you can also use the same procedure to convert 4D coordinates into 2D! first project them down to 3D, then again down to 2D (see also example and SUB proj in this useful JB thread https://justbasiccom.proboards.com/threa...e-question )

speaking of maptriangle, its been on my backburner to translate that over to QBJS but I ran into a few brick walls due to my lack of JS (not JB) knowledge, mainly the image loading and webGL stuff, and kinda lost interest, but there has been some renewed interest in webGL in one of the math communities i'm into so I may give that another shot in the near future.  I was able to at least find the formula to match 3D to 2D coordinates 1:1 with QB64's maptri and can share that mod if there's interest
Reply
#5
+1 Thanks vince, you, dbox, MasterGy and ubi44 have given me plenty to ponder.
b = b + ...
Reply
#6
Thanks vince!  Great and concise explanation of Parallel Projection and Perspective Projection, and nice code to demo it!
Reply
#7
Hey @vince I started digging into your 128 LOC above. And i am trying to imagine the setup of this pyramid.

You explained d as distance eye is from monitor = projection screen.
what are z0, oy?
a is some rotation angle but whch way around like clock hands on wall, central axis of merry-go-round? or around x axis BTW where is origin for "real" and projected image?

Best way might to describe setup is a sheet of glass in front of model and we trace lines on the glass of what we see behind glass.
The other way is have model in front of projection screen and from eye point we draw lines from model points onto projection screen behind, ha! like see through shadows Smile

Is the pyramid in front of projection screen, behind it or split somewhere through plane of projection screen i am imaging vertical x, y like movie screen and actual object in from or back or split by screen.

The base would have all positive coordinates y = 0 at top y near height of screen a bottom the base
where are the negative numbers coming from here:
dim x(5), y(5), z(5)
x( 0) = 0: y( 0) = 70: z( 0) = 0
x( 1) = 70: y( 1) =-70: z( 1) = 70
x( 2) =-70: y( 2) =-70: z( 2) = 70
x( 3) =-70: y( 3) =-70: z( 3) =-70
x( 4) = 70: y( 4) =-70: z( 4) =-70
x( 5) = 70: y( 5) =-70: z( 5) = 70

also I put a Sleep command before the loop around command and looking at the very first appearance of our pyramid, something looks wrong! It is impossible to be real pyramid with square base:
   
b = b + ...
Reply
#8
Damn i thought I could sketch in Paint, my mistake I need a quick QB64 app.

If we are seeing bottom base of Pryramid the top line of base should be slightly longer than back parallel line at base bottom most and the right corner is top line not bottom, assuming the left lower corner is correct.

   

Smile
Code: (Select All)
_Title "Quick Sketch" ' b+ 2024-02-19

Screen _NewImage(800, 600, 32)
_ScreenMove 200, 60

Do
    While _MouseInput: Wend
    mb = _MouseButton(1): mx = _MouseX: my = _MouseY
    If mb Then PSet (mx, my)
    If InKey$ = "c" Then Cls
    _Limit 300
Loop Until _KeyDown(27)
b = b + ...
Reply
#9
Here's driving down a road at night. I just kinda fudged the 3D stuff.

Code: (Select All)
Dim x(200), y(200)
scr = _ScreenImage
Hpix = _Width(scr)
Vpix = _Height(scr)
_FreeImage scr
x(0) = 0
y(0) = 0
For i = 1 To 100
    x(i) = x(i - 1) + .4
    y(i) = y(i - 1) + .2
Next i
_Title "Telephone Poles"
Screen _NewImage(Hpix, Vpix, 12)
_FullScreen
Do While InKey$ <> Chr$(27)
    For i = 1 To 7
        Call Centerline(Hpix, Vpix)
        Call PoleLeft(x(i), Hpix, Vpix)
        Call PoleRight(y(i), Hpix, Vpix)
    Next i
    Call throttle
Loop
End

Sub throttle
    _Delay .07
End Sub

Sub Centerline (Hpix, Vpix)
    Line (Hpix / 2, Vpix / 2)-(.1 * Hpix, Vpix), 14
    Line (Hpix / 2, Vpix / 2)-(.125 * Hpix, Vpix), 14
    Line (Hpix / 2, Vpix / 2)-(0, .8 * Vpix), 7
    Line (Hpix / 2, Vpix / 2)-(Hpix, .8333 * Vpix), 7
End Sub

Sub PoleLeft (x, Hpix, Vpix)
    If x >= Hpix Then x = 5
    If x >= 0 Then
        a = Hpix / 2 - x
        b = Vpix / 2 - x / 2
        c = Vpix / 2 + x / 3
        d = Vpix / 2 - x / 3
        Line (a, b)-(a, c), 0
        Circle (a, (b + c) / 2), x / 35, 0
        Circle (a, (b + c) / 2), x / 45, 0
        Circle (a, (b + c) / 2), x / 55, 0
        Circle (a, (b + c) / 2), x / 65, 0
        Circle (a, (b + c) / 2), x / 75, 0
        Line (a - x / 8, b)-(a + x / 8, b), 0
        Line (a - x / 8, d)-(a + x / 8, d), 0
    End If
    x = x ^ 1.02 + .005
    If x >= 0 Then
        a = Hpix / 2 - x
        b = Vpix / 2 - x / 2
        c = Vpix / 2 + x / 3
        d = Vpix / 2 - x / 3
        Line (a, b)-(a, c), 8
        Circle (a, (b + c) / 2), x / 35, 15
        Circle (a, (b + c) / 2), x / 45, 15
        Circle (a, (b + c) / 2), x / 55, 15
        Circle (a, (b + c) / 2), x / 65, 15
        Circle (a, (b + c) / 2), x / 75, 15
        Line (a - x / 8, b)-(a + x / 8, b), 8
        Line (a - x / 8, d)-(a + x / 8, d), 8
    End If
End Sub

Sub PoleRight (x, Hpix, Vpix)
    Rem IF x >= Hpix THEN x = 6
    If x >= Hpix Then x = 4
    If x >= 0 Then
        a = Hpix / 2 + x
        b = Vpix / 2 - x / 2
        c = Vpix / 2 + x / 3
        d = Vpix / 2 - x / 3
        Line (a, b)-(a, c), 0
        Circle (a, (b + c) / 2), x / 35, 0
        Circle (a, (b + c) / 2), x / 45, 0
        Circle (a, (b + c) / 2), x / 55, 0
        Circle (a, (b + c) / 2), x / 65, 0
        Circle (a, (b + c) / 2), x / 75, 0
        Line (a - x / 8, b)-(a + x / 8, b), 0
        Line (a - x / 8, d)-(a + x / 8, d), 0
    End If
    x = x ^ 1.02 + .005
    If x >= 0 Then
        a = Hpix / 2 + x
        b = Vpix / 2 - x / 2
        c = Vpix / 2 + x / 3
        d = Vpix / 2 - x / 3
        Line (a, b)-(a, c), 8
        Circle (a, (b + c) / 2), x / 35, 12
        Circle (a, (b + c) / 2), x / 45, 12
        Circle (a, (b + c) / 2), x / 55, 12
        Circle (a, (b + c) / 2), x / 65, 12
        Circle (a, (b + c) / 2), x / 75, 12
        Line (a - x / 8, b)-(a + x / 8, b), 8
        Line (a - x / 8, d)-(a + x / 8, d), 8
    End If
End Sub
Reply
#10
(02-19-2024, 11:17 AM)bplus Wrote: Hey @vince I started digging into your 128 LOC above. And i am trying to imagine the setup of this pyramid.

You explained d as distance eye is from monitor = projection screen.
what are z0, oy?
a is some rotation angle but whch way around like clock hands on wall, central axis of merry-go-round? or around x axis BTW where is origin for "real" and projected image?

Best way might to describe setup is a sheet of glass in front of model and we trace lines on the glass of what we see behind glass.
The other way is have model in front of projection screen and from eye point we draw lines from model points onto projection screen behind, ha! like see through shadows Smile

Is the pyramid in front of projection screen, behind it or split somewhere through plane of projection screen i am imaging vertical x, y like movie screen and actual object in from or back or split by screen.

The base would have all positive coordinates y = 0 at top y near height of screen a bottom the base
where are the negative numbers coming from here:
dim x(5), y(5), z(5)
x( 0) =  0:  y( 0) = 70:  z( 0) =  0
x( 1) = 70:  y( 1) =-70:  z( 1) = 70
x( 2) =-70:  y( 2) =-70:  z( 2) = 70
x( 3) =-70:  y( 3) =-70:  z( 3) =-70
x( 4) = 70:  y( 4) =-70:  z( 4) =-70
x( 5) = 70:  y( 5) =-70:  z( 5) = 70

also I put a Sleep command before the loop around command and looking at the very first appearance of our pyramid, something looks wrong! It is impossible to be real pyramid with square base:
the object is behind the projection screen, so anything behind it is z > 0.  But having the requirement of z>0 can be annoying to work with so I add a z0 offset to allow for negative z for things like rotation, shifting the axis over so you can rotate around the x, y, or z axis without having to shift it over to the middle of the pyramid every time.  oy in this case looks to be another offset, to give it more of a top down view rather than a straight ahead which can look strange.  rot x, y, a will rotate points x and y around the z axis in the +a direction, you can call it counter clockwise or, more precisely, defer to the right hand rule
Reply




Users browsing this thread: 3 Guest(s)