着色器

概念:attribute 用于向顶点着色器,传输几何图形待处理的各种属性,例如:顶点坐标,UV 坐标等等

注意:attribute 只能用于顶点着色器中,值在运行时会从几何图形属性中取值

点击查看代码
function createBasic() {
  // 目标:着色器变量 - attribute 使用
  // 作用:用于向顶点着色器中传入几何图形待处理的各种属性,例如:顶点坐标,UV 坐标等
  // 默认情况下几何图形 attribute 属性和值都被 ShaderMaterial 注入顶点着色器内了
  // 需要额外传递其他内容时使用 attribute
  // 注意:attribute 只能用于顶点着色器中,用于修饰浮点数向量
 
  const geometry = new THREE.PlaneGeometry(1, 1);
  console.log(geometry)
  geometry.setAttribute('position2', geometry.attributes.position)

  const material = new THREE.ShaderMaterial({
    vertexShader: `
      attribute vec3 position2;
      void main() {
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position2, 1.0);
      }
    `,
    fragmentShader: `
      void main() {
        gl_FragColor = vec4(0, 1.0, 0, 1.0);
      }
    `
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}
概念:uniform 可在顶点或片元着色器,接收全局参数使用

使用:

1.材质中传入 uniforms 属性(变量和值)

2.着色器中使用 uniform 定义同名变量接收

3.使用此变量与顶点坐标做效果

注意:uniform 是只读的

点击查看代码
function createBasic() {
  // 目标:着色器变量-uniform
  // 作用:接收全局参数使用,可在顶点/片元着色器中接收使用
  // 注意:uniform 是只读的
  // 步骤:
  // 1. 着色器材质中传入 uniforms 属性并传入变量和值
  // 2. 着色器代码中使用 uniform 定义同名变量接收
  // 3. 使用此变量在顶点坐标中
 
  const geometry = new THREE.PlaneGeometry(1, 1);
  geometry.setAttribute('position2', geometry.attributes.position)

  const material = new THREE.ShaderMaterial({
    // 2. 着色器代码中使用 uniform 定义同名变量接收
    vertexShader: `
      attribute vec3 position2;

      uniform float posX;

      void main() {
        // gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position2, 1.0);

        vec4 v = vec4(position2, 1.0);
        v.x += posX;

        gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
      }
    `,
    fragmentShader: `
      void main() {
        gl_FragColor = vec4(0, 1.0, 0, 1.0);
      }
    `,
    // 1. 着色器材质中传入 uniforms 属性并传入变量和值
    uniforms: {
      posX: {
        value: 2.0 // 初始值位移 x 轴 2 个单位
      }
    }
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}
概念:varying 将顶点着色器中数据,传递给片元着色器,一般是几何对象相关的属性

使用:借助 UV 坐标实现渐变色

1.顶点着色器中定义 varying 变量,保存 uv 坐标

2.片元着色器定义 varying 变量,自动接收 uv 坐标做颜色使用

点击查看代码

function createBasic() {
  // 目标:着色器变量-varying
  // 作用:把顶点着色器内变量,传递给片元着色器内使用
  // 步骤:
  // 1. 顶点着色器中定义 varying 变量,保存 uv 坐标
  // 2. 片元着色器中定义 varying 变量,自动接收 uv 坐标值,作为颜色使用
 
  const geometry = new THREE.PlaneGeometry(1, 1);
  geometry.setAttribute('position2', geometry.attributes.position)

  const material = new THREE.ShaderMaterial({
    vertexShader: `
      attribute vec3 position2;

      uniform float posX;

      // 1. 顶点着色器中定义 varying 变量,保存 uv 坐标
      varying vec2 myUV;

      void main() {
        // 几何图形的 uv 坐标赋予保存
        myUV = uv;

        // gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position2, 1.0);

        vec4 v = vec4(position2, 1.0);
        v.x += posX;

        gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
      }
    `,
    fragmentShader: `
      // 2. 片元着色器中定义 varying 变量,自动接收 uv 坐标值,作为颜色使用
      varying vec2 myUV;

      void main() {
        gl_FragColor = vec4(myUV.x, myUV.y, 0, 1.0);
      }
    `,
    uniforms: {
      posX: {
        value: 2.0
      }
    }
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}
使用:借助 UV 坐标实现渐变色

公式:直接用 y 轴坐标作为 rgb 颜色

点击查看代码
function createBasic() {
  // 目标:使用:借助 UV 坐标实现渐变色
  // 公式:直接用 y 轴坐标作为 rgb 颜色
  const geometry = new THREE.PlaneGeometry(1, 1);
  geometry.setAttribute('position2', geometry.attributes.position)

  const material = new THREE.ShaderMaterial({
    vertexShader: `
      attribute vec3 position2;

      uniform float posX;

      varying vec2 myUV;

      void main() {
        // 几何图形的 uv 坐标赋予保存
        myUV = uv;

        // gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position2, 1.0);

        vec4 v = vec4(position2, 1.0);
        v.x += posX;

        gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
      }
    `,
    fragmentShader: `
      varying vec2 myUV;

      void main() {
        // float color = myUV.y; // 上白下黑
        float color = 1.0 - myUV.y; // 上黑下白
        gl_FragColor = vec4(color, color, color, 1.0);
      }
    `,
    uniforms: {
      posX: {
        value: 2.0
      }
    }
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}
目标:实现波浪效果

使用:

1.增加几何图形顶点数量

2.顶点着色器控制 z 轴坐标位置

建议:收集公式 / 学习图形学+数学知识

调试:可以在 JS 中带入坐标打印数值观察调试

点击查看代码
function createBasic() {
  // 目标:实现波浪效果
  // 使用:
  // 1. 增加几何图形顶点数量
  // 2. 顶点着色器控制 z 轴坐标位置

  // 1. 增加几何图形顶点数量
  const geometry = new THREE.PlaneGeometry(1, 1, 64, 64);
  geometry.setAttribute('position2', geometry.attributes.position)

  const material = new THREE.ShaderMaterial({
    vertexShader: `
      attribute vec3 position2;

      uniform float posX;

      varying vec2 myUV;

      void main() {
        myUV = uv;

        // gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position2, 1.0);

        vec4 v = vec4(position2, 1.0);
        v.x += posX;
        
        // 2. 顶点着色器控制 z 轴坐标位置
        v.z = sin(v.x * 10.0) * 0.1;
        v.z += sin(v.y * 10.0) * 0.1; 

        gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
      }
    `,
    fragmentShader: `
      varying vec2 myUV;

      void main() {
        // float color = myUV.y; // 上白下黑
        float color = 1.0 - myUV.y; // 上黑下白
        gl_FragColor = vec4(color, color, color, 1.0);
      }
    `,
    uniforms: {
      posX: {
        value: 2.0
      }
    },
    side: THREE.DoubleSide
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}
目标:实现旋转效果

核心:所有物体都可以通过顶点着色器和片元着色器控制

难点:控制的计算过程,数学公式的使用

点击查看代码
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 2. 定义全局变量 material
let scene, camera, renderer, controls, material
function init() {
  scene = new THREE.Scene()
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
  camera.position.set(0, 0, 5)
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  document.body.appendChild(renderer.domElement)

  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true

  const axesHelper = new THREE.AxesHelper(5)
  scene.add(axesHelper)
};


function createBasic() {
  // 目标:实现旋转效果
  const geometry = new THREE.PlaneGeometry(1, 1, 64, 64)
  material = new THREE.ShaderMaterial({
    vertexShader: `
      // 4. 接收时间值-作为旋转角度
      uniform float myTime;
      void main() {
        float angle = myTime; // 旋转角度(0-360数值之间)
        float radian = radians(angle); // 角度转弧度(0-2PI)
        float cosV = cos(radian); // 求解旋转角度余弦值
        float sinV = sin(radian); // 求解旋转角度正弦值
        mat4 mx = mat4(1,0,0,0, 0,cosV,-sinV,0, 0,sinV,cosV,0, 0,0,0,1); // x 轴顺时针
        // mat4 mx = mat4(cosV,-sinV,0,0, sinV,cosV,0,0,  0,0,1,0,  0,0,0,1); // z 轴顺时针
        // mat4 mx=mat4(cosV,0,sinV,0, 0,1,0,0, -sinV,0,cosV,0, 0,0,0,1); // y 轴顺时针
      
        vec4 v = mx * vec4(position, 1.0);
      
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
      }
    `,
    fragmentShader: `
      void main() {
        gl_FragColor = vec4(0, 1.0, 0, 1.0);
      }
    `,
    uniforms: {
      // 1. 定义接收全局参数-时间变量值(作为旋转角度)
      myTime: {
        value: 0
      }
    },
    side: THREE.DoubleSide
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}

function renderLoop(t) {
  // t 是毫秒级,距离最开始的时刻过了多久
  console.log(t)
  // 3. 把时间数值传入到材质的 uniforms 变量中
  material.uniforms.myTime.value = t / 10 // 为了让旋转慢一些(200 -> 20度)

  renderer.render(scene, camera)
  controls.update()
  requestAnimationFrame(renderLoop)
}

init()
createBasic()
renderLoop()


posted @   jialiangzai  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!

喜欢请打赏

扫描二维码打赏

微信打赏

点击右上角即可分享
微信分享提示