用c++实现3d引擎 |
您所在的位置:网站首页 › 用3d做一个简易卧室 › 用c++实现3d引擎 |
upd:2024/1 重写全部 b l o g blog blog 前言这篇文章介绍如何用最简单的c++代码(只有100行)实现3d线框渲染 思路主要来自SPixel 3d教程网站(英文) 重要:关于前置数学(如矩阵、线性代数)请参见 这个 \boxed{这个} 这个 下一篇:渲染贴图 效果图实现了第一人称视角移动等等 需要ege库,但是easyx也可(graphics.h) 或者不用图形库,输出到svg文件也可,需要自行更改代码 可以下载 小熊猫 c + + ( 直接带有 e a s y x ) \boxed{小熊猫c++(直接带有easyx)} 小熊猫c++(直接带有easyx)或下载 e a s y x ( V S 或 M i n G W ) \boxed{easyx(VS或MinGW)} easyx(VS或MinGW) 本文使用了EGE Easyx/EGE的使用可参见:这个 如何获得看到的图像假设我们的屏幕是棱锥的底面 将顶点投影到屏幕上,这个过程我们称之为透视投影。 如果垂直于x轴看,可以发现
△
A
B
C
\triangle ABC
△ABC与
△
A
B
′
C
′
\triangle AB'C'
△AB′C′相似 注意我们的屏幕处于 z z z的负半轴,并且假定焦距 A B ′ = 1 AB'=1 AB′=1 于是有 B C A B = B ′ C ′ A B ′ → P ′ . y = P . y − P . z \dfrac{BC}{AB}=\dfrac{B^{\prime}C^{\prime}}{AB^{\prime}}\to P^{\prime}.y=\dfrac{P.y}{-P.z} ABBC=AB′B′C′→P′.y=−P.zP.y 以上是透视投影的原理,你可以略过下面的内容(下面的内容是具体实现) 现在我们需要注意屏幕的大小(显示屏),应该根据假想屏幕(如下图)变化到真实屏幕里 现在我们的投影后坐标会在这个假定的屏幕里,即应该满足
x
,
y
∈
[
−
1
,
1
]
x,y\in[-1,1]
x,y∈[−1,1],当然屏幕外的点应该舍去不显示 将
[
−
1
,
1
]
→
[
0
,
长
]
和
[
0
,
宽
]
[-1,1]\to[0,长]和[0,宽]
[−1,1]→[0,长]和[0,宽], 这里引入NDC空间,即,将点从它们最初所在的范围转换为范围
[
0
,
1
]
[0,1]
[0,1] 我们可以采用 x ′ = ( 1 + x ) / 2 × 长, y ′ = ( 1 + y ) / 2 × 宽 x'=(1+x)/2\times长,y'=(1+y)/2\times宽 x′=(1+x)/2×长,y′=(1+y)/2×宽 可见性如何处理立方体哪个面可见,哪个面不可见,就是可见性问题 我们可以按照点的 z z z值从大到小(从后到前)进行计算,以避免此问题 透视投影的具体计算 第一步将物体从世界坐标系变换到相机坐标系(因为相机会移动和旋转) 现在假设相机坐标系为 M 相机 M_{相机} M相机,这是一个局部坐标系, 于是我们只要用世界坐标乘以相机坐标系即可得到相机坐标 这一步相当于 P 世界 × M 世界 − 相机 = P 相机 P_{世界}\times M_{世界-相机}=P_{相机} P世界×M世界−相机=P相机 相反的,我们要求的 P 世界 = P 相机 / M 相机 P_{世界}=P_{相机}/ M_{相机} P世界=P相机/M相机 所以将物体从世界坐标系变换到相机坐标系的结果 P ′ = P M 相机 P'=\dfrac P{M_{相机}} P′=M相机P 第二步现在,我们可以使用相机空间中的点坐标,通过使用透视投影方程 P ′ . y = P . y − P . z P^{\prime}.y=\dfrac{P.y}{-P.z} P′.y=−P.zP.y来计算其在屏幕上的坐标。 即:将 P ′ P' P′变换到屏幕坐标系 P ′ ′ P'' P′′ 但是要注意 P ′ ′ P'' P′′的可见性 { 可见 ∣ P ′ . x ∣ ≤ W 2 and ∣ P ′ . y ∣ ≤ H 2 不可见 otherwise \begin{cases}可见&|P'.x|\leq\frac{W}{2}\text{and}|P'.y|\leq\frac{H}{2}\\不可见&\text{otherwise}\end{cases} {可见不可见∣P′.x∣≤2Wand∣P′.y∣≤2Hotherwise 注意: P ′ ′ P'' P′′在以后仍记为 P P P 第三步注意显示屏为 [ 0 , W ] × [ 0 , H ] [0,W]\times[0,H] [0,W]×[0,H],而现在的 P P P点在 [ − W / 2 , W / 2 ] × [ − H / 2 , H / 2 ] [-W/2,W/2]\times[-H/2,H/2] [−W/2,W/2]×[−H/2,H/2] 所以要将 P P P变换到显示屏坐标系 (1)对 P P P归一化(NDC标准空间),即将 x , y x,y x,y相对于长宽,化为 [ 0 , 1 ] [0,1] [0,1] P 归一化 . x = P . x + W / 2 W P 归一化 . y = P . y + H / 2 H \begin{aligned}P_{归一化}.x&=\frac{P.x+W/2}{W}\\P_{归一化}.y&=\frac{P.y+H/2}{H}\end{aligned} P归一化.xP归一化.y=WP.x+W/2=HP.y+H/2 (2)注意显示屏的 y y y向下,于是有 P 栅格 . x = ⌊ P 归一化 . x ∗ W 像素 ⌋ P 像素 . y = ⌊ ( 1 − P 归一化 . y ) ∗ H 栅格 ⌋ \begin{array}{l}P_{栅格}.x=\lfloor P_{归一化}.x*W_{像素}\rfloor\\P_{像素}.y=\lfloor(1-P_{归一化}.y)*H_{栅格}\rfloor\end{array} P栅格.x=⌊P归一化.x∗W像素⌋P像素.y=⌊(1−P归一化.y)∗H栅格⌋ 具体代码怎么写? |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |