# 透视变换

### 计算投影后的x坐标

float cFov = 1.f / tanf(xfov / 2);
result.m[0][0] = cFov;
result.m[1][1] = aspect * cFov;
result.m[2][3] = -1;
result.m[2][2] = far / (near - far);
result.m[3][2] = near * far / (near - far);


### 另一个齐次裁剪空间

float cFov = 1.f / tanf(xfov / 2);
result.m[0][0] = cFov;
result.m[1][1] = aspect * cFov;
result.m[2][3] = -1;
result.m[2][2] = (near + far) / (near - far);
result.m[3][2] = (2 * near * far) / (near - far);


D3D12 z区间为[0,1]

D3D12 z区间为[-1,1]

### 如果不用fov，还能用什么参数计算投影矩阵？

m3和m4的计算和上面一样，我们直接写出结果就行。对[0,1]区间是

// 注意矩阵要设置成我们推导结果的转置。
void BuildPerspectiveFovRHMatrix(Matrix4f& result, const float l, const float r, float b, float t, const float n, const float f)
{
result.Set(0);

result.m[0][0] = 2 * n / (r - l);
result.m[1][1] = 2 * n / (t - b);
result.m[2][0] = (r + l) / (r - l);
result.m[2][1] = (t + b) / (t - b);
if (g_DepthClipSpace == DepthClipSpace::kDepthClipZeroToOne)
{
result.m[2][2] = f / (n - f);
result.m[3][2] = n * f / (n - f);
}
else /* g_DepthClipSpace == DepthClipSpace::kDepthClipNegativeOneToOne */
{
result.m[2][2] = (n + f) / (n - f);
result.m[3][2] = (2 * n * f) / (n - f);
}

return;
}

##### (fov)式投影矩阵和(l,r,b,t)式投影矩阵的联系

OpenGL z范围[0, 1]

OpenGL z范围[-1, 1]

D3D12 z范围[0, 1]

D3D12 z范围[-1, 1]

OpenGL的显示还是比D3D12偏上一些，整个物体也变小很多，因为我们这次的xfov值太大了。

### 如果相机空间是左手坐标系，那怎么办？

n和f坐标地改变，导致代入方程的数据也变了，先计算z范围是[0,1]的转换矩阵

// 还是要注意我们要按照转置的思路去设置
void BuildPerspectiveFovLHMatrix(Matrix4f& result, const float xfov, const float aspect, const float near, const float far)
{
result.Set(0);

float cFov = 1.f / tanf(xfov / 2.f);
result.m[0][0] = cFov;
result.m[1][1] = aspect * cFov;
result.m[2][3] = 1.0f;

if (g_DepthClipSpace == DepthClipSpace::kDepthClipZeroToOne)
{
result.m[2][2] = -far / (near - far);
result.m[3][2] = near * far / (near - far);
}
else
{
result.m[2][2] = -(far + near) / (near - far);
result.m[3][2] = (2 * near * far) / (near - far);
}

return;
}


lefthand_OpenGL_zero_to_one

lefthand_OpenGL_negative_one_to_one

lefthand_D3D12_zero_to_one

lefthand_D3D12_negative_one_to_one

# 补充说明

（1）首先你得有一个环境，Win10+VS2017+CMake+Git+Git-Lfs+github账号
（2）克隆项目到本地（克隆过程请耐心等待，原本github就不快，而且我项目里还有大文件（git-lfs更加慢得令人发指），100M以上的那种），逐个运行build_assimp.bat，build_crossguid.bat，build_libpng.bat，build_opengex.bat，build_zlib.bat
（3）运行build.bat
（4）打开build文件夹下，Panda.sln解决方案。
（5）运行EditorD3D或是EditorOGL。

# 参考资料

《3D游戏与计算机图形学中的数学方法》
《Real-Time Render 4th Edition》
《3D Graphics for Game Programming》