← Back to Community
##### 3D Projection Tutorial
Profile icon
TurtleAndrew

I am going to teach you how to draw a 3D object.

I'm going to start with some useful information about the project bellow. First, it takes about 10 - 15 seconds to generate the map. Second, use WASD to move left, right, forward, and down and use space and right shift(not left shift) to go up and down.

To start, the only type math used in this tutorial is linear equations. You will still be able to use this tutorial and render your own 3D objects if you don't know linear equations but it may be more challenging and you likely won't understand how 3D projections work. Ok, now that were done with that, lets figure out how to project a 3D point onto a plane(a flat 2D surface). The reason I used the word project is because you take the point in 3D space, than you draw a line to the player's eye. From here you find the x and y point at z 80. Any position at z 80 is going to be referred to as the canvas. The number 80 after z would be represented by a variable player_fov aka the players field of view. This variable will be used in the equations. Than from there you would draw that point at that position on the screen. The way to sum that up would be your projecting a beam of light from a 3D point and seeing where it hits the players eye. Now lets get into the math that projects the object.

Here's a good image that helps shows what my program dose to project a vector3(x, y, z) point onto the canvas. The link to the website the image was taken from is right bellow the image and it also was the most helpful website for me when it came to learning how 3D projections work:

Computing the Pixel Coordinates of a 3D Point

And this gif further explains it:

Ray Tracing Basics

Step 1, the first step is to remove b(the y intercept) from the equation:

y = mx + b

This will make projecting the object easier. To do this I am going to use a few variables, object_x(the x position of the object), object_y(the y position of the object), object_z(the z position of the object) and player_x(the players x position), player_y(the players y position), player_z(the players z position). The outputs will be new_object_x, new_object_y, and new_object_z. Those outputs will be used in all the equations. Now onto the equation to remove b:

new_object_x = player_x - object_x
new_object_y = player_y - object_y
new_object_z = player_z - object_z

Step 2, now we will find the y position of collision on the canvas(defined at the top). The output will be screen_y and the variable m is the slope. The equation to do this is:

m = new_object_y / new_object_z
screen_y = m * player_fov + object_y

Step 3, this is the final step and gets the x position of collision on the canvas. The output will be screen_x and the variable m is the slope. The equation is:

m = new_object_x / new_object_z
screen_x = m * player_fov + object_x

If you don't want to write any code yourself than this is the code to project a 3D point written in python3:

```.css-19sk4h4{position:relative;}.css-1bu6gr6{-webkit-align-items:stretch;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;border-width:0;border-style:solid;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;outline:none;min-height:0;min-width:0;position:relative;}.css-1n2m10r{padding:var(--space-8);border-radius:var(--border-radius-4);background-color:var(--background-higher);}.css-1hwur6u{-webkit-align-items:stretch;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;border-width:0;border-style:solid;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;outline:none;min-height:0;min-width:0;padding:var(--space-8);border-radius:var(--border-radius-4);background-color:var(--background-higher);}.css-1svvr0w{height:0;}.css-1ubbl1f{padding:var(--space-4);padding-left:var(--space-4);padding-right:var(--space-2);font-family:var(--font-family-code);font-size:14px;line-height:var(--line-height-small);overflow-x:auto;word-break:break-word;white-space:break-spaces;overflow-wrap:anywhere;}```def convert_3D_to_2D(vec3_pos):
vec3_dist = [vec3_player_pos[0] - vec3_pos[0], vec3_player_pos[1] - vec3_pos[1], vec3_player_pos[2] - vec3_pos[2]]

try:
m = vec3_dist[1] / vec3_dist[2]
except ZeroDivisionError:
m = 0

y = m * player_fov + vec3_pos[1]

try:
m2 = vec3_dist[0] / vec3_dist[2]
except ZeroDivisionError:
m2 = 0

y2 = m2 * player_fov + vec3_pos[0]

return [y2, y]``````

You now are done with the math! And congratulations on finishing the tutorial! I hope this worked for you and if you have any questions or need help than feel free to ask in the comments.

