Page 1 of 1
How does 3d math work?
Posted: Fri Sep 18, 2009 11:23 am
by Trond
I don't know anything about 3d math except I know about the basic coordinate system. I made this starfield from a tutorial, and it's pretty cool. Unfortunately, I don't get how it works (specifically, the world-to-screen coordinate transformation procedure). So I was wondering if anyone would care to explain it to me? Please, in a simple fashion!
Code: Select all
Structure PT3
x.f
y.f
z.f
EndStructure
Structure iPT2
x.i
y.i
EndStructure
Global Eye.PT3
Eye\x = 512
Eye\y = 384
Eye\z = 30
Procedure Cam2Scr(*Cam.PT3, *Scr.iPT2)
If *Cam\z > 0
; These two lines works wonders, and how/why is a complete mystery to me.
*Scr\x = eye\x + *Cam\x * eye\z / (*Cam\z + eye\z)
*Scr\y = eye\y - *Cam\y * eye\z / (*Cam\z + eye\z)
ProcedureReturn 1
EndIf
*Scr\x = -1
*Scr\y = -1
EndProcedure
If InitSprite() = 0
MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
End
EndIf
OpenWindow(0, 0, 0, 1024, 768, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Invisible)
OpenWindowedScreen(WindowID(0), 0, 0, 1024, 768, 0, 0, 0)
HideWindow(0, 0)
NewList Stars.PT3()
Macro sxy
Stars()\x = -1000+Random(2000)
Stars()\y = -1000+Random(2000)
EndMacro
For I = 0 To 400
AddElement(Stars())
Stars()\z = Random(255)
sxy
Next
Repeat
Repeat
Event = WindowEvent()
Select Event
Case #PB_Event_CloseWindow
End
EndSelect
Until Event = 0
FlipBuffers()
ClearScreen(RGB(0, 0, 0))
StartDrawing(ScreenOutput())
ForEach Stars()
Cam2Scr(@Stars()\x, @p.iPT2)
If p\x >= 0 And p\x < 1024 And p\y >= 0 And p\y < 768
Col = 255-(Stars()\z)
Col = RGB(col, col, col)
Plot(p\x, p\y, Col)
Stars()\z - 1
Else
DeleteElement(Stars())
AddElement(Stars())
Stars()\z = 255
sxy
EndIf
Next
StopDrawing()
Delay(10)
ForEver
Re: How does 3d math work?
Posted: Fri Sep 18, 2009 12:49 pm
by Kaeru Gaman
a lot of this, including the projection, is really well explained in the POV-Ray documentation.
www.povray.org
helped me to understand much of the basics.
Re: How does 3d math work?
Posted: Fri Sep 18, 2009 1:06 pm
by Trond
Are you sure? I can't find anything about the actual formula, only the concept is explained, and I already understand that, I just can't relate it to the formula.
Re: How does 3d math work?
Posted: Fri Sep 18, 2009 1:14 pm
by Kaeru Gaman
oh.. could be, it's a while ago I worked thru it.
sorry.
what you need to transform a 3D-vector into a 2D-vector is a "Matrix".
http://en.wikipedia.org/wiki/Matrix_(mathematics)
the Values the Matrix needs to contain are directly dependant of scale and projection...
sorry I can't help you much further...
Re: How does 3d math work?
Posted: Fri Sep 18, 2009 7:22 pm
by Demivec
@Trond: Here's a simple explanation.

I'll rewrite the formulas to use different variable names.
Code: Select all
x = x1 + x2 * (z1 / (z2 + z1))
y = y1 + y2 * (z1 / (z2 + z1))
(x,y) is the screen position. (x1,y1,z1) are the eye (or typically camera position). (x2,y2,z2) are the object position (which you call Cam).
Both the 'x' and 'y' position of the object are scaled by the combined 'z' position of the eye and the object and then added to the eye position for the 'x' and 'y'.
This means that the farther away something is (greater 'z') the smaller the change it will cause in the original 'x' and 'y' of the eye position.
If the 'z' value was ignored for both the object and the eye position for instance the equations would reduce to:
This would show the object's position without being scaled before it is added to the eye position. You can try this out in your code sample by simply commenting out the remainder of the formula. It will show all the stars with their varying brightnesses but without the benefit of depth distortion.
If you want to increase the distortion (or foreshortening effect for depth) just put a multiplier in the divisor portion of the formulas (i.e. 'x = x1 + x2 * (z1 / (M * z2 + z1))' where M = the multiplier) to create a tunnel like effect. If the multiplier is greater than one it increased the effect, if less than one it decreases it. Fifty is one that I like. It will also expose the fact that your start world isn't very wide or tall when its depth seems to be increased.
Just for fun, if you wanted to make the eye position move place this line before the delay. It will cause a shaking or jittering effect.
Code: Select all
Eye\x + 1 - Random(2): Eye\y + 1 - Random(2)
Re: How does 3d math work?
Posted: Fri Sep 18, 2009 10:13 pm
by Trond
Thank you very much, Demivec, I will read it thoroughly tomorrow, it seems like I can understand it with your help.
Re: How does 3d math work?
Posted: Fri Sep 18, 2009 10:31 pm
by utopiomania
Check out 'Donald E Knuth - The Art of Computer Programming' Algo heaven.

