效果图
提交单:https://github.com/CartmanORCamille/CDX/commit/afc7a52fc96466ddb1ab5233e4986bb739037e33
关键点
- 渲染管线基础。
- C 与 C++ 交叉编译和全局变量。
- 位表(键盘事件,摄像机视角与观察点)。
渲染几何体基础
画一个正方体
【猜测】demo 里(gif图)在旋转的时候看不到底部&顶部三角形,但是在静止时可以看到,应该是 Z 轴没设置好导致摄像机范围内看不到两个面。
demo 里是用索引数据绘制正方体,三角形序列用 D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST。
demo 里用三角形列表而不是三角形带,因为三角形带导致几何体必须按照带状方式组织,实现难度较大。三角形列表具有更好的灵活性(三角形不必彼此相连),三角形连接顺序都是顺时针。
主要渲染过程
- 创建顶点数据。
- 创建顶点索引数据。
- 创建 shader 编译对象,读取 shader 对象里的 Technique 和常量齐次矩阵(世界矩阵 * 观察矩阵 * 投影矩阵)对象。
- 创建渲染视图(IA 阶段装配信息)。
- 创建渲染模式,并默认选择线框模式渲染。
- IA 阶段绑定各项数据。
- 获取 Technique 数据对象。
- 根据 Technique pass 数量获取 pass 并绑定的上下文(Context)。
- 绘制索引顶点。
编译 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
标签:P1,渲染,technique,Vertex,C++,编译,pass,extern,CDX From: https://www.cnblogs.com/hatsuzuki/p/17514874.html