Here's some images of a 3D map made using perline noise rendered using this 3D projection method and ran without a maximum render distance on my computer(not on repl):

And here's some more images of the world(not ran on repl) using my ray tracing lighting system that traces a ray from each point to the sun and check to see if it collides with anything. This feature is to slow for repl and will not be implemented. In this image I was getting around 0.3 fps:

The project bellow is the same code as used to create those images except repl runs pygame very slowly and therefore I had to implement a maximum render distance to allow you to move around the map in real time. Another feature in my project is a smoothish lighting system. Basically I subtract the height of one of the three points on the triangle being rendered from another. Than I used the clamp function shown bellow to limit how much darker or brighter an object could be. This function is also written in python3:

```.css-19sk4h4{position:relative;}.css-1bu6gr6{-webkit-align-items:stretch;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;border-width:0;border-style:solid;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;outline:none;min-height:0;min-width:0;position:relative;}.css-1n2m10r{padding:var(--space-8);border-radius:var(--border-radius-4);background-color:var(--background-higher);}.css-1hwur6u{-webkit-align-items:stretch;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;border-width:0;border-style:solid;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;outline:none;min-height:0;min-width:0;padding:var(--space-8);border-radius:var(--border-radius-4);background-color:var(--background-higher);}.css-1svvr0w{height:0;}.css-1ubbl1f{padding:var(--space-4);padding-left:var(--space-4);padding-right:var(--space-2);font-family:var(--font-family-code);font-size:14px;line-height:var(--line-height-small);overflow-x:auto;word-break:break-word;white-space:break-spaces;overflow-wrap:anywhere;}```def clamp(value, min_, max_):
return min(max(value, min_), max_)``````

After doing this I add the new value that I generated to the r, g, and b color before clamping each of the values to be within 0 - 255 using the same function shown above. I also have one more tip that may help, only draw a triangle if all of the three points x and y positions are grater than 0 otherwise there will be weird lines when you pass an object. One final feature in my program is a noise function. This creates the terrain that is rendered to the screen smoothly. First off, this is not an actual perline noise algorithm but it still creates smooth terrain. The way this function works on a basic level is it goes from the bottom left to the top right and on the way it gets the average height level of the terrain around it(If there is no terrain around it than it sets its height to a random value). It than choses a random value from a range of values till the value is a certain range(this range is random making the heights of the terrain even more random) away from the average terrain height. When it finds this height than it adds the height to a 2D array. I also added a chance to spawn a peak and if it dose than the height is forced to be a lot higher than the average creating a jump in the height of the terrain around it. That's all it takes to recreate the noise function. A tip to create a 3D game is to use a mesh(a list of shape positions that creates and object when rendered) and use a triangle as the shape it renders. Another useful tip is to order the terrain from top left to top bottom so when rendered the terrain will not overlap and create a weird visual bug. I will be updating this tutorial once I added in camera rotation so you to can look around you world at more angles than now. I have also started a ray tracer and have put the prototype on repl, the link is bellow. And finally, with all this new found information, you should be well enough equipped to create your own 3D game or game engine from scratch. Good luck!

Interesting facts:

There are 22500 polygons(triangles) in each map
There are 67500 vector3(x, y, z) points in the entire map

Good sources from learning more about 3D projections and the math behind it:

Voters
Profile icon
HBthePencil
Profile icon
KnowledgeCat247
Profile icon
BinhMinh12
Profile icon
BananaJellyfish
Profile icon
zakdakidd
Profile icon
tussiez
Profile icon
EpicRaisin
Profile icon
programmeruser
Profile icon
AkshataAmara
Profile icon
jeweled
hotnewtop
Profile icon
BananaJellyfish

i think you should try making one of your 3D projects into a full game

Profile icon
TurtleAndrew
Profile icon
BananaJellyfish

@TurtleAndrew im going to find out how to raycast so i can make cool things like you

Profile icon
TurtleAndrew

@BananaJellyfish I sent you those tutorials so dig in. It's not to hard but dose require some math.

Profile icon
BananaJellyfish

@TurtleAndrew nooo...my worst enemy lol

Profile icon
TurtleAndrew

