SupernaturalCow
Member
Hi all,
First off, I'm not coming into this from ground zero. I'm relatively savvy with the concepts behind 3D space, linear algebra, types of projection, and matrices. So, if your first compulsion is to link me with a common go-to online resource, odds are I've already spent much of my time looking at it. Don't let that stop you from re-linking, mind you, I just want to be clear that posting a thread isn't my first port of call here.
The Goal
A simple fly-through camera, as achievable with the built-in GM functions:
The Problem
I'm trying to learn how to implement my own perspective 3D camera. Putting aside the fact that my project uses vbuffers and solely deals with the Draw GUI event, I think this stuff is pretty interesting and would like to figure out how to manually do it.
So, I think I'm pretty close, but am getting some weird results and think my math might be slightly off.
The Attempt
x, y, z, yaw, pitch, roll == 0.
pitch == -0.2 (the rest are 0).
view_x == -0.03
view_y == -0.03
view_z == -339.88
view_yaw == -470.23
view_pitch == 0
view_roll == 0
I know these are relatively arbitrary, but I wanted to showcase what I'm looking at here.
If you're like me and have no idea, I'd be happy to share the vertex data writing code too, I just wanted to avoid dumping my entire pipeline here before anyone even replied lol. It is curious that the van doesn't move in the same direction as the background, though. The way the spotlight works is it dims anything not within a radius of the mouse position. This helps me to isolate a position in 3D space on the screen.
Thanks guys!
First off, I'm not coming into this from ground zero. I'm relatively savvy with the concepts behind 3D space, linear algebra, types of projection, and matrices. So, if your first compulsion is to link me with a common go-to online resource, odds are I've already spent much of my time looking at it. Don't let that stop you from re-linking, mind you, I just want to be clear that posting a thread isn't my first port of call here.
The Goal
A simple fly-through camera, as achievable with the built-in GM functions:
Code:
// Camera create
var cam = camera_create(),
mat_proj = matrix_build_projection_perspective_fov(45,view_wport[0]/view_hport[0],1,32000);
camera_set_proj_mat(cam,mat_proj);
view_set_camera(0,cam);
camera_set_update_script(cam,scr_cam_update());
// scr_cam_update()
var matr_view = matrix_build_lookat(x,y,z,x+dcos(dir), y-dsin(dir),z-dsin(pitch),0,0,1);
I'm trying to learn how to implement my own perspective 3D camera. Putting aside the fact that my project uses vbuffers and solely deals with the Draw GUI event, I think this stuff is pretty interesting and would like to figure out how to manually do it.
So, I think I'm pretty close, but am getting some weird results and think my math might be slightly off.
The Attempt
This part works as expected. Any functions in camelCase are just my own way of managing memory, and can be treated as any other object var attribution.
Code:
STEP
// Rotation
var _yaw = view_yaw,
_pitch = view_pitch,
_rotational_spd = 0.00001, // Lower is slower.
_mouse_x = mouse_x,
_mouse_y = mouse_y,
;
_yaw -= (_mouse_x-window_width/2)*_rotational_spd;
_pitch -= clamp(_pitch-(_mouse_y-window_height/2)*_rotational_spd, -120, 120);
viewSetYaw(_yaw);
viewSetPitch(_pitch);
// Translation
var _move_spd = 10,
_xaxis = keyboard_check(ord("D"))-keyboard_check(ord("A")),
_yaxis = keyboard_check(ord("S"))-keyboard_check(ord("W")),
_zaxis = keyboard_check(ord("C"))-keyboard_check(vk_space),
_view_x = view_x,
_view_y = view_y,
_view_z = view_z,
;
_view_x += _xaxis*dsin(_yaw)*_move_spd-_yaxis*dcos(_yaw)*_move_spd;
_view_y += _xaxis*dcos(_yaw)*_move_spd-_yaxis*dsin(_yaw)*_move_spd;
_view_z += _zaxis*_move_spd;
viewSetX(_view_x);
viewSetY(_view_y);
viewSetZ(_view_z);
Same as before. This stuff works without the fly-through camera, i.e. with orthographic projection.
Code:
DRAW GUI
shader_set(gpu_dynamic_lighting);
// View 3D translation and rotation uniforms.
// Translation
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewX"), view_x);
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewY"), view_y);
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewZ"), view_z);
// Scale
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewScale"), view_scale);
// Rotation
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewYaw"), view_yaw);
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewPitch"), view_pitch);
shader_set_uniform_f(shader_get_uniform(gpu_dynamic_lighting, "u_fViewRoll"), view_roll);
// For each render target in the game,
for (var j=0; j<RENDER.height; j++) {
var _render = j,
_tex = renderGetVertexTexture(_render),
_num_buffers = renderGetNumVertexBuffers(_render),
;
// For each VB in the render target,
for (var k=0; k<_num_buffers; k++) {
var _vb = renderGetVertexBuffer(_render, k);
// Submit the buffer.
vertex_submit_buffer(_vb, _tex); // Submits with pr_trianglelist.
};
};
shader_reset();
Code:
SHADER - VERTEX
// Only relevant code incl.
// DW - I've tested without irrelevant code and the problem persists.
attribute vec3 in_Position; // (x,y,z) [as seen in room editor] sprite (x,y,depth) - corners not sprite origin!
uniform float u_fViewX;
uniform float u_fViewY;
uniform float u_fViewZ;
uniform float u_fViewScale;
uniform float u_fViewYaw;
uniform float u_fViewPitch;
uniform float u_fViewRoll;
void main()
{
// Obtain 3D position of point to be projected, _a.
vec3 _a = vec3( in_Position.x, in_Position.y, in_Position.z);
// Obtain 3D position of view, _v.
vec3 _v = vec3( u_fViewX, u_fViewY, u_fViewZ);
// Obtain 3D rotation of view, _theta.
vec3 _theta = vec3( u_fViewYaw, u_fViewPitch, u_fViewRoll);
// Calculate sin and cos of theta, _s, _c.
vec3 _s = sin(_theta);
vec3 _c = cos(_theta);
// Calculate display surface's position relative to view lens, _e.
vec3 _e = _a-_v;
// To apply 2D perspective, we first need to determine 3D transformation point, _d.
// Directly from: https://en.wikipedia.org/wiki/3D_projection#Mathematical_formula
vec3 _d = vec3(0.0, 0.0, 0.0);
_d.x = _c.y * (_s.z*_e.y + _c.z*_e.x) - _s.y*_e.z;
_d.y = _s.x * (_c.y*_e.z + _s.y * (_s.z*_e.y + _c.z*_e.x)) + _c.x * (_c.z*_e.y - _s.z*_e.x);
_d.z = _c.x * (_c.y*_e.z + _s.y * (_s.z*_e.y + _c.z*_e.x)) - _s.x * (_c.z*_e.y - _s.z*_e.x);
// Finally, determine 2D position of point to be projected, b.
vec4 object_space_pos = vec4(0.0, 0.0, 0.0, 1.0/u_fViewScale);
object_space_pos.x = (_e.z/_d.z)*_d.x + _v.x;
object_space_pos.y = (_e.z/_d.z)*_d.y + _v.y;
// Submit edits to screen.
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
// To fragment
v_vPosition = vec3( in_Position.x, in_Position.y, in_Position.z); // Send true 3D verts to fragment shader.
v_vTexcoord = in_TextureCoord;
// Haven't included fragment bc irrelevant.
}
x, y, z, yaw, pitch, roll == 0.
pitch == -0.2 (the rest are 0).
view_x == -0.03
view_y == -0.03
view_z == -339.88
view_yaw == -470.23
view_pitch == 0
view_roll == 0
I know these are relatively arbitrary, but I wanted to showcase what I'm looking at here.
If you're like me and have no idea, I'd be happy to share the vertex data writing code too, I just wanted to avoid dumping my entire pipeline here before anyone even replied lol. It is curious that the van doesn't move in the same direction as the background, though. The way the spotlight works is it dims anything not within a radius of the mouse position. This helps me to isolate a position in 3D space on the screen.
Thanks guys!
Last edited: