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]=_11m[1]=_12m[4]=_21m[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_texturedx_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 LevelD3D_FEATURE_LEVEL_11_0
Shader Modelvs_5_0 / ps_5_0
光栅化D3D11_FILL_SOLID + D3D11_CULL_NONE
常量缓冲单个 register(b0),包含 world / view / projection + 光照参数
光照模型环境光 + 方向光漫反射 + 点光源漫反射衰减
顶点格式POSITION + NORMAL + TEXCOORD + COLOR