Re: How does 3d math work?
Posted: Sat Sep 19, 2009 6:17 am
by Demivec
@Trond: I thought I would just post a small modification to your original code sample.
I renamed a few of the variables for clarity and modified one of the structures. I implemented a dynamic depthChangeRate for a simple special effect. Press SpaceBar to activate it and it runs until it completes before it can be activated again. It was fun to do and I thought it might give you some variations of the formulas for comparison. I also got to test out the new timer functions.
Code: Select all
Structure PT3
x.f
y.f
Z.f
px.i
py.i
EndStructure
Structure iPT2
x.i
y.i
EndStructure
Global Cam.PT3
Cam\x = 512
Cam\y = 384
Cam\Z = 30
Procedure obj2Scr(*obj.PT3, *Scr.iPT2)
If *obj\Z > 0
*Scr\x = Cam\x + *obj\x * Cam\Z / (*obj\Z + Cam\Z)
*Scr\y = Cam\y - *obj\y * Cam\Z / (*obj\Z + Cam\Z)
ProcedureReturn 1
EndIf
*Scr\x = -1
*Scr\y = -1
EndProcedure
If InitSprite() = 0
MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
End
EndIf
If InitKeyboard() = 0
MessageRequester("Error", "Can't initialize Keyboard input!", 0)
End
EndIf
OpenWindow(0, 0, 0, 1024, 768, "Press [Space] for special effect", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Invisible)
OpenWindowedScreen(WindowID(0), 0, 0, 1024, 768, 0, 0, 0)
HideWindow(0, 0)
NewList Stars.PT3()
Macro sxy
Stars()\x = -2000+Random(4000)
Stars()\y = -2000+Random(4000)
EndMacro
For i = 0 To 400
AddElement(Stars())
Stars()\Z = Random(255)
sxy
Next
Define depthChangerate = 1 ;this will be subtracted from the Z depth each frame
Define Msg$ ;this will be text that is displayed over the star background
Repeat
Repeat
event = WindowEvent()
Select event
Case #pb_event_timer
Select EventTimer()
Case 10 ;Hyperspace ramp-up
If depthChangerate < 20
depthChangerate + 1
AddWindowTimer(0,10,time * 0.90)
Else
RemoveWindowTimer(0,10)
AddWindowTimer(0,45,time * 10)
AddWindowTimer(0,40,500)
time = 500
EndIf
Case 15
Msg$ = "Hyperspace Travel Activated"
RemoveWindowTimer(0,15)
Case 40 ;Hyperspace ramp-down
If depthChangerate > 1
depthChangerate - 1
AddWindowTimer(0,40,time * 1.1)
Else
RemoveWindowTimer(0,40)
Msg$ = ""
inHyperspace = #False
EndIf
Case 45
Msg$ = "Disengaging Hyperspace Travel"
RemoveWindowTimer(0,45)
EndSelect
Case #PB_Event_CloseWindow
End
EndSelect
Until event = 0
FlipBuffers()
ClearScreen(RGB(0, 0, 0))
StartDrawing(ScreenOutput())
ForEach Stars()
obj2Scr(@Stars()\x, @p.iPT2)
If p\x >= 0 And p\x < 1024 And p\y >= 0 And p\y < 768
Col = 255-(Stars()\Z)
Col = RGB(Col, Col, Col)
Plot(p\x, p\y, Col)
If Stars()\px + Stars()\py <> 0 And inHyperspace
LineXY(Stars()\px,Stars()\py,p\x,p\y,Col)
EndIf
Stars()\px = p\x
Stars()\py = p\y
Stars()\Z - depthChangerate
Else
DeleteElement(Stars())
AddElement(Stars())
Stars()\Z = 255
sxy
EndIf
Next
If Msg$ <> ""
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(512 - TextWidth(Msg$) / 2,700,Msg$,#Green)
EndIf
StopDrawing()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Space) And Not inHyperspace
inHyperspace = #True
time = 500
Msg$ = "Engaging Hyperspace Travel"
AddWindowTimer(0,15,time * 10)
AddWindowTimer(0,10,time)
EndIf
Delay(10)
ForEver
@Edit: added InitKeyboard() and Title to window that contains directions.
Re: How does 3d math work?
Posted: Sat Sep 19, 2009 9:35 pm
by jack
nice example Demivec, I just had to add a InitKeyboard() before the Repeat..Forever loop.
Re: How does 3d math work?
Posted: Sun Sep 20, 2009 2:35 am
by Demivec
jack wrote:nice example Demivec, I just had to add a InitKeyboard() before the Repeat..Forever loop.
@Jack: Thanks, I always try to stop before I go too far. Even so, I still managed to end up in outer space...
The code functioned fine for me without the InitKeyboard(). I only received a warning when I used the debugger. I didn't do that while coding it and so I hadn't noticed it. Thanks for bringing it to my attention.
Code in previous post edited to correct the omission.