概念: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);
}
使用:
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);
}
使用:借助 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);
}
公式:直接用 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()