【CDX随笔总结】P1_Vertex 的整理和分析【未完成,持续编写】

发布时间 2023-07-05 17:14:07作者: 阿初

效果图

提交单:https://github.com/CartmanORCamille/CDX/commit/afc7a52fc96466ddb1ab5233e4986bb739037e33

关键点

  • 渲染管线基础。
  • C 与 C++ 交叉编译和全局变量。
  • 位表(键盘事件,摄像机视角与观察点)。

渲染几何体基础

画一个正方体

【猜测】demo 里(gif图)在旋转的时候看不到底部&顶部三角形,但是在静止时可以看到,应该是 Z 轴没设置好导致摄像机范围内看不到两个面。

demo 里是用索引数据绘制正方体,三角形序列用 D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST。
demo 里用三角形列表而不是三角形带,因为三角形带导致几何体必须按照带状方式组织,实现难度较大。三角形列表具有更好的灵活性(三角形不必彼此相连),三角形连接顺序都是顺时针。

主要渲染过程

  1. 创建顶点数据。
  2. 创建顶点索引数据。
  3. 创建 shader 编译对象,读取 shader 对象里的 Technique 和常量齐次矩阵(世界矩阵 * 观察矩阵 * 投影矩阵)对象。
  4. 创建渲染视图(IA 阶段装配信息)。
  5. 创建渲染模式,并默认选择线框模式渲染。
  6. IA 阶段绑定各项数据。
  7. 获取 Technique 数据对象。
  8. 根据 Technique pass 数量获取 pass 并绑定的上下文(Context)。
  9. 绘制索引顶点。

编译 Shader

编译 Shader

编译 Shader 对象并存入指针 pCompiledShader

	// build shader.
	hrResult = D3DX11CompileFromFile(
		L".\\FX\\P1.fx", NULL, NULL, NULL, "fx_5_0", dwShaderFlags, 0, NULL, &pCompiledShader, &pCompiledErrMsgs, NULL
	);

Effect 和 technique

effect

effect 是个框架。它包含以下。
一个 shader 通常保存在 effect 文件中(fx),这是一个纯文本(类似 C 语言代码保存在 .c 文件中)。
在一个 effect 文件中,必须包含一个 technique,一个 technique 必须包含一个 pass。

technique

一个 technique 由一个或多个 pass 组成,用于创建一个渲染技术。每个 pass 实现一种不同的几何体渲染方式。可以按照某种方式将多个 pass 的渲染结果混合在一起就可以得到想要的渲染结果。
比如在地形渲染中使用多通道纹理映射技术(multi-pass texturing technique),多通道技术通常会占用大量的系统资源,因为每个 pass 要对几何体进行一次渲染。
在 shader 里声明定义个 technique 关键字是 technique11

pass

一个 pass 由一个顶点着色器,一个可选的集合着色器,一个像素着色器和一些渲染状态组成,这部分定义了 pass 的几何体渲染方式。
像素着色器也是可选的,比如指向绘制深度缓冲,不想绘制后台缓冲,在这种情况下就不需要像素着色器计算像素颜色。

Demo

在 demo 里用了 1 个 technqiue,包含 1 个 pass。在这个 pass 里指定了顶点着色器和像素着色器,注释了渲染状态(渲染状态初始化时指定了,并由键盘控制)。

创建 Effect 并存入指针 pFX

	hrResult = D3DX11CreateEffectFromMemory(
		pCompiledShader->GetBufferPointer(),
		pCompiledShader->GetBufferSize(),
		0,
		ptCdx->pD3d,
		&(ptP1Demo->pFX)
	);
	TH_CHECKERR_FAILED(hrResult);

C 与 C++ 交叉编译

主项目是 C 语言,P1 Demo 是 C++ 文件。

extern "C"

extern "C" 目的是为了 C++ 能够调用 C 语言代码,加上这句后,表示这部分代码按照 C 语言的方式进行编译。
C++ 编译的时候会修改函数的名称(C++ 函数支持重载),但这样 C 语言就读不到了。

在 P1 Demo 里会使用到 D3D Math 这个数学库,这个库只能在 C++ 上用,所以这里就用到了交叉编译。

A.h
#ifdef  __cplusplus
extern "C" {
#endif
	// 这里导入所需要的代码。
    inlcude <DirectXMath.h>
    // 只在头文件中声明。
    int a;
#ifdef __cplusplus
}
#endif

A.cpp
// 在 main 函数外定义 a 变量。
int a = 1;
void main() {...}

extern "C" 是包含双重含义。首先是 extern,然后是 "C"。
extern 告诉编译器此变量会暴露,申明此变量或函数可以在本模块或其他模块中使用。
"C" 以 C 语言模式编译和链接,函数名编译后不会被修改。

全局变量

extern int a
这仅仅是个声明,而非定义,并没有为 a 分配内存空间。a 在所有模块中作为全局变量只能被定义一次(在 main 函数外),否则会报错。
B 模块想调用 A 模块中定义的变量/函数时,只需要导入头文件,虽然在编译阶段找不到此变量/函数,但是并不会报错,会在 A 模块编译生成中的目标代码找到。

与 extern 对应的是 static,static 表示变量或者函数只能在本模块使用,所以不可能被 extern "C" 修饰。

在 demo 里,C++ 调用 C 与 C 调用 C++ 都是用 extern "C",因为已经 extern 了,而且都已经导入了D3DMain.h头文件,可以链接到。

位表

Bitmap

参考

https://www.cnblogs.com/Ray1024/p/6101284.html