@BananaJellyfish As long as you don't post it, you can copy my rays casting code and make your own levels under the "ray_casting_map.map" file. The tiles are 0: air, 1: tan wall thing, 2: stone brick wall, 3: next level door, 4: stone door, 5: wood wall, 6: wood door.

Profile icon
BananaJellyfish

@TurtleAndrew thanks, but i kinda want to make it with completely my own code. that will give me a greater sense of achievement

Profile icon
TurtleAndrew

@BananaJellyfish lol, understandable. It's just tan, invers tan, cos, sin, and lots of trig.

Profile icon
TurtleAndrew

@BananaJellyfish Thats grate! Just wanted to give you options. If you have questions about ray casting then feel free to ask and i will happily answer.

Profile icon
BananaJellyfish
Profile icon
TurtleAndrew

@BananaJellyfish Sorry, i didn't see the "you" (referring to me) but i have been trying to make a 3D game but pythons so slow its very hard. This is the closest I've come (the ray casting). I did make an isometric 3d game but it would run at 0fps on repl so thats out of the window.

Profile icon
BananaJellyfish

@TurtleAndrew ohh... yeah javascript is probably better if you want to make a complex raycasting game since you can open it in another tab. Take for example this: https://repl.it/talk/share/Wolfenstein-3D-style-raycaster-in-JavaScript/20166

Profile icon
TurtleAndrew

@BananaJellyfish That looks way better then mine! I would do a different language but I haven't been able to find an engine to render the output of it with.

Profile icon
BananaJellyfish

@TurtleAndrew yeah its better than anything i could do as well. however, i think you are nearly there!

Profile icon
TurtleAndrew

@BananaJellyfish Maybe. I know node JS but not java script and theres other factors. I know c# and am trying to figure out unity because that is an option. I'll figure it out some day and thats when I'll have a good and fast 3D game.

Profile icon
BananaJellyfish

@TurtleAndrew nice, tell me when you've made one!

Profile icon
TurtleAndrew

@BananaJellyfish I will. But it probably wont be soon.

Profile icon
BananaJellyfish

@TurtleAndrew well, while ur doing that i'll be practising raycasting

Profile icon
TurtleAndrew
Profile icon
TurtleAndrew

@BananaJellyfish It wont let me send an image on the comments of that project so heres the image of the cave rule:

Profile icon
BananaJellyfish

I dont get it, how is that a cave? I am very confused @TurtleAndrew

Profile icon
TurtleAndrew

@BananaJellyfish Zoom in and it is a bunch of rooms surrounded by walls. Think of it as if the blacks are walls and the whites are floors.

Profile icon
BananaJellyfish

Oh yeah, i see it now! Is this used in raycasting? @TurtleAndrew

Profile icon
TurtleAndrew
Profile icon
TurtleAndrew

@BananaJellyfish I generated the first level using it with a 50-50 distribution of blacks and whites. I did edit the level to add more chambers (some of which are connected with doors) but the main room/rooms were generated.

Profile icon
BananaJellyfish

The first level of what? Your raycaster game? @TurtleAndrew

Profile icon
TurtleAndrew

@BananaJellyfish Yes the ray casting game. I edited the comment above a little btw.

Profile icon
BananaJellyfish

@TurtleAndrew that's awesome! I think i need to do some more research and practice before i attempt a raycaster

Profile icon
TurtleAndrew

@BananaJellyfish I think you can do it.

Profile icon
BananaJellyfish

Thanks! i'm going to attempt it once my current project is done @TurtleAndrew

Profile icon
TurtleAndrew

@BananaJellyfish you also don't have to generate levels like that, its just that i had been experimenting with cellular automata at that time and was thinking it would make for a cool level.

Profile icon
TurtleAndrew

@BananaJellyfish sounds grate! Also those tutorials should help (the one i sent you earlier).

Profile icon
BananaJellyfish

Yeah, i think it will be better for me to start small with a simple raycasyer @TurtleAndrew

Profile icon
TurtleAndrew

@BananaJellyfish the flat colored version of mine is probably as simple as it gets so that should be a good starting point.

