improve star projection

This commit is contained in:
asrael 2026-01-23 11:04:05 -06:00
parent c771fa665d
commit 28c3e7ee04
22 changed files with 612 additions and 660 deletions

View file

@ -121,7 +121,7 @@ pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam) {
if (cam->mode == PXL8_3D_CAMERA_PERSPECTIVE) {
return pxl8_mat4_perspective(cam->fov, cam->aspect, cam->near, cam->far);
} else {
return pxl8_mat4_ortho(
return pxl8_mat4_orthographic(
cam->ortho_left, cam->ortho_right,
cam->ortho_bottom, cam->ortho_top,
cam->near, cam->far
@ -219,9 +219,9 @@ pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, p
pxl8_mat4 view = pxl8_3d_camera_get_view(cam);
pxl8_mat4 proj = pxl8_3d_camera_get_projection(cam);
pxl8_mat4 vp = pxl8_mat4_mul(proj, view);
pxl8_mat4 vp = pxl8_mat4_multiply(proj, view);
pxl8_vec4 clip = pxl8_mat4_mul_vec4(vp, (pxl8_vec4){world_pos.x, world_pos.y, world_pos.z, 1.0f});
pxl8_vec4 clip = pxl8_mat4_multiply_vec4(vp, (pxl8_vec4){world_pos.x, world_pos.y, world_pos.z, 1.0f});
if (clip.w <= 0.0f) return result;

View file

@ -215,7 +215,7 @@ void pxl8_cpu_destroy(pxl8_cpu_backend* cpu) {
void pxl8_cpu_begin_frame(pxl8_cpu_backend* cpu, const pxl8_3d_frame* frame) {
if (!cpu || !frame) return;
cpu->frame = *frame;
cpu->mvp = pxl8_mat4_mul(frame->projection, frame->view);
cpu->mvp = pxl8_mat4_multiply(frame->projection, frame->view);
}
void pxl8_cpu_end_frame(pxl8_cpu_backend* cpu) {
@ -368,8 +368,8 @@ void pxl8_cpu_draw_line_3d(pxl8_cpu_backend* cpu, pxl8_vec3 v0, pxl8_vec3 v1, u8
if (!cpu || !cpu->current_target) return;
pxl8_cpu_render_target* render_target = cpu->current_target;
pxl8_vec4 c0 = pxl8_mat4_mul_vec4(cpu->mvp, (pxl8_vec4){v0.x, v0.y, v0.z, 1.0f});
pxl8_vec4 c1 = pxl8_mat4_mul_vec4(cpu->mvp, (pxl8_vec4){v1.x, v1.y, v1.z, 1.0f});
pxl8_vec4 c0 = pxl8_mat4_multiply_vec4(cpu->mvp, (pxl8_vec4){v0.x, v0.y, v0.z, 1.0f});
pxl8_vec4 c1 = pxl8_mat4_multiply_vec4(cpu->mvp, (pxl8_vec4){v1.x, v1.y, v1.z, 1.0f});
if (c0.w <= 0.0f || c1.w <= 0.0f) return;
@ -1068,8 +1068,7 @@ static void dispatch_triangle(
const pxl8_atlas* textures, const pxl8_gfx_material* material
) {
if (material->wireframe) {
u8 color = (material->texture_id > 0) ? (u8)material->texture_id : 15;
rasterize_triangle_wireframe(cpu, vo0, vo1, vo2, color, material->double_sided);
rasterize_triangle_wireframe(cpu, vo0, vo1, vo2, 15, material->double_sided);
return;
}
@ -1100,8 +1099,8 @@ void pxl8_cpu_draw_mesh(
) {
if (!cpu || !mesh || !model || !material || mesh->index_count < 3 || !cpu->current_target) return;
pxl8_mat4 mv = pxl8_mat4_mul(cpu->frame.view, *model);
pxl8_mat4 mvp = pxl8_mat4_mul(cpu->frame.projection, mv);
pxl8_mat4 mv = pxl8_mat4_multiply(cpu->frame.view, *model);
pxl8_mat4 mvp = pxl8_mat4_multiply(cpu->frame.projection, mv);
f32 near = cpu->frame.near_clip > 0.0f ? cpu->frame.near_clip : 0.1f;
@ -1120,13 +1119,13 @@ void pxl8_cpu_draw_mesh(
pxl8_vec4 p1 = {v1->position.x, v1->position.y, v1->position.z, 1.0f};
pxl8_vec4 p2 = {v2->position.x, v2->position.y, v2->position.z, 1.0f};
vo0.clip_pos = pxl8_mat4_mul_vec4(mvp, p0);
vo1.clip_pos = pxl8_mat4_mul_vec4(mvp, p1);
vo2.clip_pos = pxl8_mat4_mul_vec4(mvp, p2);
vo0.clip_pos = pxl8_mat4_multiply_vec4(mvp, p0);
vo1.clip_pos = pxl8_mat4_multiply_vec4(mvp, p1);
vo2.clip_pos = pxl8_mat4_multiply_vec4(mvp, p2);
pxl8_vec4 w0 = pxl8_mat4_mul_vec4(*model, p0);
pxl8_vec4 w1 = pxl8_mat4_mul_vec4(*model, p1);
pxl8_vec4 w2 = pxl8_mat4_mul_vec4(*model, p2);
pxl8_vec4 w0 = pxl8_mat4_multiply_vec4(*model, p0);
pxl8_vec4 w1 = pxl8_mat4_multiply_vec4(*model, p1);
pxl8_vec4 w2 = pxl8_mat4_multiply_vec4(*model, p2);
vo0.world_pos = (pxl8_vec3){w0.x, w0.y, w0.z};
vo1.world_pos = (pxl8_vec3){w1.x, w1.y, w1.z};
vo2.world_pos = (pxl8_vec3){w2.x, w2.y, w2.z};
@ -1144,9 +1143,9 @@ void pxl8_cpu_draw_mesh(
vo2.color = v2->color;
if (material->dynamic_lighting) {
pxl8_vec3 n0 = pxl8_vec3_normalize(pxl8_mat4_mul_vec3(*model, v0->normal));
pxl8_vec3 n1 = pxl8_vec3_normalize(pxl8_mat4_mul_vec3(*model, v1->normal));
pxl8_vec3 n2 = pxl8_vec3_normalize(pxl8_mat4_mul_vec3(*model, v2->normal));
pxl8_vec3 n0 = pxl8_vec3_normalize(pxl8_mat4_multiply_vec3(*model, v0->normal));
pxl8_vec3 n1 = pxl8_vec3_normalize(pxl8_mat4_multiply_vec3(*model, v1->normal));
pxl8_vec3 n2 = pxl8_vec3_normalize(pxl8_mat4_multiply_vec3(*model, v2->normal));
pxl8_light_result lr0 = calc_vertex_light(vo0.world_pos, n0, &cpu->frame);
pxl8_light_result lr1 = calc_vertex_light(vo1.world_pos, n1, &cpu->frame);
@ -1177,44 +1176,6 @@ void pxl8_cpu_draw_mesh(
}
}
void pxl8_cpu_draw_mesh_wireframe(
pxl8_cpu_backend* cpu,
const pxl8_mesh* mesh,
pxl8_mat4 model,
u8 color
) {
if (!cpu || !cpu->current_target || !mesh || mesh->index_count < 3) return;
pxl8_cpu_render_target* render_target = cpu->current_target;
pxl8_mat4 mvp = pxl8_mat4_mul(cpu->frame.projection, pxl8_mat4_mul(cpu->frame.view, model));
for (u32 i = 0; i < mesh->index_count; i += 3) {
const pxl8_vertex* v0 = &mesh->vertices[mesh->indices[i]];
const pxl8_vertex* v1 = &mesh->vertices[mesh->indices[i + 1]];
const pxl8_vertex* v2 = &mesh->vertices[mesh->indices[i + 2]];
pxl8_vec4 c0 = pxl8_mat4_mul_vec4(mvp, (pxl8_vec4){v0->position.x, v0->position.y, v0->position.z, 1.0f});
pxl8_vec4 c1 = pxl8_mat4_mul_vec4(mvp, (pxl8_vec4){v1->position.x, v1->position.y, v1->position.z, 1.0f});
pxl8_vec4 c2 = pxl8_mat4_mul_vec4(mvp, (pxl8_vec4){v2->position.x, v2->position.y, v2->position.z, 1.0f});
if (c0.w <= 0.0f || c1.w <= 0.0f || c2.w <= 0.0f) continue;
f32 hw = (f32)render_target->width * 0.5f;
f32 hh = (f32)render_target->height * 0.5f;
i32 x0 = (i32)(hw + c0.x / c0.w * hw);
i32 y0 = (i32)(hh - c0.y / c0.w * hh);
i32 x1 = (i32)(hw + c1.x / c1.w * hw);
i32 y1 = (i32)(hh - c1.y / c1.w * hh);
i32 x2 = (i32)(hw + c2.x / c2.w * hw);
i32 y2 = (i32)(hh - c2.y / c2.w * hh);
pxl8_cpu_draw_line_2d(cpu, x0, y0, x1, y1, color);
pxl8_cpu_draw_line_2d(cpu, x1, y1, x2, y2, color);
pxl8_cpu_draw_line_2d(cpu, x2, y2, x0, y0, color);
}
}
u8* pxl8_cpu_get_framebuffer(pxl8_cpu_backend* cpu) {
if (!cpu || cpu->target_stack_depth == 0) return NULL;
return cpu->target_stack[0]->framebuffer;

View file

@ -57,13 +57,6 @@ void pxl8_cpu_draw_mesh(
const pxl8_atlas* textures
);
void pxl8_cpu_draw_mesh_wireframe(
pxl8_cpu_backend* cpu,
const pxl8_mesh* mesh,
pxl8_mat4 model,
u8 color
);
u8* pxl8_cpu_get_framebuffer(pxl8_cpu_backend* cpu);
u32* pxl8_cpu_get_output(pxl8_cpu_backend* cpu);
u32 pxl8_cpu_get_height(const pxl8_cpu_backend* cpu);

View file

@ -41,6 +41,7 @@ struct pxl8_gfx {
u32 sprite_cache_capacity;
u32 sprite_cache_count;
pxl8_viewport viewport;
pxl8_mat4 view_proj;
};
pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx) {
@ -611,8 +612,10 @@ void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8
pxl8_3d_frame frame = pxl8_3d_frame_from_camera(camera, uniforms);
pxl8_mat4 vp = pxl8_mat4_mul(frame.projection, frame.view);
pxl8_mat4 vp = pxl8_mat4_multiply(frame.projection, frame.view);
gfx->frustum = pxl8_frustum_from_matrix(vp);
gfx->view_proj = vp;
switch (gfx->backend.type) {
case PXL8_GFX_BACKEND_CPU:
@ -628,6 +631,38 @@ const pxl8_frustum* pxl8_3d_get_frustum(pxl8_gfx* gfx) {
return &gfx->frustum;
}
const pxl8_mat4* pxl8_3d_get_view_proj(pxl8_gfx* gfx) {
if (!gfx) return NULL;
return &gfx->view_proj;
}
u32 pxl8_3d_project_points(pxl8_gfx* gfx, const pxl8_vec3* in, pxl8_vec3* out, u32 count, const pxl8_mat4* transform) {
if (!gfx || !in || !out) return 0;
pxl8_mat4 mvp = transform ? pxl8_mat4_multiply(gfx->view_proj, *transform) : gfx->view_proj;
f32 hw = (f32)gfx->framebuffer_width * 0.5f;
f32 hh = (f32)gfx->framebuffer_height * 0.5f;
u32 visible = 0;
for (u32 i = 0; i < count; i++) {
pxl8_vec4 clip = pxl8_mat4_multiply_vec4(mvp, (pxl8_vec4){in[i].x, in[i].y, in[i].z, 1.0f});
if (clip.w <= 0.0f) {
out[i].z = -1.0f;
continue;
}
f32 inv_w = 1.0f / clip.w;
out[i].x = hw + clip.x * inv_w * hw;
out[i].y = hh - clip.y * inv_w * hh;
out[i].z = clip.w;
visible++;
}
return visible;
}
void pxl8_3d_clear(pxl8_gfx* gfx, u8 color) {
if (!gfx) return;
switch (gfx->backend.type) {
@ -672,17 +707,6 @@ void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* mo
}
}
void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color) {
if (!gfx || !mesh) return;
switch (gfx->backend.type) {
case PXL8_GFX_BACKEND_CPU:
pxl8_cpu_draw_mesh_wireframe(gfx->backend.cpu, mesh, model, color);
break;
case PXL8_GFX_BACKEND_GPU:
break;
}
}
void pxl8_3d_end_frame(pxl8_gfx* gfx) {
if (!gfx) return;
switch (gfx->backend.type) {

View file

@ -60,10 +60,11 @@ void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);
void pxl8_3d_clear_depth(pxl8_gfx* gfx);
void pxl8_3d_draw_line(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, u8 color);
void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_gfx_material* material);
void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color);
void pxl8_3d_end_frame(pxl8_gfx* gfx);
u8* pxl8_3d_get_framebuffer(pxl8_gfx* gfx);
const pxl8_frustum* pxl8_3d_get_frustum(pxl8_gfx* gfx);
const pxl8_mat4* pxl8_3d_get_view_proj(pxl8_gfx* gfx);
u32 pxl8_3d_project_points(pxl8_gfx* gfx, const pxl8_vec3* in, pxl8_vec3* out, u32 count, const pxl8_mat4* transform);
pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms);

View file

@ -18,6 +18,12 @@ typedef enum pxl8_blend_mode {
} pxl8_blend_mode;
typedef struct pxl8_gfx_material {
char name[16];
pxl8_vec3 u_axis;
pxl8_vec3 v_axis;
f32 u_offset;
f32 v_offset;
u32 texture_id;
u32 lightmap_id;
u8 alpha;