ThreeJS Shader的效果样例光影墙、扩散面(四)

cnblogs 2024-09-14 08:11:00 阅读 66

一、实现一个光影墙

1.根据自定义坐标点,输出一个光影墙

/**

* 添加光影墙

*/

function addLightWall() {

const geometry = new THREE.BufferGeometry();

const vertices = new Float32Array([

5, 0, 2,

3, 0, 5,

-2, 0, 5,

-4, 0, 2,

-4, 5, 2,

-2, 5, 5,

3, 5, 5,

5, 5, 2

]);

const indices = new Uint16Array([

0, 1, 7,

1, 6, 7,

1, 2, 6,

2, 5, 6,

2, 3, 5,

3, 4, 5

])

geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

geometry.setIndex(new THREE.BufferAttribute(indices, 1));

geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));

const uniforms = {

uTime: { value: 0.01 },

};

setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)

}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {

material = new THREE.ShaderMaterial({

vertexShader: vertexShader,

fragmentShader: fragmentShader,

side: THREE.DoubleSide,

uniforms: uniforms,

transparent: true,

// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色

});

material.depthTest = true;

material.depthWrite = false;

let planeMesh = new THREE.Mesh(geometry, material);

if (isLine) {

planeMesh = new THREE.Points(geometry, material);

}

planeMesh.position.x = position[0];

planeMesh.position.y = position[1];

planeMesh.position.z = position[2];

scene.add(planeMesh);

}

自定义坐标

2.圆柱体的光影墙

/**

* 添加光影墙

*/

function addLightWall() {

const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);

geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));

// 生成一个渐变色的光影墙

const vertex = `

varying vec3 vPosition;

varying vec2 vUv;

varying float vHeight;

attribute float aHeight;

void main() {

vHeight = aHeight;

vUv = uv;

vPosition = position;

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

}

`;

const frag = `

varying vec3 vPosition;

varying vec2 vUv;

varying float vHeight;

void main() {

float d = (vHeight - distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z))) / vHeight;

gl_FragColor = vec4(0.0, 1.0, 1.0, d);

}

`;

const uniforms = {

uTime: { value: 0.01 },

};

setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)

}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {

material = new THREE.ShaderMaterial({

vertexShader: vertexShader,

fragmentShader: fragmentShader,

side: THREE.DoubleSide,

uniforms: uniforms,

transparent: true,

// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色

});

material.depthTest = true;

material.depthWrite = false;

let planeMesh = new THREE.Mesh(geometry, material);

if (isLine) {

planeMesh = new THREE.Points(geometry, material);

}

planeMesh.position.x = position[0];

planeMesh.position.y = position[1];

planeMesh.position.z = position[2];

scene.add(planeMesh);

}

圆柱体光影墙

3.为圆柱体添加可移动的线圈

/**

* 添加光影墙

*/

function addLightWall() {

const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);

geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));

// 生成一个可以向上移动的墙体线

const vertex = `

varying vec3 vPosition;

varying vec2 vUv;

varying float vHeight;

attribute float aHeight;

void main() {

vHeight = aHeight;

vUv = uv;

vPosition = position;

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

}

`;

const frag = `

uniform float uTime;

varying vec3 vPosition;

varying vec2 vUv;

varying float vHeight;

void main() {

float dis = distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z));

float highlightPos = mod(uTime * 5.0, vHeight) - 2.5;

float highlightDis = distance(vec3(vPosition.x, highlightPos, vPosition.z), vec3(vPosition.x, -2.5, vPosition.z));

float highlightOpa = (vHeight - highlightDis) / vHeight;

float opacity = (vHeight - dis) / vHeight;

if (abs(dis - highlightDis) < 0.05) {

gl_FragColor = vec4(0.04, 0.95, 0.95, highlightOpa + 0.2);

} else {

gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);

}

}

`;

const uniforms = {

uTime: { value: 0.01 },

};

setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)

}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {

material = new THREE.ShaderMaterial({

vertexShader: vertexShader,

fragmentShader: fragmentShader,

side: THREE.DoubleSide,

uniforms: uniforms,

transparent: true,

// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色

});

material.depthTest = true;

material.depthWrite = false;

let planeMesh = new THREE.Mesh(geometry, material);

if (isLine) {

planeMesh = new THREE.Points(geometry, material);

}

planeMesh.position.x = position[0];

planeMesh.position.y = position[1];

planeMesh.position.z = position[2];

scene.add(planeMesh);

}

