Last active
May 7, 2022 14:57
-
-
Save amirrajan/20aa5ae329035ac8439beeb49fecff4b to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit: Loading an OBJ file and rendering triangles.
This file contains hidden or 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
def tick args | |
args.grid.origin_center! | |
args.state.triangles ||= read_obj 'models/mario.obj' | |
movement_multiplier = 1000 | |
args.outputs.labels << { x: 0, | |
y: 30.from_top, | |
text: "W,A,S,D to move. Mouse to look. Triangles is a Indie/Pro Feature and will be ignored in Standard.", | |
alignment_enum: 1 } | |
args.state.cam_y ||= 0.00 | |
if args.inputs.keyboard.i | |
args.state.cam_y += 0.01 | |
elsif args.inputs.keyboard.k | |
args.state.cam_y -= 0.01 | |
end | |
args.state.cam_angle_y ||= 0 | |
if args.inputs.keyboard.q | |
args.state.cam_angle_y += 0.25 | |
elsif args.inputs.keyboard.e | |
args.state.cam_angle_y -= 0.25 | |
end | |
args.state.cam_angle_x ||= 0 | |
if args.inputs.keyboard.u | |
args.state.cam_angle_x += 0.1 | |
elsif args.inputs.keyboard.o | |
args.state.cam_angle_x -= 0.1 | |
end | |
if args.inputs.mouse.has_focus | |
y_change_rate = (args.inputs.mouse.x / 640) ** 2 | |
if args.inputs.mouse.x < 0 | |
args.state.cam_angle_y -= 0.8 * y_change_rate | |
else | |
args.state.cam_angle_y += 0.8 * y_change_rate | |
end | |
x_change_rate = (args.inputs.mouse.y / 360) ** 2 | |
if args.inputs.mouse.y < 0 | |
args.state.cam_angle_x += 0.8 * x_change_rate | |
else | |
args.state.cam_angle_x -= 0.8 * x_change_rate | |
end | |
end | |
args.state.cam_z ||= 6.4 | |
if args.inputs.keyboard.up | |
point_1 = { x: 0, y: 0.02 } | |
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y | |
args.state.cam_x -= point_r.x * movement_multiplier | |
args.state.cam_z -= point_r.y * movement_multiplier | |
elsif args.inputs.keyboard.down | |
point_1 = { x: 0, y: -0.02 } | |
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y | |
args.state.cam_x -= point_r.x * movement_multiplier | |
args.state.cam_z -= point_r.y * movement_multiplier | |
end | |
args.state.cam_x ||= 0.00 | |
if args.inputs.keyboard.right | |
point_1 = { x: -0.02, y: 0 } | |
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y | |
args.state.cam_x -= point_r.x * movement_multiplier | |
args.state.cam_z -= point_r.y * movement_multiplier | |
elsif args.inputs.keyboard.left | |
point_1 = { x: 0.02, y: 0 } | |
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y | |
args.state.cam_x -= point_r.x * movement_multiplier | |
args.state.cam_z -= point_r.y * movement_multiplier | |
end | |
if args.inputs.keyboard.key_down.r || args.inputs.keyboard.key_down.zero | |
args.state.cam_x = 0.00 | |
args.state.cam_y = 0.00 | |
args.state.cam_z = 1.00 | |
args.state.cam_angle_y = 0 | |
args.state.cam_angle_x = 0 | |
end | |
camera_matrix = Matrix.mul (translate -args.state.cam_x, -args.state.cam_y, -args.state.cam_z), | |
(rotate_y args.state.cam_angle_y), | |
(rotate_x args.state.cam_angle_x) | |
args.state.perspective_triangles = args.state.triangles.map do |t| | |
{ p1: perspective(Matrix.mul(t[0], camera_matrix)), | |
p2: perspective(Matrix.mul(t[1], camera_matrix)), | |
p3: perspective(Matrix.mul(t[2], camera_matrix)) } | |
end | |
args.state.perspective_triangles.each do |triangle| | |
if triangle.p1 && triangle.p2 && triangle.p3 | |
p1 = triangle.p1 | |
p2 = triangle.p2 | |
p3 = triangle.p3 | |
args.outputs.sprites << { | |
x: p1.x, | |
y: p1.y, | |
x2: p2.x, | |
y2: p2.y, | |
x3: p3.x, | |
y3: p3.y, | |
source_x: 0, | |
source_y: 0, | |
source_x2: 100, | |
source_y2: 0, | |
source_x3: 100, | |
source_y3: 100, | |
path: :pixel, | |
r: 0, g: 0, b: 0, a: 80 | |
} | |
end | |
end | |
end | |
def perspective vec | |
left = 100.0 | |
right = -100.0 | |
bottom = 100.0 | |
top = -100.0 | |
near = 3000.0 | |
far = 8000.0 | |
sx = 2 * near / (right - left) | |
sy = 2 * near / (top - bottom) | |
c2 = - (far + near) / (far - near) | |
c1 = 2 * near * far / (near - far) | |
tx = -near * (left + right) / (right - left) | |
ty = -near * (bottom + top) / (top - bottom) | |
p = Matrix.mat4 sx, 0, 0, tx, | |
0, sy, 0, ty, | |
0, 0, c2, c1, | |
0, 0, -1, 0 | |
r = Matrix.mul vec, p | |
return nil if r.w < 0 | |
r.x *= r.z / r.w / 100 | |
r.y *= r.z / r.w / 100 | |
Matrix.vec2(r.x, r.y) | |
end | |
def translate dx, dy, dz | |
Matrix.mat4 1, 0, 0, dx, | |
0, 1, 0, dy, | |
0, 0, 1, dz, | |
0, 0, 0, 1 | |
end | |
def rotate_y angle_d | |
cos_t = Math.cos angle_d.to_radians | |
sin_t = Math.sin angle_d.to_radians | |
(Matrix.mat4 cos_t, 0, sin_t, 0, | |
0, 1, 0, 0, | |
-sin_t, 0, cos_t, 0, | |
0, 0, 0, 1) | |
end | |
def rotate_x angle_d | |
cos_t = Math.cos angle_d.to_radians | |
sin_t = Math.sin angle_d.to_radians | |
(Matrix.mat4 1, 0, 0, 0, | |
0, cos_t, -sin_t, 0, | |
0, sin_t, cos_t, 0, | |
0, 0, 0, 1) | |
end | |
def read_obj path | |
contents = ($gtk.read_file path) | |
verticies = contents.each_line | |
.find_all do |l| | |
l.strip.start_with? "v " | |
end.map do |l| | |
x, y, z = l.strip.split(' ')[1..-1].map { |t| t.to_f } | |
{ x: x, y: y, z: z } | |
end | |
faces = contents.each_line | |
.find_all do |l| | |
l.strip.start_with? "f " | |
end.map do |l| | |
a, b, c = l.strip.split(' ')[1..-1] | |
{ a: a.split('/')[0].to_i - 1, | |
b: b.split('/')[0].to_i - 1, | |
c: c.split('/')[0].to_i - 1 } | |
end | |
triangles = faces.map do |f| | |
[ | |
Matrix.vec4(verticies[f.a].x, verticies[f.a].y, verticies[f.a].z, 1), | |
Matrix.vec4(verticies[f.b].x, verticies[f.b].y, verticies[f.b].z, 1), | |
Matrix.vec4(verticies[f.c].x, verticies[f.c].y, verticies[f.c].z, 1) | |
] | |
end | |
triangles | |
end | |
$gtk.reset |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Impressive, thanks.