feat: OBJ model loader + fix mesh.h duplicates
- mesh_load_obj: parse vertices, UVs, faces from .obj files - Auto-generate face normals - Per-face vertex expansion (simple but correct)
This commit is contained in:
1 parent
d15a3947ab
commit
ea3e0ab61c
2 files changed
+99
No files matched your search
@@ -1,5 +1,7 @@
|
||||
#include "mesh.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#ifndef MATH_ASM_AVAILABLE
|
||||
#include "../ASM/math_c_fallback.h"
|
||||
@@ -108,3 +110,99 @@ Mesh* mesh_create_sphere(ID3D11Device* dev, float r, int seg) {
|
||||
free(v); free(idx);
|
||||
return m;
|
||||
}
|
||||
|
||||
// OBJ 加载器
|
||||
Mesh* mesh_load_obj(ID3D11Device* dev, const char* path) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) return NULL;
|
||||
|
||||
// 先统计顶点和面数
|
||||
int max_v = 4096, max_f = 8192;
|
||||
float* verts = (float*)malloc(max_v * 3 * sizeof(float));
|
||||
float* uvs = (float*)malloc(max_v * 2 * sizeof(float));
|
||||
int vert_count = 0, uv_count = 0;
|
||||
int* face_idx = (int*)malloc(max_f * 3 * sizeof(int));
|
||||
int face_count = 0;
|
||||
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (line[0] == 'v' && line[1] == ' ') {
|
||||
float x, y, z;
|
||||
if (sscanf(line + 2, "%f %f %f", &x, &y, &z) == 3 && vert_count < max_v) {
|
||||
verts[vert_count * 3] = x;
|
||||
verts[vert_count * 3 + 1] = y;
|
||||
verts[vert_count * 3 + 2] = z;
|
||||
vert_count++;
|
||||
}
|
||||
} else if (line[0] == 'v' && line[1] == 't') {
|
||||
float u, v;
|
||||
if (sscanf(line + 3, "%f %f", &u, &v) == 2 && uv_count < max_v) {
|
||||
uvs[uv_count * 2] = u;
|
||||
uvs[uv_count * 2 + 1] = v;
|
||||
uv_count++;
|
||||
}
|
||||
} else if (line[0] == 'f' && line[1] == ' ') {
|
||||
// 解析面: f v/vt v/vt v/vt 或 f v v v
|
||||
int v0, v1, v2;
|
||||
char* p = line + 2;
|
||||
v0 = atoi(p) - 1; while (*p && *p != ' ') p++; p++;
|
||||
v1 = atoi(p) - 1; while (*p && *p != ' ') p++; p++;
|
||||
v2 = atoi(p) - 1;
|
||||
if (v0 >= 0 && v1 >= 0 && v2 >= 0 && face_count < max_f) {
|
||||
face_idx[face_count * 3] = v0;
|
||||
face_idx[face_count * 3 + 1] = v1;
|
||||
face_idx[face_count * 3 + 2] = v2;
|
||||
face_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vert_count == 0 || face_count == 0) {
|
||||
free(verts); free(uvs); free(face_idx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 构建去重顶点 (简单方案: 每个面一个顶点)
|
||||
int out_vcount = face_count * 3;
|
||||
Vertex* out_verts = (Vertex*)calloc(out_vcount, sizeof(Vertex));
|
||||
uint32_t* out_idx = (uint32_t*)malloc(face_count * 3 * sizeof(uint32_t));
|
||||
|
||||
for (int i = 0; i < face_count; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int vi = face_idx[i * 3 + j];
|
||||
int oi = i * 3 + j;
|
||||
if (vi < vert_count) {
|
||||
out_verts[oi].pos[0] = verts[vi * 3];
|
||||
out_verts[oi].pos[1] = verts[vi * 3 + 1];
|
||||
out_verts[oi].pos[2] = verts[vi * 3 + 2];
|
||||
}
|
||||
out_verts[oi].color[0] = out_verts[oi].color[1] = out_verts[oi].color[2] = 1.0f;
|
||||
out_verts[oi].color[3] = 1.0f;
|
||||
out_idx[oi] = oi;
|
||||
}
|
||||
}
|
||||
|
||||
// 简单法线计算 (面法线)
|
||||
for (int i = 0; i < face_count; i++) {
|
||||
float* p0 = out_verts[i * 3].pos;
|
||||
float* p1 = out_verts[i * 3 + 1].pos;
|
||||
float* p2 = out_verts[i * 3 + 2].pos;
|
||||
float e1[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
|
||||
float e2[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]};
|
||||
float nx = e1[1]*e2[2] - e1[2]*e2[1];
|
||||
float ny = e1[2]*e2[0] - e1[0]*e2[2];
|
||||
float nz = e1[0]*e2[1] - e1[1]*e2[0];
|
||||
float nl = sqrtf(nx*nx + ny*ny + nz*nz);
|
||||
if (nl > 0.0001f) { nx /= nl; ny /= nl; nz /= nl; }
|
||||
for (int j = 0; j < 3; j++) {
|
||||
out_verts[i * 3 + j].norm[0] = nx;
|
||||
out_verts[i * 3 + j].norm[1] = ny;
|
||||
out_verts[i * 3 + j].norm[2] = nz;
|
||||
}
|
||||
}
|
||||
|
||||
Mesh* m = create_mesh(dev, out_verts, out_vcount, out_idx, face_count * 3, sizeof(Vertex));
|
||||
free(out_verts); free(out_idx); free(verts); free(uvs); free(face_idx);
|
||||
return m;
|
||||
}
|
||||
@@ -20,5 +20,6 @@ typedef struct {
|
||||
Mesh* mesh_create_cube(ID3D11Device* dev);
|
||||
Mesh* mesh_create_plane(ID3D11Device* dev, float size);
|
||||
Mesh* mesh_create_sphere(ID3D11Device* dev, float r, int seg);
|
||||
Mesh* mesh_load_obj(ID3D11Device* dev, const char* path);
|
||||
void mesh_destroy(Mesh* m);
|
||||
void mesh_draw(Mesh* m, ID3D11DeviceContext* ctx);
|
||||
Reference in new issue
Block a user