Profile icon
BananaJellyfish

Profile icon
TurtleAndrew
Profile icon
TurtleAndrew

@BananaJellyfish I've spent a few more hours optimizing the ray caster. I can now run it at 30fps on a res of 1 with textures on my desktop. I only get 32 with out textures so textures are very optimized. I also added much better lighting, theres four different light levels for the four sides of the walls.

Profile icon
BananaJellyfish

@TurtleAndrew have you updated it on repl as well?

Profile icon
TurtleAndrew
Profile icon
TurtleAndrew

@TurtleAndrew its faster at rendering textures by a lot.

Profile icon
BananaJellyfish

Wow, awesome! I can't check it out right now, but i will soon @TurtleAndrew

Profile icon
jeweled

Really cool would be an understatement for this! Amazing job!

Profile icon
TurtleAndrew

@jeweledfox Thanks!

Profile icon
Highwayman

I’m crying you make it sound so easy why did I never learn this

Profile icon
TurtleAndrew

Its not easy, it took me like ten hours. I can help you learn how to do it if you want. Also, during the ten hours the funniest thing happened and when I move to the left the entire world would become a burrito. It took like 2 hours to fix.

Profile icon
TurtleAndrew

@Highwayman I'm still working on a bug where when you go bellow the ground the ground flips upside down and comes to the player. I'm also working on a ray tracer that is taking years to run.

Profile icon
TurtleAndrew

@Highwayman I've also been working on a new lighting system that took like 4 hours because it uses ray tracing, obviously ray tracing is not possible in real time on repl.

Profile icon
Highwayman

Lol a burrito 😂 I kinda wanna see that.
I can help you with the speed problems. I can take your calculations and transfer them into C++ imported functions so that it runs faster, that might help. It’d be interesting to see how that worked out.
Also yeah! That would be cool!
@TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman That would work, the main reason it's slow is I'm using ".index" and "in" on a list of objects which is super slow. I need to find a faster method of detecting collision. The tracing of the rays is super fast, I used the ray tracer using a different collision detection method for lighting on the 3D projections program and it still runs well. I did not add it to the one on repl.

Profile icon
TurtleAndrew

@Highwayman I dont have any images of it being a full burrito but here's an image of it starting to turn into a burrito.

Profile icon
TurtleAndrew

@TurtleAndrew fyi that was a flat square not curved.

Profile icon
TurtleAndrew

@TurtleAndrew fyi that was a flat square not curved.

Profile icon
TurtleAndrew

@Highwayman Also, the ray tracing light system doesn't take 4 hours to run, it took that long to make.

Profile icon
TurtleAndrew

@TurtleAndrew Here's what that lighting system looks like.

Profile icon
Highwayman

Looking at the burrito beginnings like oh no here we go lol.
Ohh I was confused ye I did think you meant how long it was running like a hyperbole.
Aye that’s nice, it also has a lot more color it seems?
@TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman That was a very old image.

Profile icon
Highwayman

Ope really I think I’m forgetting things oops 😬 @TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman its all good. I also did fix the burritoing. It would go full burrito. I dont have that old code or any more images of the burritoing.

Profile icon
TurtleAndrew

@Highwayman I just got reflections working on my ray tracer.

Profile icon
TurtleAndrew

@TurtleAndrew I also fixed a mathematical error and am running it again. I was averaging colors and added 5 and only divided by 3 not five.

Profile icon
TurtleAndrew

@TurtleAndrew i do know how to add the burritoing back in i think

Profile icon
TurtleAndrew

@TurtleAndrew It worked but didnt because of other changes, i just needed to make one of the 1D lines 3D

Profile icon
Highwayman

Wait so you can just make it burrito now whenever like hey XP
Ya know I never fully understood what ray tracing is for, cause it’s like some people are telling me it simulates gravity basically and others are like it’s just f’ing graphics deal with it and others... well yeah, hard to get a handle of lol.
Oof reminds me of my last math test lol I forget exactly what I did, but I do remember that I did like 2+3 = 7 or something ridiculous like that and my teacher was like where is your logic, da.

@TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman For ray tracing, you baiscaly cast rays for each pixel on the screen from the player and see where it collides, here some links that may help you understand how it works:

Profile icon
TurtleAndrew

@Highwayman I can kind of make it burrito whenevere but i made a change at some point that will stop it from going full burrito. I basically need to make a 1D line a 3D line using the Pythagorus theorem.

Profile icon
TurtleAndrew

@Highwayman I can teach you the math for ray tracing and 3D projections, they are really similar btw.

Profile icon
TurtleAndrew

@TurtleAndrew Also, ray tracing doesn't simulate gravity but it dose simulate light allowing for reflections, refractions, and transparency. It also takes like a year to run :(. I still have to wait like 30 more minutes for it to run with fixed reflections.

Profile icon
TurtleAndrew

@TurtleAndrew This gif might help, its from this website:

Profile icon
TurtleAndrew

@TurtleAndrew Also, sorry but i never had the burritoing happen with my ray tracer. Just think though how cool it would be if it did happen on my ray tracer.

Profile icon
Highwayman

Lol a burrito if Ray tracer. The reflections just start lifting off the ground 😜
That gif was super helpful, ye!
Makes sense I was a little skeptical when they said they were using it to simulate gravity lol.
They seems to be ye because that gif is kinda looking like what you talked about in the tutorial ye that’sbe interesting.

@TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman Yes, the tutorial is explaining that image and also going over the math to do what the image dose. If i can find the math to make a burrito shape than i could ray trace a burrito with refection and all. But the requires finding the outside points on a flattened circle.

Profile icon
TurtleAndrew

@Highwayman Also here's the most recent render from my ray tracer including two mirrors and two walls:

Profile icon
Highwayman

It seems to be coming along quite smoothly, not counting the burrito of course XD @TurtleAndrew

oof wow I haven't been on repl.it for a MONTH

Profile icon
TurtleAndrew

@Highwayman Yes it is. I also finished the ray tracer and created a ray marcher which is the same thing but uses more math so it can run quicker. Also on the ray marcher you can move your camera around and it gets 60fps(this is only the one i programed on c++ the one on python takes 2 minutes to load because python is slow)

Profile icon
Highwayman

Haha yup that’s python for you lol.
Is that just because you only added the moving camera feature to the ray marcher or is it because the ray caster just can’t handle it?
@TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman It's because the ray marcher is the only one i also made on c++ and c++ is like 10000000000000 time quicker than python.

Profile icon
Highwayman

Makes sense. @TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman I know its been a while scenes the burritoing but i was searching trough image backups and within the same backup that had the burritoing image there was an image of the projection code. That may be the code that caused the burritoing. I also thought of this and just in case you wanted to try it out heres the code. No promises it contains the glitch:

Profile icon
Highwayman

XD "since the burritoing" kinda got me lol, awesome! thanks :P @TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman How well do you know c++ and python3? Im wondering because im working on a python3 to c++ compiler. The issu is its really hard to do so im looking for some people to work with on the project. You can find out more about it on the post i put up replit.com

Profile icon
Highwayman

I am pretty well versed in C++, but python...not so much. I know enough to be of a help to the newbs in ask, but not much more. @TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman Its not complicated python3 (for the compiler) so if you think you can do it then i'll happily work on the project with you.

Profile icon
Highwayman

mm... I really want to say yes, but my level of availability on this website is practically nil right now; it generally is during the school year now, and especially at the end of a quarter, and it's just gonna end with me disappointing everybody.
That being said, if this is still happening and I have some sort of holiday break/it's summer, then I..might..ping..you? You'll probably be fare along by then though. :/ ack. group projects and me don't seem o ever work out :(
@TurtleAndrew

Profile icon
TurtleAndrew

@Highwayman Thats all good. It's just a massive project and i dont have anyone to help yet. If it continues into the summer (which it probably will) then your free to help out, no matter how far along the project is.

Profile icon
Highwayman

Sounds good! compilers are cool. @TurtleAndrew

Profile icon
EpicGamer007

Even though this is python, this is still really cool! Nice!

Profile icon
TurtleAndrew