移动线圈光影墙

二、实现一个渐变色的波纹圆圈

1.实现一个固定的渐变色圆圈

原理:

1)UV点的范围是[0, 1],所以各个像素点距离圆心的距离范围是0~0.5,如果乘以2刚好是透明度的范围(0~1),这样就可以实现一个简单的渐变圆

2)假设厚度为t,那么颜色的透明度的范围是[1, 1-t],而我们实际需要的是[1, 0],可以用图二来表示两个线性关系,可以得到两个方程式

方程式1:y = -x + 1;

方程式2:y = -t + 1;

现在我们知道方程式二中的y的值(像素点到中心的距离distance),通过解方程式就可以得到方程式1中所对应的透明度的值为(distance - 1) /t + 1;

/**

* 添加一个扩散面

*/

function addDiffuseCircle() {

const geometry = new THREE.CircleGeometry(3, 48);

// 绘制一个渐变圈宽度可控的圆弧

const vertex = `

varying vec2 vUv;

void main() {

vUv = uv;

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

}

`;

const frag = `

uniform float uTime;

uniform float uThickness;

varying vec2 vUv;

void main() {

// 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2

float distance = length(vUv - 0.5) * 2.0;

float opacity = (distance - 1.0) / uThickness + 1.0;

gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);

}

`;

const uniforms = {

uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度

uSpeed: { value: 0.5, range: [0, 5] },

uTime: { value: 0.01 },

};

setGui(uniforms);

setShader(geometry, vertex, frag, [0,0,0], uniforms);

}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {

material = new THREE.ShaderMaterial({

vertexShader: vertexShader,

fragmentShader: fragmentShader,

side: THREE.DoubleSide,

uniforms: uniforms,

transparent: true,

// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色

});

material.depthTest = true;

material.depthWrite = false;

let planeMesh = new THREE.Mesh(geometry, material);

if (isLine) {

planeMesh = new THREE.Points(geometry, material);

}

planeMesh.position.x = position[0];

planeMesh.position.y = position[1];

planeMesh.position.z = position[2];

planeMesh.rotateX(Math.PI / 2);

scene.add(planeMesh);

}

厚度可变的渐变圆

2.半径自动缩放的渐变圆

/**

* 添加一个扩散面

*/

function addDiffuseCircle() {

const geometry = new THREE.CircleGeometry(3, 48);

// 创建一个大小可控的渐变圆弧

const vertex = `

varying vec2 vUv;

void main() {

vUv = uv;

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

}

`;

const frag = `

uniform float uTime;

uniform float uThickness;

uniform float uSpeed;

varying vec2 vUv;

void main() {

// 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2

// 假设从内像外开始扩散,距离和时间关系是 最内部: 距离0,时间0;最外部:距离1,时间1,如果用1-时间的话,

// 所以此时1-时间+距离和样例1中的透明度相同

float timeDis = fract(uTime * uSpeed);

float distance = length(vUv - 0.5) * 2.0;

if (timeDis < distance) {

gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0);

} else {

float opacity = (1.0 - timeDis + distance - 1.0) / uThickness + 1.0;

gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);

}

}

`;

const uniforms = {

uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度

uSpeed: { value: 0.5, range: [0, 5] },

uTime: { value: 0.01 },

};

setShader(geometry, vertex, frag, [0,0,0], uniforms);

}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {

material = new THREE.ShaderMaterial({

vertexShader: vertexShader,

fragmentShader: fragmentShader,

side: THREE.DoubleSide,

uniforms: uniforms,

transparent: true,

// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色

});

material.depthTest = true;

material.depthWrite = false;

let planeMesh = new THREE.Mesh(geometry, material);

if (isLine) {

planeMesh = new THREE.Points(geometry, material);

}

planeMesh.position.x = position[0];

planeMesh.position.y = position[1];

planeMesh.position.z = position[2];

planeMesh.rotateX(Math.PI / 2);

scene.add(planeMesh);

}

自动缩放的渐变圆



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。