三维坐标如何变成彩色渐变:从顶点到片元的插值原理

0 阅读3分钟

一、概念

在 GPU 渲染中,颜色的计算分为两个阶段:

  1. 顶点着色器 (Vertex Shader)

    • 只对每个顶点执行一次。
    • 可以为每个顶点输出不同的属性,例如位置。
  2. 片元着色器 (Fragment Shader)

    • 对三角形覆盖的每个像素执行一次。
    • 接收到的是顶点属性经过插值后的结果

这就是为什么虽然三角形只有三个顶点,却能让三角形内部的每个像素显示出不同的颜色。

const material = new THREE.ShaderMaterial({
  glslVersion: THREE.GLSL3, // 必须指定 GLSL3 才能使用 in/out
  vertexShader: `
  out vec3 vPosition;       // 传递给片元 shader
    void main() {
    vPosition = position;
      gl_Position = vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    out vec4 FragColor; // GLSL 3.0 输出
    in vec3 vPosition;        // 来自顶点 shader 的插值
    void main() {
      FragColor = vec4(vPosition * 0.5 + 0.5, 1.0);
    }
  `
});

二、原理

在你的代码里:

vPosition = position;               // 顶点坐标 (x,y,z)
FragColor = vec4(vPosition * 0.5 + 0.5, 1.0);
  1. 每个顶点坐标不同

    • 三角形有三个顶点 (x,y,z),每个值不一样。
    • 经过 *0.5+0.5 映射后,每个顶点都对应一个不同的 RGB 颜色。
  2. GPU 自动插值

    • 光栅化时,GPU 会把三角形内部的像素分配给三个顶点。
    • 每个像素的位置不同,它的 (x,y,z) 由三个顶点的坐标加权平均得到。
    • 因此,每个像素的 vPosition 也不同 → 映射到颜色后也不同。
  3. 结果:渐变色

    • 三角形的三个顶点是三种不同颜色。
    • 内部像素的颜色是三者插值混合出来的。
    • 所以三角形内部会显示为彩色渐变。

三、实例演算(注:在glsl 计算与js中不一样,例 pos = (1,1,0); posT = (pos, 1.0) 能够得到 (1,1,1,1.0) 如是加减乘除是对每一个值 进行操作,例+0.5 为(1.5.1.5.1.5.1.5))

假设三角形三个顶点:

  1. A 点(-1,-1,0)

    • (0,0,0.5) → 深蓝色
  2. B 点(1,-1,0)

    • (1,0,0.5) → 紫红色
  3. C 点(0,1,0)

    • (0.5,1,0.5) → 绿色偏粉

在渲染时:

  • 边 AB 上的像素:颜色从蓝色逐渐过渡到紫红色。
  • 边 AC 上的像素:颜色从蓝色逐渐过渡到绿色。
  • 三角形内部:任意一点的颜色 = A、B、C 三个颜色加权平均,结果就是彩色渐变。

四、为什么没写入颜色也能变彩色?

关键在于 position 本身就是变化的

  • 你没有显式写死颜色,而是用 (x,y,z) 作为颜色来源。
  • 不同像素位置 → 不同插值后的 (x,y,z) 值。
  • 这些值经过 *0.5+0.5 转换后直接用作 RGB。

因此,即使你没写 uniformattribute 的颜色,坐标本身就提供了差异,结果自然就是彩色的。


五、总结

  • 三个顶点各自有不同的坐标 (x,y,z)
  • 映射后变成三个不同的 (r,g,b) 颜色。
  • GPU 在片元阶段自动插值 → 内部像素颜色随位置变化。
  • 最终三角形呈现渐变彩色,而不是单一颜色。

换句话说:彩色效果来自于“顶点位置的不同 + GPU 的插值机制”。


本文部分内容借助 AI 辅助生成,并由作者整理审核。