ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

3D图形核心原理与实战:从数学基础到渲染管线及性能优化

3D图形核心原理与实战:从数学基础到渲染管线及性能优化 1. 从“2. 3D图形”这个标题说起它到底在讲什么看到“2. 3D图形”这个标题很多人第一反应可能是这不就是三维建模、渲染那一套吗但如果你真的在图形学、游戏引擎、数据可视化或者工业软件这条线上摸爬滚打过几年就会意识到这个标题背后藏着的是一整套从数学基础到工程落地的完整知识体系。它不是一个单一的技术点而是一个横跨数学、计算机科学、硬件架构和艺术表达的交叉领域。我之所以想认真聊聊这个话题是因为在过去几年里我见过太多人在学习3D图形时走了弯路。有人一上来就啃OpenGL红宝书结果被各种矩阵变换和着色器语法劝退有人直接跳到Unity或Unreal引擎里拖拽组件做出来的场景看着还行但一旦遇到性能瓶颈或者自定义渲染需求就完全不知道从何下手还有人把3D图形等同于“学一个建模软件”结果在需要程序化生成几何体或者实现自定义光照模型时束手无策。“2. 3D图形”这个编号本身也暗示了一种系统性——它很可能是某个系列教程或知识体系中的第二个模块。这意味着它前面可能已经铺垫了基础概念后面还会延伸到更高级的主题。所以我在拆解这个标题时会把它放在一个完整的知识链路里来看3D图形到底解决什么问题它的核心数学工具是什么渲染管线是怎么工作的在实际项目中如何选型和优化有哪些坑是只有真正做过项目的人才会知道的这篇文章适合谁看如果你是对3D图形完全陌生但想入门的开发者我会用生活化的类比帮你建立直觉如果你已经有一定基础但总觉得知识是碎片化的我会帮你把各个模块串起来如果你正在做实际项目但遇到了性能或效果上的瓶颈我会分享一些从实战中总结出来的经验和技巧。不管你是做游戏、做数据可视化、做CAD软件还是做AR/VR应用3D图形的核心原理都是相通的。在开始深入之前我想先明确一个观点3D图形不是一门“纯理论”学科也不是一门“纯工具”技能。它更像是一门手艺——你需要理解背后的数学原理但更需要通过大量的动手实践来培养“图形直觉”。这种直觉让你在看到一个问题时能快速判断出应该用什么样的几何表示、什么样的渲染策略、什么样的优化手段。而这篇文章的目标就是帮你建立这种直觉。2. 3D图形的数学地基为什么向量、矩阵和坐标系是绕不开的2.1 向量和矩阵不是考试内容而是描述空间的“语言”很多人学3D图形时最痛苦的就是数学部分。我完全理解这种感受——当年我第一次看到MVP矩阵变换的公式时也觉得这玩意儿跟实际写代码有什么关系但后来做项目多了才明白向量和矩阵不是数学家为了为难程序员而发明的它们是描述三维空间中最基本操作的“语言”。你可以把向量理解成“带方向的箭头”。在3D图形里一个顶点的位置是一个向量一个表面的法线方向是一个向量光线的传播方向也是一个向量。而矩阵呢它本质上是一个“变换器”——你给它一个向量它按照预设的规则把这个向量映射到新的位置或方向。平移、旋转、缩放这三种最基本的空间操作全都可以用矩阵来表示。为什么非要用矩阵因为矩阵有一个极其优雅的性质多个变换可以合并成一个矩阵。比如你想先旋转一个物体再平移它理论上可以做两次运算。但如果你把旋转矩阵和平移矩阵相乘得到一个组合矩阵那么对每个顶点只需要做一次矩阵乘法就行了。在实时渲染中每秒钟要处理几百万甚至上千万个顶点这种合并带来的性能提升是巨大的。我经常用一个类比来解释这件事假设你要给一栋楼的每个房间送快递。如果每次都要先查“旋转路线”再查“平移路线”效率很低。但如果你提前把这两条路线合并成一条“综合路线”每个快递员只需要看一张地图就行了。矩阵乘法就是在做这种“路线合并”。2.2 齐次坐标一个让平移也能用矩阵表示的巧妙设计这里有一个初学者很容易忽略的细节在三维空间中平移操作其实不能用3x3矩阵来表示。为什么因为3x3矩阵只能对向量做线性变换而平移是非线性的——它不保持原点不变。但我们在图形学中又特别希望所有变换都能统一用矩阵乘法来处理怎么办解决方案就是齐次坐标。简单来说我们把三维向量扩展成四维多出来的那个分量通常设为1。这样一个4x4矩阵就可以同时表示旋转、缩放和平移了。这个设计看起来只是数学上的小技巧但它带来的工程便利是巨大的整个渲染管线中所有的顶点变换都可以统一成矩阵乘法GPU可以针对这种运算做极致的硬件优化。我在实际项目中踩过的一个坑是有时候为了省内存想把矩阵从4x4压缩成3x4因为最后一行通常是0,0,0,1。这在某些情况下确实可行但一旦涉及到投影矩阵或者需要求逆矩阵时就会出问题。所以我的建议是除非你非常清楚自己在做什么否则老老实实用4x4矩阵内存换来的正确性和可维护性是值得的。2.3 坐标系变换从模型空间到屏幕空间的完整链路一个3D模型从它被创建出来到最终显示在屏幕上要经历一系列坐标系变换。这个过程就像把一件商品从工厂送到消费者手里中间要经过仓库、物流中心、配送站等多个环节。首先是模型空间也叫局部空间。这是模型被创建时所在的坐标系原点通常在模型的中心或者底部。比如你在Blender里建了一个茶壶它的顶点坐标就是在这个空间里定义的。然后是世界空间。通过模型矩阵我们把模型放到场景中的某个位置。这个矩阵包含了平移、旋转和缩放信息。比如你把茶壶放在桌子上旋转了45度还放大了1.5倍这些操作都体现在模型矩阵里。接下来是观察空间也叫相机空间。通过视图矩阵我们把整个世界坐标系转换到以相机为原点的坐标系。这一步的本质是不管世界有多大我们只关心相机能看到的那部分。视图矩阵可以理解为“把相机移到原点并让它朝向-z方向”的变换。最后是裁剪空间和屏幕空间。通过投影矩阵我们把观察空间中的坐标转换到裁剪空间。透视投影会让远处的物体看起来更小正交投影则保持物体大小不变。裁剪空间中的坐标经过透视除法后就得到了归一化设备坐标NDC再经过视口变换最终变成屏幕上的像素坐标。这个链路听起来很复杂但实际写代码时你通常只需要把三个矩阵乘在一起MVP 投影矩阵 × 视图矩阵 × 模型矩阵。然后把这个MVP矩阵传给顶点着色器每个顶点乘一下就行了。理解这个链路的意义在于当渲染结果不对时你知道该去检查哪个矩阵。3. 渲染管线GPU到底在背后做了什么3.1 从顶点到像素一条高度并行的流水线渲染管线是3D图形的核心执行引擎。你可以把它想象成一个工厂的流水线原材料顶点数据从一端进去经过一系列加工站最终从另一端出来的是屏幕上的像素颜色。现代GPU的渲染管线大致分为以下几个阶段顶点着色器、图元装配、光栅化、片元着色器、测试与混合。每个阶段都有明确的职责而且大部分阶段都是高度并行的——GPU可以同时处理成千上万个顶点或像素。顶点着色器是程序员可以编程的第一个阶段。它的输入是单个顶点的属性位置、法线、纹理坐标等输出是变换后的顶点位置和其他需要传递给后续阶段的数据。在这个阶段你通常会做MVP变换、计算光照方向、传递纹理坐标等。图元装配阶段把顶点组装成三角形。为什么是三角形因为三角形是最简单的多边形三个点一定共面而且任何多边形都可以拆分成三角形。这个阶段还会做裁剪把完全在视锥体外的三角形丢弃部分在视锥体内的三角形进行切割。光栅化是把三角形转换成片元的过程。你可以把片元理解成“候选像素”——它包含了位置、深度、颜色等信息但还没有最终确定是否要写入屏幕。光栅化的核心任务是判断哪些像素被三角形覆盖以及计算每个像素的重心坐标用于插值顶点属性。片元着色器是程序员可以编程的第二个阶段。它的输入是插值后的顶点属性输出是片元的颜色。在这个阶段你通常会做纹理采样、光照计算、阴影处理等。片元着色器的计算量通常比顶点着色器大得多因为一个三角形可能覆盖很多像素。最后是测试与混合阶段。深度测试决定片元是否被遮挡模板测试用于实现特殊效果混合阶段则处理透明物体的颜色混合。3.2 可编程管线和固定管线的区别为什么现代图形编程更灵活但也更复杂早期的图形API比如OpenGL 1.x使用的是固定管线。这意味着光照、纹理、变换等操作都有固定的公式和参数程序员只能通过设置开关和参数来调整效果。这种方式上手容易但灵活性极差——如果你想实现一个非标准的光照模型或者想做卡通渲染固定管线根本做不到。现代图形APIOpenGL 3.3、DirectX 11、Vulkan、Metal使用的是可编程管线。顶点着色器和片元着色器完全由程序员编写你可以实现任何你想要的算法。这种灵活性带来了巨大的创作空间但也意味着你需要自己处理很多之前由固定管线自动完成的事情。我个人的经验是如果你只是想做简单的3D展示用引擎Unity、Unreal、Three.js提供的内置材质就够了。但如果你想做独特的视觉效果或者需要针对特定硬件做优化那就必须深入理解可编程管线。我见过很多项目在后期遇到性能问题根源就是片元着色器写得太复杂或者顶点着色器做了太多不必要的计算。3.3 一个容易被忽略的细节顶点属性插值背后的透视校正当光栅化阶段把三角形转换成片元时它需要对顶点属性进行插值。比如一个三角形的三个顶点分别有不同的颜色那么三角形内部的像素颜色就是这三个顶点颜色的加权平均。这个加权平均的权重就是重心坐标。但这里有一个微妙的问题在透视投影下简单的线性插值是不正确的。为什么因为透视投影会让远处的物体变小这意味着屏幕上的像素间距和世界空间中的距离不是线性关系。如果直接对纹理坐标做线性插值远处的纹理会出现扭曲。解决方案是透视校正插值。GPU会自动对顶点属性进行透视校正确保插值结果在视觉上是正确的。这个细节在大多数情况下是透明的但当你手动实现一些高级效果比如自定义的光照模型或者屏幕空间反射时就需要意识到这一点。我在做一个地形渲染项目时曾经遇到过一个问题远处的纹理出现了明显的拉伸和扭曲。排查了很久才发现是因为我在片元着色器中手动计算纹理坐标时没有考虑到透视校正。后来改成让GPU自动插值问题就解决了。这个经历让我明白理解管线背后的数学原理能帮你快速定位那些“看起来莫名其妙”的渲染问题。4. 几何表示从三角形网格到隐式曲面4.1 三角形网格为什么是3D图形的“通用货币”在实时渲染中三角形网格是最常见的几何表示方式。几乎所有的游戏模型、建筑可视化场景、工业零件模型最终都会被转换成三角形网格。为什么是三角形因为三角形有三个无可替代的优势第一三个点一定共面不存在“弯曲”的问题第二任何多边形都可以三角化第三GPU的硬件设计就是围绕三角形优化的。一个三角形网格由顶点列表和索引列表组成。顶点列表存储每个顶点的位置、法线、纹理坐标等属性索引列表则指定哪些顶点组成一个三角形。这种“顶点索引”的结构可以有效地复用顶点数据——比如一个立方体只有8个顶点但如果不复用的话需要36个顶点12个三角形×3。在实际项目中网格的拓扑结构对渲染性能有很大影响。一个常见的优化手段是重新排列三角形的顺序让它们在内存中更连续从而提高缓存命中率。另一个手段是使用索引缓冲区减少顶点数据的重复传输。这些优化在移动端尤其重要因为移动GPU的带宽和缓存都比桌面GPU小得多。4.2 法线、切线和纹理坐标顶点属性的完整清单一个顶点除了位置之外通常还包含其他属性。法线用于光照计算它决定了表面在某个点上的朝向。切线和副切线用于法线贴图它们定义了纹理空间到世界空间的变换。纹理坐标UV用于纹理采样它告诉GPU应该从纹理的哪个位置取颜色。这些属性看起来简单但在实际使用中有很多细节需要注意。比如法线的归一化如果你在顶点着色器中对法线做了变换一定要重新归一化否则光照计算会出现错误。再比如纹理坐标的接缝问题当一个模型的UV在某个边缘处不连续时需要在那个边缘处复制顶点否则插值会出现问题。我在做一个角色渲染项目时曾经因为法线没有归一化导致光照看起来“发灰”。排查了很久才发现是因为在顶点着色器中对法线做了非均匀缩放但没有重新归一化。这个教训让我养成了一个习惯只要对法线做了任何变换就立即归一化不要省这一步。4.3 隐式曲面和参数化曲面什么时候该用非网格表示虽然三角形网格是主流但它并不是唯一的选择。在某些场景下隐式曲面和参数化曲面可能更合适。隐式曲面用一个函数F(x,y,z)0来定义表面。比如一个球体可以表示为x²y²z²-r²0。隐式曲面的优点是判断一个点在表面内部还是外部非常容易只需要看F的符号而且可以精确表示光滑曲面。缺点是直接渲染隐式曲面比较困难通常需要用Marching Cubes等算法转换成网格。参数化曲面用一个参数方程来定义表面。比如一个球体可以表示为(rsinθcosφ, rsinθsinφ, rcosθ)。参数化曲面的优点是可以精确控制表面的形状而且UV坐标天然就是参数域。缺点是参数化曲面在实时渲染中通常需要预先转换成网格。我在做科学可视化项目时经常需要渲染等值面。这种情况下隐式曲面加Marching Cubes是标准方案。但如果是要做产品展示或者游戏场景三角形网格仍然是首选。选择哪种表示方式取决于你的具体需求是需要精确的数学表示还是需要高效的实时渲染。5. 光照与着色让3D物体看起来“真实”的核心5.1 从Lambert到PBR光照模型的演进逻辑光照是3D图形中最能影响视觉真实感的因素之一。早期的光照模型非常简单比如Lambert漫反射模型只考虑光线方向和表面法线的夹角。这个模型计算量小但效果很“塑料”——它无法表现金属、布料、皮肤等不同材质的区别。后来出现了Phong模型和Blinn-Phong模型它们增加了镜面反射项可以表现高光。但Phong模型的高光是基于经验的没有物理依据。再后来基于物理的渲染PBR成为主流。PBR的核心思想是用物理学的原理来描述光线与表面的交互包括能量守恒、微表面理论、菲涅尔效应等。PBR的好处是材质参数在不同光照环境下都能保持一致的外观。这意味着美术师只需要调整一次材质就能在白天、夜晚、室内、室外等各种场景下都看起来合理。这对于大型项目来说是一个巨大的效率提升。但PBR也不是万能的。它的计算量比Phong模型大得多在移动端或者低端硬件上可能需要降级。而且PBR需要更精细的纹理输入比如粗糙度贴图、金属度贴图、环境光遮蔽贴图这对美术制作流程提出了更高的要求。5.2 阴影从Shadow Map到级联阴影和软阴影阴影是另一个让3D场景看起来真实的关键因素。没有阴影的场景物体会像“漂浮”在空中一样缺乏空间感。最常用的阴影技术是Shadow Map。它的原理很简单从光源的角度渲染一遍场景把深度信息存到一张纹理里。然后在正常渲染时把每个像素变换到光源空间比较它的深度和Shadow Map中的深度如果更远就说明在阴影中。但Shadow Map有很多问题。首先是锯齿由于Shadow Map的分辨率有限阴影边缘会出现明显的锯齿。解决方案是使用百分比渐近过滤PCF对周围多个像素的深度比较结果做平均。其次是级联阴影对于大场景单一分辨率的Shadow Map无法同时满足近处和远处的精度需求。级联阴影把视锥体分成多个层级每个层级用不同分辨率的Shadow Map。我在做一个开放世界场景时曾经因为Shadow Map的精度问题导致远处物体的阴影完全消失。后来用了级联阴影把视锥体分成四个层级近处用高分辨率远处用低分辨率问题才解决。这个经验告诉我阴影质量不是单一参数能决定的需要根据场景的尺度和相机的距离来综合调整。5.3 环境光照和全局光照让场景“活”起来直接光照只能处理光源直接照射到表面的情况。但现实中光线会在物体之间多次反弹形成间接光照。比如一个房间里有白色的墙壁和红色的地毯即使光源是白色的墙壁也会因为地毯的反射而带上一点红色。环境光照是一种简化的间接光照模拟。最简单的做法是用一张环境贴图通常是立方体贴图来提供各个方向的环境光。更高级的做法是用球谐函数Spherical Harmonics来压缩环境光信息或者用光照探针Light Probe来捕捉场景中的光照分布。全局光照GI是更精确的间接光照模拟但计算量很大。实时GI通常需要预计算比如Lightmap或者使用屏幕空间技术SSAO、SSR。我在做建筑可视化项目时Lightmap是标配——虽然烘焙需要时间但运行时的性能开销几乎为零而且效果非常稳定。6. 性能优化3D图形项目中最容易踩坑的地方6.1 Draw Call、批处理和实例化减少CPU和GPU之间的通信Draw Call是CPU向GPU发送的渲染命令。每次Draw Call都会带来一定的CPU开销因为需要设置渲染状态、绑定资源、提交命令。如果场景中有大量独立的物体Draw Call数量会急剧上升导致CPU成为瓶颈。减少Draw Call的常用手段是批处理。静态批处理把不会移动的物体合并成一个大的网格动态批处理把使用相同材质的物体合并。但批处理也有代价合并后的网格会占用更多内存而且动态批处理对顶点数量有限制。实例化是另一种减少Draw Call的技术。它允许你用一次Draw Call渲染多个相同的物体每个物体可以有不同的变换矩阵和颜色。这在渲染大量树木、草地、粒子时非常有效。我在做一个城市可视化项目时场景中有上万栋建筑。如果每栋建筑一个Draw Call帧率直接掉到个位数。后来用了实例化把相同类型的建筑合并渲染Draw Call从上万降到了几十帧率恢复到了60帧。这个经历让我深刻体会到在3D图形中性能优化往往比效果调优更重要。6.2 纹理压缩和Mipmap显存和带宽的平衡术纹理是3D场景中占用显存最多的资源之一。一张4096x4096的RGBA纹理占用64MB显存如果场景中有几十张这样的纹理显存很快就会耗尽。纹理压缩是解决这个问题的关键。常见的压缩格式包括ETC、ASTC、BC系列。这些格式在压缩比和画质之间有不同的权衡。比如ASTC的压缩比可以从4x4到12x12灵活调整适合移动端BC7的画质最好适合桌面端。Mipmap是另一个重要的优化手段。它预先生成一系列逐级缩小的纹理当物体离相机较远时使用较小的Mipmap级别。这不仅能减少纹理采样时的缓存不命中还能避免远处纹理的闪烁摩尔纹。我在移动端项目中最常遇到的性能问题就是纹理带宽。移动GPU的带宽通常只有桌面GPU的十分之一左右如果纹理没有压缩或者Mipmap没有正确生成帧率会非常不稳定。我的经验是在移动端所有纹理都必须压缩而且要根据目标设备选择合适的压缩格式。6.3 过度绘制和深度测试像素级别的性能陷阱过度绘制是指同一个像素被多次写入。在3D场景中如果物体按照从远到近的顺序渲染远处的物体会先被绘制然后被近处的物体覆盖造成浪费。解决方案是使用深度预通道Depth Pre-Pass或者按照从近到远的顺序渲染不透明物体。深度测试是GPU自动进行的优化如果一个片元的深度比深度缓冲区中的值大说明它被遮挡了可以直接丢弃。但深度测试只有在片元着色器执行之后才能进行除非使用Early-Z技术。Early-Z允许GPU在片元着色器之前做深度测试从而跳过被遮挡片元的着色计算。我在做一个室内场景时曾经因为大量透明物体玻璃、窗帘导致过度绘制严重。透明物体不能使用Early-Z而且需要按照从远到近的顺序渲染。后来我把透明物体分层先渲染不透明的再渲染半透明的最后渲染完全透明的性能有了明显改善。7. 实战中的经验与避坑指南7.1 从零搭建一个3D渲染器的关键决策点如果你打算从零开始写一个3D渲染器有几个关键决策会影响后续的开发效率和最终效果。第一个决策是使用什么图形API。OpenGL上手快跨平台好但驱动质量参差不齐。DirectX 12和Vulkan性能好控制精细但学习曲线陡峭。Metal是苹果平台的专属选择。我的建议是如果是学习目的从OpenGL或者WebGL开始如果是商业项目根据目标平台选择。第二个决策是渲染管线的架构。前向渲染简单直接适合光源数量少的场景。延迟渲染可以处理大量光源但对透明物体和MSAA支持不好。Forward是折中方案先用计算着色器做光源剔除再用前向渲染。选择哪种架构取决于你的场景中光源数量和材质复杂度。第三个决策是资源管理策略。纹理、网格、着色器这些资源什么时候加载、什么时候释放、如何复用这些看似琐碎的问题在大型项目中会直接影响稳定性和性能。我见过很多项目在后期出现内存泄漏或者加载卡顿根源都是资源管理没有设计好。7.2 调试3D渲染问题的系统化方法3D渲染的问题往往表现为“画面不对”但原因可能出在数学、数据、API调用或者硬件兼容性等各个层面。我总结了一套系统化的排查方法。第一步是隔离问题。把场景简化到最小可复现的状态一个三角形、一个光源、一个相机。如果最小场景也有问题那说明是基础设置的问题如果最小场景正常逐步增加复杂度直到问题复现。第二步是可视化中间结果。把法线、深度、UV、光照等中间结果直接输出成颜色可以快速定位问题出在哪个环节。比如如果法线可视化看起来不对那问题很可能出在法线变换或者归一化上。第三步是检查矩阵。MVP矩阵是很多问题的根源。我通常会写一个辅助函数把矩阵打印出来然后手动验证几个关键点的变换结果。虽然笨但非常有效。第四步是查文档和社区。图形API的文档有时候不够详细但社区里往往有人遇到过类似的问题。我在遇到Vulkan的同步问题时就是在社区里找到了详细的解释和解决方案。7.3 跨平台3D开发的兼容性陷阱跨平台3D开发最大的挑战是硬件和驱动的差异。同一个着色器代码在NVIDIA显卡上正常在AMD显卡上可能就编译失败在桌面端正常在移动端可能就性能崩溃。纹理格式的兼容性是一个典型问题。不同平台支持的压缩格式不同你需要为每个平台准备不同的纹理资源。而且有些平台对纹理尺寸有限制比如某些移动GPU不支持非2的幂次纹理。浮点精度是另一个陷阱。移动GPU通常对高精度浮点highp的支持有限如果你的着色器大量使用highp可能会导致性能下降甚至编译失败。我的经验是在移动端着色器中尽量使用mediump只在必要时使用highp。还有一个容易被忽略的问题是着色器编译时间。在Windows上着色器编译通常很快但在某些游戏主机或者移动设备上编译可能需要几秒钟。如果游戏在运行时编译着色器会导致明显的卡顿。解决方案是预编译着色器或者使用着色器缓存。8. 3D图形的未来方向与个人学习建议8.1 实时光线追踪和路径追踪的工程化落地光线追踪曾经是离线渲染的专利但近年来实时光线追踪逐渐成为可能。硬件厂商推出了专门的光线追踪加速单元图形API也提供了相应的支持。实时光线追踪目前主要用于反射、阴影和全局光照。它最大的优势是能提供物理正确的效果但代价是计算量大。在实际项目中通常会将光线追踪和光栅化结合使用光栅化处理主要几何体光线追踪处理反射和阴影。路径追踪是更精确的渲染方法它模拟光线在场景中的完整传播路径。但路径追踪的收敛速度很慢通常需要降噪算法来辅助。我在做产品可视化时曾经尝试过实时光线追踪效果确实惊艳但需要仔细调整降噪参数否则画面会有明显的噪点。8.2 云渲染和WebGPU3D图形的新战场云渲染把渲染任务放到服务器上客户端只需要接收视频流。这种方式可以让低端设备也能运行高质量的3D应用但网络延迟和带宽是主要瓶颈。WebGPU是下一代Web图形API它提供了比WebGL更底层的硬件访问能力。WebGPU支持计算着色器、多线程渲染等高级特性让Web端的3D应用可以达到接近原生的性能。我在做Web端3D可视化时已经明显感受到WebGPU带来的性能提升。8.3 给不同阶段学习者的具体建议如果你刚开始学3D图形我的建议是先学一门图形APIOpenGL或WebGL同时补数学基础线性代数、微积分。不要一上来就学引擎因为引擎会隐藏太多细节让你无法理解底层原理。如果你已经会用一个引擎但想深入理解渲染原理我的建议是尝试自己写一个简单的渲染器。不需要很复杂能渲染一个带纹理和光照的立方体就行。这个过程会让你对渲染管线的每个阶段都有切身的体会。如果你在做实际项目我的建议是性能优化要趁早。不要等到项目后期才发现帧率不够。在项目初期就建立性能基准定期做性能测试这样问题才能及时发现和解决。最后我想说的是3D图形是一个需要长期积累的领域。不要指望看几篇文章或者做几个Demo就能精通。但只要你保持好奇心和动手习惯每解决一个问题你对这个领域的理解就会深一层。我在这个领域摸爬滚打这么多年仍然经常遇到新的挑战和新的发现。这大概就是3D图形的魅力所在——它永远有值得探索的空间。
返回列表