Last active
October 19, 2016 12:00
-
-
Save KeyMaster-/a9aaf9f9ef53b6fab7beaa5b213a4b8a to your computer and use it in GitHub Desktop.
A quick luxe program to demonstrate manual perspective projection of a rotating pyramid.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import luxe.GameConfig; | |
import luxe.Input; | |
import luxe.Vector; | |
class Main extends luxe.Game { | |
//--- The actual important stuff -- | |
var verts:Array<Vector>; //Holds the '3D model' vertices, i.e. actual 3D coordinates | |
//The setup function, this runs once at the start of the game | |
override function ready() { | |
verts = []; | |
//4 bottom verts | |
//Replace this with the 3 bottom vertices of a triangle to form a tetrahedron (and also adjust what lines are drawn in update) | |
//Remember that positive z goes down the screen, so larger z is further down | |
verts.push(new Vector(0.5, 0.5, 0.5)); //right, far | |
verts.push(new Vector(0.5, 0.5, -0.5)); //right, near | |
verts.push(new Vector(-0.5, 0.5, -0.5)); //left, near | |
verts.push(new Vector(-0.5, 0.5, 0.5)); //left, far | |
//Top vert | |
verts.push(new Vector(0, -0.5, 0)); | |
} //ready | |
//Our accumulated running time, for the rotation | |
var time:Float = 0; | |
override function update(delta:Float) { | |
time += delta; | |
var transformed = []; //Our vertices, transformed to screen space | |
for(i in 0...verts.length) { | |
var transformed_vert = verts[i].clone(); | |
var angle = time * Math.PI; | |
//The 2D rotation matrix around the y-axis (i.e. along the x-z plane) | |
transformed_vert.x = Math.cos(angle) * verts[i].x - Math.sin(angle) * verts[i].z; | |
transformed_vert.z = Math.sin(angle) * verts[i].x + Math.cos(angle) * verts[i].z; | |
transformed_vert.z += 2; //Push the whole model away from our "camera" at 0,0, into the screen | |
//This is the perspective projection. | |
//Objects far away have a higher z coordinate, and thus get scaled towards the center of the projection (right now, that's the 0,0 point) | |
transformed_vert.x /= transformed_vert.z; | |
transformed_vert.y /= transformed_vert.z; | |
transformed_vert.multiplyScalar(Luxe.screen.w / 2); //Scale up the resulting projected position to be actually visible on screen. This value is kinda arbitrary | |
transformed_vert.add(Luxe.screen.mid); //Currently, our model is centered around 0,0. This moves it to the center of the screen. | |
transformed_vert.z = 0; //This is in screenspace, so there should be no z. (Necessary for my rendering, if you just pass x/y directly z doesn't matter) | |
transformed.push(transformed_vert); | |
} | |
//Draw the 4 base verts | |
draw_line(transformed[0], transformed[1]); | |
draw_line(transformed[1], transformed[2]); | |
draw_line(transformed[2], transformed[3]); | |
draw_line(transformed[3], transformed[0]); | |
//Draw the 4 lines to the peak | |
draw_line(transformed[0], transformed[4]); | |
draw_line(transformed[1], transformed[4]); | |
draw_line(transformed[2], transformed[4]); | |
draw_line(transformed[3], transformed[4]); | |
} //update | |
function draw_line(p0:Vector, p1:Vector) { | |
Luxe.draw.line({ | |
p0:p0, | |
p1:p1, | |
immediate:true | |
}); | |
} | |
//--- Luxe specific setup. --- | |
override function config(config:GameConfig) { | |
config.window.title = 'luxe game'; | |
config.window.width = 960; | |
config.window.height = 640; | |
config.window.fullscreen = false; | |
return config; | |
} //config | |
override function onkeyup(event:KeyEvent) { | |
if(event.keycode == Key.escape) { | |
Luxe.shutdown(); | |
} | |
} //onkeyup | |
} //Main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment