Computer Science Canada

Will this 3d plotting procedure work?

Author:  richcash [ Tue Aug 15, 2006 5:44 pm ]
Post subject:  Will this 3d plotting procedure work?

Well, I've been trying to figure out the best way to plot 3d points on a 2d screen, and I was directed to this page by Delos and [Gandalf].
http://freespace.virgin.net/hugo.elias/routines/3d_to_2d.htm
(I'm not really working on this right now, but it's good to know for when I do.)
Well, there were some variable names used on that web site that I didn't really understand, and no one could seem to explain them to me. (For my original topic and more background info : http://www.compsci.ca/v2/viewtopic.php?t=13184)

However, looking at Catalyst's 3d particle engine, I derived this procedure from it and it seems to work for plotting 3d points. I'm not too sure if it works accurately though, so if anyone can tell me if this works or not (maybe it doesn't always work?).

code:
var Camx, Camy, Camz, CamzFrame : int
proc DrawParticle (x, y, z : int)
    var xD, yD : int
    if z < Camz then
        xD := round ((CamzFrame - (z - (((z - Camz) / ((x - Camx) + 0.001)) * x))
            / ((z - Camz) / ((x - Camx) + 0.001))))
        yD := round ((CamzFrame * ((y - Camy) / ((z - Camz) + 0.001))) + (y -
            (((y - Camy) / ((z - Camz) + 0.001)) * z)))
    end if
    drawdot (xD, yD, 7)
end DrawParticle


Also, on an unrelated note, if I have 3d structures connected by points, how can I avoid drawing everything behind the structure (for optimization).

Author:  Windsurfer [ Tue Aug 15, 2006 8:32 pm ]
Post subject: 

It does work, but it's very complex. Start off from the simple stuff first. The basis of this type of 3D -> 3D proc is this:
code:

var draw_x : int := x div z
var draw_y : int := y div z


Yes, it's that simple. Divide X and Y by Z.
Well, to begin with.
Then you have to add everyhting else in, like making the camera centered, rotating it, adjustments for Field-of-view, ect.

For a slightly more simplified version of this (and perhaps more usable? i don't know) I came up with a function that converts 3D stuff. I created all this from scratch, btw, so it may be wrong in some ways.

code:


%this is the size of the screen
% i suppose i could have used maxx and maxy instead.
const X_SCREEN := 1024
const Y_SCREEN := 768

%middle of the screen in the X and Y axis so that the camera is centered
    const SCR_W := X_SCREEN div 2
    const SCR_H := Y_SCREEN div 2

    %this is the "key dividor" amount... it makes something at a z coordinate
    %perfectly align with the screen... just don't touch it
    %I got to this value by experimentation
    const Z_KEY_DIV := 350

var rotate_x, rotate_y, rotate_z : real := 0
var camera_pan_x, camera_pan_y, camera_pan_z : real := 0



%this rotates a 3D point( x1, y1, z1) around another point (origin) by a cetain number of degrees in each axis (xy, zy, zx).
%Keep in mind that this modifies the point. (uses var)
    procedure Rotate_Point_3D (var x1 : real, var y1 : real, var z1 : real,
            origin_x, origin_y, origin_z, xy, zy, zx : real)

        var temp_x : real := x1 - origin_x
        var temp_y : real := y1 - origin_y
        var temp_z : real := z1 - origin_z

        % zx plane
        x1 := temp_x * cosd (zx) - temp_z * sind (zx) + origin_x
        z1 := temp_x * sind (zx) + temp_z * cosd (zx) + origin_z



        temp_x := x1 - origin_x
        temp_z := z1 - origin_z

        % zy plane
        z1 := temp_z * cosd (zy) - temp_y * sind (zy) + origin_z
        y1 := temp_z * sind (zy) + temp_y * cosd (zy) + origin_y


        temp_z := z1 - origin_z
        temp_y := y1 - origin_y

        % xy plane
        x1 := temp_x * cosd (xy) - temp_y * sind (xy) + origin_x
        y1 := temp_x * sind (xy) + temp_y * cosd (xy) + origin_y
    end Rotate_Point_3D


%this converts a 3D point into a 2D one and returns true if the conversion was successful
%xt and yt are the 2D coordinates
    function Make3D (x1, y1, z1 : real, var xt, yt : int) : boolean

%create duplicate variables of the point and pan it
        var x2 : real := x1 + camera_pan_x
        var y2 : real := y1 + camera_pan_y
        var z2 : real := z1 + camera_pan_z

        Rotate_Point_3D (x2, y2, z2, SCR_W, SCR_H, 0, rotate_x, rotate_y, rotate_z)
        if z2 > 1 then
            xt := round ((x2 - SCR_W) / (z2 / Z_KEY_DIV) + SCR_W)
            yt := round ((y2 - SCR_H) / (z2 / Z_KEY_DIV) + SCR_H)
            result true %3d was successful
        else
            xt := 100
            yt := 100
            result false %3d was not successful
        end if
    end Make3D


This is fun because if you want to draw a black dot at a point, say 500,500,0, you just make a proc that does this:

code:

var temp_x, temp_y : int
if Make_3D(500,500,0, temp_x, temp_y) then
drawdot(temp_x, temp_y, black)
end if

note: untested.

Simple, no? All rotations and panning is taken care of. Of course, there is then dealing with madifying the values accociated with that... maybe i should make a tutorial on this, considering so many people are interested... or maybe there already is one? hmm.....

Author:  richcash [ Tue Aug 15, 2006 10:40 pm ]
Post subject: 

Thanks, Windsurfer, you explained it very well. It seems to work great. Now, when I need to use 3d I'll just have to learn how to use your system to rotate and move the camera. As I said, I'm not really working on this just yet.

A tutorial would be great if we don't already have one, I think 3d is an interesting thing that is possible in Turing, but not too many people end up working with it!

Author:  iker [ Wed Aug 16, 2006 12:14 pm ]
Post subject: 

I've found this semi-simple algorithm to rotate a point in Zylums 3D engine, but had to refine it a bit to work for the 3d project I'm working on. This rotates the points from the camera's POV. pntX, pntY and pntZ are the original xyz points, then rotX, rotY, rotZ are the xyz points. xR yR and zR are the angles of rotation (0 .. 359). I haven't 100% figured out whats going on, but what I do know is that Zylum used 3D addition. Hopefully this helps, maby if someone wanted to expand on it a bit.
code:

rotY := pntY  * cosd (yR) - pntZ * sind (yR)
rotZ := pntZ  * cosd (yR) + pntY  * sind (yR)
temp := rotZ
rotZ := temp * cosd (xR) - pntX * sind (xR)
rotX := pntX * cosd (xR) + temp * sind (xR)
temp := rotX
rotX := temp * cosd (zR) - rotY * sind (zR)
rotY := rotY * cosd (zR) + temp * sind (zR)
pntX := rotX
pntY := rotY
pntZ := rotZ

Author:  richcash [ Wed Aug 16, 2006 2:38 pm ]
Post subject: 

That's a fairly good algorithm, iker, I really like how you're rotating in 3 dimensions (or at least I think so). Perhaps I could combine yours and Windsurfer's, though they are very similar. I didn't even know zylum made a 3d particle engine, now I have more resources! I think I'm finally understanding these types of systems and the mathematics behind them, thanks for your input!

Author:  Windsurfer [ Wed Aug 16, 2006 9:17 pm ]
Post subject: 

richcash wrote:
That's a fairly good algorithm, iker, I really like how you're rotating in 3 dimensions (or at least I think so). Perhaps I could combine yours and Windsurfer's, though they are very similar.


Yes, they are very similar... in fact, i think they're the same, apart from the fact that mine rotates around an origin, and not just (0,0,0).


: