网站开发认证考试wordpress如何在地址栏中加网站logo
网站开发认证考试,wordpress如何在地址栏中加网站logo,不写代码门户网站建设,珠海企业网站设计公司先把一句话摆在最前面#xff1a;顶点阶段只是把“点”算好了位置#xff0c;
图元装配 裁剪这一步#xff0c;干的事情就是#xff1a;
把这些点按索引连成三角形#xff0c;然后把跑出摄像机视野外的那部分三角形切掉或扔掉。你可以把它想象成#xff1a;
顶点阶…先把一句话摆在最前面顶点阶段只是把“点”算好了位置图元装配 裁剪这一步干的事情就是把这些点按索引连成三角形然后把跑出摄像机视野外的那部分三角形切掉或扔掉。你可以把它想象成顶点阶段一个个灯泡都拧好了位置对了图元装配根据电路图把这些灯泡连成一串串“灯带”三角形裁剪把掉到舞台外、遮挡掉的那些灯带剪掉不要再交给后面去点亮光栅化、着色。这一章节我们专门讲这两步图元装配Primitive Assembly顶点 → 点/线/三角形重点讲三角形怎么从“顶点 索引”装配起来。裁剪Clipping哪些三角形完全看不到直接扔掉哪些三角形一半在视野里一半在外面要在边界上“切一刀”只留里面那半。目标是用大白话 足够细节让你脑海里能出现一个清晰的动画“顶点变完位置之后GPU 是怎么把它们连成一个个三角形再在视锥体的边界上剪来剪去的。”一、先回顾一下“流水线”图元装配 裁剪在第几道工序把整条渲染流水线简单复习一遍只看传统光栅化管线CPU 阶段准备顶点数据位置、法线、UV、索引……设置各种状态Shader、纹理、RenderTarget 等调用 DrawXxx告诉 GPU“把这堆数据画出来”。顶点阶段Vertex Shader对每个顶点local → world → view → clip算出裁剪空间坐标(x, y, z, w)顺带把法线、UV 等也处理一下传下去。图元装配Primitive Assembly← 我们要讲的第一个主角按照指定方式点列表/线列表/三角列表/三角条带……把一个个顶点“组装”成一个个图元通常是三角形。裁剪Clipping← 第二个主角判断三角形是否在可见体视锥 / 裁剪盒子 / NDC 盒子里完全在外扔掉部分在内沿裁剪平面把三角形切开保留可见部分。透视除法 视口变换Perspective Divide Viewport Transformndc clip / w得到 [-1,1] 立方体坐标映射到具体屏幕像素坐标。光栅化Rasterization把每个三角形变成一堆像素片元准备逐像素着色。片元着色器Fragment / Pixel Shader对每个像素算颜色、光照、贴图、阴影。测试 混合Depth/Stencil/Blend深度测试、模板测试、颜色混合透明等写入最终帧缓冲。所以图元装配 裁剪正好夹在“顶点变换”和“光栅化”之间起到“从点到面并剪掉不需要的面”的承上启下作用。二、图元装配把点连成三角形这一步到底是怎么做的2.1 顶点只是“散点”要靠“连接规则”变成几何形状CPU 提供给 GPU 的数据主要有两块顶点缓冲Vertex Buffer一条数组[v0, v1, v2, v3, v4, v5, ...]每个 v 里有 position、normal、uv、color 等。索引缓冲Index Buffer另一条数组[i0, i1, i2, i3, i4, i5, ...]每三个索引组成一个三角形(i0, i1, i2)→ 三角形 0(i3, i4, i5)→ 三角形 1…GPU 在图元装配阶段要做的就是按照你指定的“图元类型primitive type”用索引把顶点排排坐拼成一个个图元。2.2 常见几种图元类型点 / 线 / 三角形最常见的是三种点列表Point List每个顶点独立画一个点用得不多更多是调试或点云渲染。线列表 / 线条Line List / Line Strip每两个顶点画一条线或者头尾相接画连续的折线。三角形列表 / 条带Triangle List / Triangle Strip三角形列表每 3 个顶点一个三角形三角形条带复用前两个顶点每增一个点多出一个三角形。游戏里绝大多数可见物体都是用三角形表示的。所以我们重点说三角形。2.3 三角形列表Triangle List最常用、最直观假设顶点数组vertices [v0, v1, v2, v3, v4, v5, ...]索引数组indices [0, 1, 2, 2, 3, 0, ...]绘制模式TRIANGLES三角形列表。图元装配的逻辑大概是for(k 0; k indices.length; k 3): i0 indices[k] i1 indices[k1] i2 indices[k2] 三角形 T (vertices[i0], vertices[i1], vertices[i2])这样(0,1,2) → 第一个三角形(2,3,0) → 第二个三角形……每个顶点已经在顶点着色器里被变换到了 Clip Space有 x,y,z,w图元装配时只是把它们按索引分组。2.4 三角形条带Triangle Strip节省顶点数据的一种方式为了节省带宽有时候会用 Triangle Strip顶点顺序v0, v1, v2, v3, v4, v5...构造方式三角形 0(v0, v1, v2)三角形 1(v1, v2, v3)三角形 2(v2, v3, v4)…优点共边的三角形能共享两个顶点每增加一个顶点就多一个三角形对一些规则网格来说很适合。缺点拓扑受限制现在很多引擎直接用 Triangle List 了简单粗暴又直观。你理解了 List再知道 Strip 是“共享前两个”的变种就够了。2.5 顶点阶段和图元装配的边界谁干啥顶点阶段对每一个顶点独立计算它的位置和携带的其他数据图元装配按指定方式把这些独立的顶点组装成图元线/三角形。想象一下顶点阶段像是“给每个演员排好站位”图元装配就是“导演拿着剧本说你们三个组成一组跳这个舞、你们三个组下一个”。三、裁剪Clipping把视野外的三角形剪掉或切一刀装好三角形之后并不是全都要画。有些完全在视野外有些只露出一点点。裁剪阶段就是根据一个“标准裁剪体”Clip Volume把“三角形 视野”的交集算出来完全在外扔掉完全在内原样保留部分交叉在边界上切开生成新的三角形或多边形只保留里面的部分。3.1 裁剪空间里的“标准盒子”前面顶点阶段我们把点变到了Clip Space然后 GPU 做透视除法得到 NDCNormalized Device CoordinatesNDC 中x、y、z大概都在 [-1,1] 范围内的点是可见的超出这个范围的就是视野外。裁剪的时候有两种实现方式在 Clip Space 下直接裁剪使用约束-w x w-w y wz 同理或在透视除法后在 NDC 下裁剪使用-1 x 1-1 y 1z 范围等。具体取决于 GPU 内部实现细节对我们而言可以简单理解为有一个“长方体视野盒子”超出这盒子外的三角形都要处理一下。3.2 裁剪的六个平面左、右、上、下、近、远无论是视锥还是标准裁剪盒子最终都会变成六个裁剪平面左平面右平面上平面下平面近裁剪面near plane远裁剪面far plane。裁剪的逻辑就是对每个三角形依次判断它对这几个平面的关系。简单来说对于一个平面三角形三个顶点都在平面的“内侧”这个三角形对这个平面来说是“完全在内”的三个都在“外侧”对这个平面来说“完全在外”可以整个扔掉有的在内、有的在外需要在平面和三角形的边的交点处切开。对所有平面都处理完剩下的就是实际会被绘制的部分。3.3 完全在外扔掉就完了剪掉整个三角形最简单的情况比如一个三角形完全在相机视野的左边之外对“左裁剪平面”来说它三个点的 x 坐标全都 -wClip Space或者 -1NDC这种直接丢弃这个三角形连光栅化都不需要不会参与后面任何计算。这就是 GPU 为什么能很高效很多你以为“存在的”三角形其实根本不会走到像素阶段。3.4 完全在内原样送去下一步如果三个顶点都在所有裁剪平面的“内侧”那这个三角形不需要裁剪直接交给后续透视除法 光栅化也就是完整三角形原样保留。3.5 部分在内、部分在外要在边界上“切一刀”最麻烦的是中间情况有一个或两个顶点在视野内剩下的在外三角形一部分在可见空间有一部分伸出去了。解决方案把“在内”的部分保留把“在外”的部分切掉在裁剪平面和三角形边的交点处创建新的顶点。这样原来的一个三角形会变成一个新的三角形或者两个新的三角形具体看哪几条边和裁剪平面相交。下面我们用直观例子仔细讲。四、详细拆解“裁剪三角形”的过程带具体情况为了好讲我们只考虑在某一个平面上的裁剪比如左平面然后理解 GPU 是怎么“切三角形”的。记号Iinside顶点在平面内侧可见空间内Ooutside在平面外侧。三角形有三个点可能有这些情况I I I → 全在内保留不切O O O → 全在外扔掉I I O → 两个内一个外I O O → 一个内两个外O I O → 仍旧是“一内两外”的组合只是顺序不同还有其他组合但本质就是“一个内两个外”或“两个内一个外”。我们分别说 3 和 4。4.1 情况一两内一外I I O → 三角形变成两个小三角形假设顶点是v0内v1内v2外。三角形 (v0, v1, v2)。边有三条v0-v1全在内无需切v1-v2穿过平面v2-v0穿过平面。在两个穿过平面的边上会产生两个交点i1v1-v2 与平面的交点i2v2-v0 与平面的交点。原三角形的一部分被切掉剩下的那部分几何形状其实是一个“凸四边形”GPU 会把它再拆为两个三角形T1 (v0, v1, i1)T2 (v0, i1, i2)这样原来的三角形变成了两个新的三角形而这两个三角形都完全在平面内侧可见空间内。4.2 情况二一内两外I O O → 三角形变成一个小三角形假设v0内v1外v2外。三条边v0-v1穿过平面v0-v2穿过平面v1-v2全在外无需理会。两个穿过平面的边上产生两个交点i1v0-v1 与平面的交点i2v0-v2 与平面的交点。可见的那部分是一个小三角形T (v0, i1, i2)所以原来的大三角形被平面“切掉大部分”只剩下面向内侧的小三角形 T。4.3 交点坐标怎么算——线性插值三角形的边是线段比如边 v1-v2v1 在内v2 在外或相反平面可以表示为一个方程ax by cz d 0或 N·p d 0。我们可以用参数 t 描述从 v1 向 v2 的点P(t) v1 t * (v2 - v1), t ∈ [0,1]把 P(t) 代入平面方程解出 t就得到交点的位置。但在实际硬件实现中Clip Space / NDC 的裁剪范围比较规整可以用更简单的方式算 t —— 比如对某一维x 或 y 或 z做插值。举个简单例子假设我们在 NDC 中对 x 1 的平面裁剪右平面v1.x 0.5内侧v2.x 2.0外侧我们想要 P.x 1 P v1 t * (v2 - v1) P.x v1.x t * (v2.x - v1.x) 0.5 t * (2.0 - 0.5) 1 → t (1 - 0.5) / (2.0 - 0.5) 0.5 / 1.5 1/3于是交点 P v1 (1/3) * (v2 - v1)同理顶点的其他属性UV、颜色、法线等也要用同样的 t 做插值这样裁剪后的顶点仍然有合理的纹理和光照信息。裁剪 在视野盒子的边上沿着边线找到“过界点”然后用线性插值算出新的顶点包括 position、UV、color 等。五、裁剪的结果三角形数量会变化顶点数量也会增加裁剪的一个直接影响三角形数量可能变多顶点数量会“临时增加”。举例原来只有一个三角形 I I O 的情况被裁剪成两个三角形裁剪过程中产生的新顶点不会回写到原始顶点缓冲而是作为流水线中的临时数据继续往下传。这一步一般都在 GPU 的固定功能或高度优化的模块里完成对我们编程的人来说你看不到“裁剪后的新索引缓冲”但可以知道“经过裁剪以后被送入光栅化阶段的三角形都是完整在视野内的”。六、裁剪存在的意义省算力、避免乱画、保证正确显示为什么要费劲裁剪直接全部三角形往下画不行吗从三个角度看它的重要性。6.1 性能提前扔掉看不到的三角形如果不裁剪所有三角形都送去光栅化 → 每个三角形都要算覆盖哪些像素 → 再跑片元 Shader即使这些三角形完全在屏幕外仍然浪费大量计算。裁剪后完全在外的直接扔掉部分在内的只把在内的那一部分交给后面。节省像素级计算是高性能渲染的关键之一。6.2 正确性防止奇怪的投影或错误插值当一个三角形大部分在视野外一小部分在内如果不正确裁剪插值后的 UV/深度可能会出现畸形最严重的可能导致将视野外的东西错误地绘制到屏幕上artifact。裁剪时正确计算交点 插值能保证三角形的可见部分在边界上被“干净利落地切断”没有超出视野的碎片跑进来捣乱。6.3 为了后面透视除法和深度计算顺利进行记得在 Clip Space 中我们用规则-w x w等作为裁剪标准透视除法后我们只希望 NDC 在 [-1,1] 的立方体里后面的视口映射和深度测试都建立在这个基础上。如果不在 Clip/NDC 阶段裁剪把非法的点交给后面透视除法可能得到无限大比如 w→0视口映射可能把东西打到屏幕远外的某个鬼位置深度缓冲也会被写入不可预期的值。裁剪阶段的存在保证了“进入光栅化阶段的所有三角形都处在一个合理的合法空间范围内。”七、和背面剔除Backface Culling怎么区分裁剪Clipping和剔除Culling容易混淆简单区分一下7.1 剔除Culling不看背面就别画背面剔除是在图元装配后、光栅化前的另一道操作根据三角形顶点在屏幕 / NDC 中的顺序顺时针/逆时针判断它是面向相机还是背对相机默认只画“正面”背面直接丢掉减少绘制负担同时符合“物体内部看不到”的直觉。它不修改三角形形状只决定画不画整个三角形。7.2 裁剪Clipping针对视野边界“几何切割”裁剪会根据视锥/裁剪盒的边界平面切割三角形可能把一个三角形拆成零个全外、一个一内两外、两个两内一外修改的是几何形状本身。可以这么记剔除判断“要不要画这个三角形”裁剪判断“这个三角形在视野的哪部分要画、哪部分不要”。八、从开发者的视角你能“控制”或“感知”这一阶段的什么虽然图元装配 裁剪是 GPU 内部的“固定功能阶段”但我们可以从几个方向理解或影响它。8.1 通过 DrawCall 的模式影响图元装配比如在 OpenGL 中glDrawElements(GL_TRIANGLES,...);// 三角形列表glDrawArrays(GL_TRIANGLE_STRIP,...);// 三角形条带glDrawArrays(GL_LINES,...);// 线glDrawArrays(GL_POINTS,...);// 点在 DirectX / Vulkan 中也是类似传入一个PrimitiveTopology图元拓扑。你指定了拓扑就等于告诉 GPU“图元装配阶段请按照我给你的这种规则把顶点连起来。”8.2 控制裁剪平面特别是 near / farProjection 矩阵参数near, far, fov, aspect会影响裁剪范围near 过大离相机太近的东西被裁掉可能造成“模型被截断”的效果near 过小深度缓冲精度变差Z-fighting 增多far 过小远处的物体提前被裁掉突然消失far 过大同样影响深度精度。注意near 不要设得太小比如 0.001一般游戏中 near 用 0.1 / 0.3 / 1 之类比较合理。8.3 使用裁剪平面做特殊效果镜子、水面、门户有些高级渲染技巧会显式地设置裁剪平面比如渲染镜子反射只想画镜子平面“另一侧”的世界水面反射只渲染水面以上或水面以下传送门定义一个自定义裁剪平面只渲染通过门框看到的部分。虽然细节实现会因 API 而异但本质上就是给 GPU 增加一个或多个裁剪平面让裁剪阶段帮我们“切掉不想画的空间”。九、把整个“图元装配 裁剪”的过程缩成一条直观的“动画”把这两个阶段串起来你可以在脑海里想象这样一段动画顶点阶段结束时空中漂浮着许多点每个点都有一个 Clip Space 坐标 (x,y,z,w)它们各自带着法线、UV、颜色等信息。图元装配GPU 拿着索引缓冲“0,1,2 你们三组成一个三角形2,3,0 你们也是4,5,6 你们再来一组……”一堆三角形在“裁剪空间”里被连成网。裁剪阶段想象有一个透明的长方体-w…w 或 -1…1 的盒子所有三角形都漂在这个盒子里有的完全在盒子外有的穿过边界有的完好地在盒子里面。GPU 开始检查每个三角形完全在外整块扔掉完全在内保留穿过盒子在盒子边缘的地方“切一刀”把伸出去那部分削掉只保留盒子里面的多边形再拆成三角形。最终结果被送往光栅化阶段的三角形全部都老老实实待在裁剪盒子范围内每个三角形都精准地只覆盖它在屏幕上“该出现的那一块区域”。十、最后用几句话再把这两步刻进脑子里图元装配Primitive Assembly把已经在 Clip Space 的顶点按拓扑TRIANGLES / STRIP 等组装成图元关键数据来源是顶点缓冲 索引缓冲输出的是一个个三角形以及线/点。裁剪Clipping针对每个三角形检查它与“可见空间盒子”的关系全在内保留全在外丢弃一部分在内一部分在外在边界平面算交点切出新的三角形。交点用线性插值计算顶点的所有属性position/UV/color 等都一起插值。为什么要有它们图元装配顶点阶段只算点不知道谁跟谁是一组图元装配帮你“连线成形”把数学点变成几何面。裁剪防止“视野外的面”浪费后续计算保证进入光栅化的几何都在合法范围内避免奇怪投影和深度错误。你在代码里能看到什么通过 DrawCall 设定 PrimitiveTopology点/线/三角通过 Projectionnear/far/fov间接影响裁剪范围有时会用额外裁剪平面做高级效果镜子、水面、传送门。如果用一句特别形象的话收尾顶点阶段是“点位算好了”图元装配是“把这些点连出三角形来”裁剪是“拿剪刀沿着视野盒子的边把跑出去的部分咔嚓掉”剩下的干干净净的三角形才会被送去变成一堆像素最终在屏幕上组成你看到的那一帧画面。