eduwin 3D 渲染 API(D3D11)
eduwin 对 Direct3D 11 的轻量封装。
核心约定:
- 矩阵采用 row-major 存储,与
D3DMATRIX和 HLSL 的row_major float4x4一致 - 顶点格式包含位置 + 法线 + UV + 顶点色(共 48 字节)
- 常量缓冲包含世界/视图/投影矩阵 + 光照参数
- 着色器支持:环境光 + 方向光 + 点光源的漫反射光照
数据类型
typedef struct { float m[16]; } dx_mat4;
4×4 矩阵,row-major 存储(m[row*4+col])。例如 m[0]=_11,m[1]=_12,m[4]=_21,m[12]=_41。
typedef struct {
float x, y, z; // 位置 0-11
float nx, ny, nz; // 法线 12-23
float u, v; // UV 24-31
float r, g, b, a; // 颜色 32-47
} dx_vertex;
顶点格式:位置(3 float)+ 法线(3 float)+ UV(2 float)+ 顶点色(4 float),共 48 字节。
typedef struct { void *vb; void *ib; int icount; } dx_geometry;
dx_geometry 包含顶点缓冲和索引缓冲。通过 dx_create_geometry 创建,dx_free_geometry 释放。
typedef struct dx_texture_t dx_texture;
纹理是不透明类型,通过 dx_create_texture 或 dx_create_texture_rgba 创建。
生命周期
int dx_init(HWND hwnd, int w, int h);
初始化 D3D11。创建 swap chain、编译 shader、创建常量缓冲和光栅化状态。成功返回 1,失败返回 0。
hwnd— 渲染窗口句柄w,h— 客户区宽高(像素)- 内部自动调用
dx_resize创建 render target 和 depth stencil
void dx_shutdown(void);
销毁所有 D3D11 资源(rasterizer state、constant buffer、input layout、shaders、render target、depth stencil、swap chain、device context、device)。
void dx_begin(float r, float g, float b, float a);
开始一帧渲染。清空 render target 为指定颜色,清空 depth stencil。每帧必须在所有绘制前调用一次。
void dx_end(void);
结束一帧渲染。调用 Present(1, 0) 交换前后缓冲。
void dx_resize(int w, int h);
重建 render target 和 depth stencil。窗口大小变化时调用。
矩阵设置
void dx_set_world(dx_mat4 world);
void dx_set_view(dx_mat4 view);
void dx_set_projection(dx_mat4 proj);
设置世界矩阵、视图矩阵、投影矩阵。在 dx_begin / dx_end 之间调用,每次 dx_draw_indexed 前需先设 world。三个矩阵在常量缓冲中的 HLSL 代码路径为:
p = mul(p, mWorld);
p = mul(p, mView);
p = mul(p, mProjection);
相机封装
typedef struct {
float position[3]; /* 相机位置 camera.position */
float target[3]; /* 观察目标 camera.lookAt */
float up[3]; /* 上方向 */
float fov; /* 视场角 */
float aspect; /* 宽高比 width/height */
float near_z; /* 近裁剪面 */
float far_z; /* 远裁剪面 */
} dx_camera;
void dx_camera_init(dx_camera *cam, float px, float py, float pz, float aspect);
void dx_camera_update(dx_camera *cam);
用法:
dx_camera cam;
dx_camera_init(&cam, 0, 3, -5, 800.0f / 600.0f); // 初始化
dx_camera_update(&cam); // 每帧更新
// 窗口 resize 时改 aspect 再 update:
cam.aspect = 1024.0f / 768.0f;
dx_camera_update(&cam);
网格(Mesh = Geometry + Material + Transform)
dx_mesh 封装了几何体 + 材质 + 变换,隐藏矩阵操作,仿 Three.js 的 Mesh:
typedef struct {
dx_geometry *geometry; /* 顶点数据 */
dx_material *material; /* 材质(可 NULL) */
float position[3]; /* 平移 */
float rotation[3]; /* 旋转(XYZ 欧拉角) */
float scale[3]; /* 缩放 */
} dx_mesh;
dx_mesh* dx_create_mesh(dx_geometry *geo, dx_material *mat);
void dx_mesh_set_position(dx_mesh *m, float x, float y, float z);
void dx_mesh_set_rotation(dx_mesh *m, float x, float y, float z);
void dx_mesh_set_scale(dx_mesh *m, float x, float y, float z);
void dx_mesh_draw(dx_mesh *m);
void dx_free_mesh(dx_mesh *m);
dx_mesh_draw 内部自动计算 world = S × Rx × Ry × Rz × T,绑定材质,绘制几何体。可直接读写字段:
mesh->position[0] = 2; /* X 位置 */
mesh->rotation[1] = 0.5f; /* Y 旋转 */
网格通常由 dx_create_mesh 作为指针创建,dx_free_mesh 释放(注意:不会释放 geometry/material,共享引用需调用方管理)。
obj.ry = 0.5f; // 绕 Y 转
obj.rx = 0.1f; // 绕 X 转
obj.sx = 2.0f; // X 方向放大 2 倍
---
## 几何体操作
```c
dx_geometry* dx_create_geometry(dx_vertex *verts, int vcount,
unsigned short *indices, int icount);
创建自定义几何体。上传顶点和索引数据到 D3D11 的默认用途(D3D11_USAGE_DEFAULT)缓冲。
dx_geometry* dx_create_box(float w, float h, float d,
float r, float g, float b, float a);
创建立方体几何体。自动生成 8 个顶点和 36 个索引(12 个三角形),中心在原点。
dx_geometry* dx_create_sphere(float radius,
float r, float g, float b, float a);
创建 UV 球体几何体(12 环 × 16 段),中心在原点。
dx_geometry* dx_create_cylinder(float radius, float height,
float r, float g, float b, float a);
创建圆柱体几何体(16 段),中心在原点。
dx_geometry* dx_create_pyramid(float w, float h, float d,
float r, float g, float b, float a);
创建四棱锥几何体(5 顶点 / 6 三角形),中心在原点。
dx_geometry* dx_create_plane(float w, float h,
float r, float g, float b, float a);
创建平面几何体(4 顶点 / 2 三角形),默认在 XY 平面、面向 +Z 方向、中心在原点。通过旋转可以变成地面(绕 X 转 -90°)或墙面。
void dx_draw_geometry(dx_geometry *geo, int count, int start_index, int base_vertex);
绘制几何体。每次调用前必须设置好 world 矩阵。
void dx_free_geometry(dx_geometry *geo);
释放几何体的顶点和索引缓冲,并释放几何体本身。
光照
void dx_set_ambient_light(float r, float g, float b, float intensity);
设置环境光颜色和强度(漫反射系数)。环境光均匀照亮所有物体,无方向感。
void dx_set_directional_light(float dx, float dy, float dz,
float r, float g, float b, float intensity);
设置方向光。dx/dy/dz 是指向光源的方向向量(会被归一化),r/g/b 是颜色,intensity 是强度。
void dx_set_point_light(float px, float py, float pz,
float r, float g, float b, float intensity,
float range);
设置点光源。px/py/pz 是世界坐标位置,range 是衰减距离。
光照在 dx_begin / dx_end 之间、绘制之前设置:
dx_begin(0.15f, 0.15f, 0.2f, 1);
dx_set_ambient_light(0.4f, 0.4f, 0.4f, 1.0f);
dx_set_directional_light(0.3f, -1, 0.5f, 1, 1, 1, 1.2f);
dx_set_point_light(1.5f, 3, 2, 1, 0.8f, 0.6f, 0.8f, 6);
dx_mesh_draw(mesh);
dx_end();
纹理
dx_texture* dx_create_texture(const char *filename);
从 BMP/PNG/JPG 文件创建纹理。返回纹理句柄,失败返回 NULL。
dx_texture* dx_create_texture_rgba(int w, int h, const unsigned char *rgba);
从内存 RGBA 像素数据创建纹理,用于程序生成的纹理。
void dx_free_texture(dx_texture *tex);
释放纹理资源。
void dx_bind_texture(dx_texture *tex, int slot);
将纹理绑定到着色器的指定插槽(slot 从 0 开始)。绑定后后续绘制的物体会使用该纹理。传 NULL 可解除绑定。
用法:
dx_texture *tex = dx_create_texture("checker.bmp");
dx_bind_texture(tex, 0); // 绑定到 slot 0
dx_mesh_draw(mesh); // 使用纹理绘制
dx_bind_texture(NULL, 0); // 解绑
glTF 加载
dx_mesh** dx_load_gltf(const char *path, int *out_count);
从 glTF 文件加载网格,返回 dx_mesh* 数组。out_count 返回网格数量。失败返回 NULL。
void dx_free_geometries(dx_geometry **geos, int count);
释放 dx_load_gltf 返回的整个网格数组。
用法:
int count;
dx_geometry **geos = dx_load_gltf("model.gltf", &count);
if (geos) {
for (int i = 0; i < count; i++)
dx_mesh *m = dx_create_mesh(geos[i], NULL);
// ...
dx_free_geometries(geos, count);
}
矩阵数学辅助
所有矩阵函数使用 row-major 约定,与 D3DXMATRIX 一致。
void dx_mat4_identity(dx_mat4 *m);
void dx_mat4_mul(dx_mat4 *out, const dx_mat4 *a, const dx_mat4 *b);
void dx_mat4_rotation_x(dx_mat4 *m, float angle);
void dx_mat4_rotation_y(dx_mat4 *m, float angle);
void dx_mat4_rotation_z(dx_mat4 *m, float angle);
void dx_mat4_translation(dx_mat4 *m, float x, float y, float z);
void dx_mat4_look_at_lh(dx_mat4 *m, const float eye[3],
const float at[3], const float up[3]);
void dx_mat4_perspective_fov_lh(dx_mat4 *m, float fov_y,
float aspect, float zn, float zf);
内部结构
| 组件 | 说明 |
|---|---|
| Swap Chain | 双缓冲,DXGI_SWAP_EFFECT_DISCARD |
| Feature Level | D3D_FEATURE_LEVEL_11_0 |
| Shader Model | vs_5_0 / ps_5_0 |
| 光栅化 | D3D11_FILL_SOLID + D3D11_CULL_NONE |
| 常量缓冲 | 单个 register(b0),包含 world / view / projection + 光照参数 |
| 光照模型 | 环境光 + 方向光漫反射 + 点光源漫反射衰减 |
| 顶点格式 | POSITION + NORMAL + TEXCOORD + COLOR |