threeJs--shander道路流光特效
直线-篇
import loaderDraco from "../hook/DracoLoader";
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { BloomPass } from 'three/addons/postprocessing/BloomPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { scene, THREE, renderer, camera } from "../hook/web3d";
let model = new THREE.Group();
function romeFn() {
loaderDraco().load('/mo-Group/墨.glb', (gltf: any) => {
model.add(gltf.scene)
scene.add(model)
}, (xhr: any) => {
if (xhr.loaded / xhr.total * 100 == 100) {
}
})
}
// romeFn()
function initBloom() {
const params = {
threshold: 0,
strength: 0.5,
radius: 0.5,
exposure: 0.5
};
const renderScene = new RenderPass(scene, camera);
//strength = 1, kernelSize = 25, sigma = 4
//自身体积范围内发光
const bloomPass: any = new BloomPass(5, 20, 100);
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
const outputPass = new OutputPass();
composer.addPass(outputPass);
}
let lineheight = window.innerHeight / 1
let lineWidth = 1
let materials: any = [];
let amount = 30;
let gap = 8;
let width = 88;
let hueStart = 0.7;
let hueEnd = 0.2;
let lightStart = 0.5;
let lightEnd = 1.0;
let modArr = new THREE.Group();
const linestopFn = () => {
// initBloom()
const spline = new THREE.LineCurve3(
new THREE.Vector3(0, 0, lineheight * 0.25),
new THREE.Vector3(0, 0, lineheight * 0.75)
);
//直的管道
const geometry = new THREE.TubeGeometry(spline, 64, lineWidth, 8, false);
const step = (width - gap) / amount;
let commonUniforms = {
uFade: { value: new THREE.Vector2(0, 0.6) },
};
const vertexShader = `varying vec2 vUv;
void main(void) {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}`
/* */
//同流动光束片元着色器
const fragmentShader = `
varying vec2 vUv;
uniform float uSpeed;
uniform float uTime;
uniform vec2 uFade;
uniform vec3 uColor;
uniform float uDirection;
void main() {
vec3 color = uColor;
//流动方向
float s = -uTime * uSpeed;
float v = 0.0;
if(uDirection == 1.0) {
v = vUv.x;
} else {
v = -vUv.x;
}
float d = mod((v + s), 1.0);
if(d > uFade.y)
discard;
else {
//平滑透明度渐变
float alpha = smoothstep(uFade.x, uFade.y, d);
//透明度太小时不显示
if(alpha < 0.001)
discard;
gl_FragColor = vec4(color, alpha);
}
}
`
for (let i = 0; i < amount; i++) {
const c = new THREE.Color('#000');
const v = i / amount;
c.setHSL(
THREE.MathUtils.lerp(hueStart, hueEnd, v),
1,
THREE.MathUtils.lerp(lightStart, lightEnd, v)
);
const material = new THREE.ShaderMaterial({
side: THREE.DoubleSide,
texture: new THREE.TextureLoader().load('/public/mo-image/箭头.png'),
transparent: true,
uniforms: {
uColor: { value: c },
//uTime设置为随机的开始时间
uTime: { value: THREE.MathUtils.lerp(-1, 1, Math.random()) },
//左侧一半是往前,右侧一半是往回
uDirection: { value: i < amount * 0.5 ? 1 : 0 },
//随机加速
uSpeed: { value: THREE.MathUtils.lerp(1, 1.5, Math.random()) },
...commonUniforms
},
vertexShader: vertexShader,
fragmentShader
});
materials.push(material);
const mesh = new THREE.Mesh(geometry, material);
//x坐标平移到等比的位置
mesh.position.x = i * step + (i > amount * 0.5 - 1 ? gap : 0);
//y坐标随机上移
mesh.position.y = Math.random() * 50;
modArr.add(mesh)
}
modArr.position.set(100, 0, -lineheight / 2)
modArr.rotateZ(Math.PI / 1)
scene.add(modArr);
function render() {
materials.forEach((m: any) => {
m.uniforms.uTime.value += 0.02;
if (m.uniforms.uTime.value > 1) {
m.uniforms.uTime.value = 0;
}
});
requestAnimationFrame(render);
}
render()
}
// linestopFn()
export default linestopFn;
曲线-篇
/* 曲线 */
import loaderDraco from "../hook/DracoLoader";
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { BloomPass } from 'three/addons/postprocessing/BloomPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { scene, THREE, renderer, camera } from "../hook/web3d";
let model = new THREE.Group();
function romeFn() {
loaderDraco().load('/mo-Group/顺兴之-墨丫.glb', (gltf: any) => {
model.add(gltf.scene)
scene.add(model)
}, (xhr: any) => {
if (xhr.loaded / xhr.total * 100 == 100) {
}
})
}
romeFn()
function initBloom() {
const params = {
threshold: 0,
strength: 0.5,
radius: 0.5,
exposure: 0.5
};
const renderScene = new RenderPass(scene, camera);
//strength = 1, kernelSize = 25, sigma = 4
//自身体积范围内发光
const bloomPass: any = new BloomPass(5, 20, 100);
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
const outputPass = new OutputPass();
composer.addPass(outputPass);
}
let lineheight = window.innerHeight / 1
let lineWidth = 1
let materials: any = [];
let amount = 30;
let gap = 8;
let width = 88;
let hueStart = 0.7;
let hueEnd = 0.2;
let lightStart = 0.5;
let lightEnd = 1.0;
let modArr = new THREE.Group();
const linestopFnplus = () => {
// initBloom()
const spline = new THREE.LineCurve3(
new THREE.Vector3(0, 0, lineheight * 0.25),
new THREE.Vector3(0, 0, lineheight * 0.75),
);
//直的管道
const geometry = new THREE.TubeGeometry(spline, 64, lineWidth, 8, false);
/* */
const step = (width - gap) / amount;
let commonUniforms = {
uFade: { value: new THREE.Vector2(0, 0.6) },
uOffset: { value: new THREE.Vector2(40, 20) }
};
const vertexMoveHeight = `
float getMove(float u,float offset){
float a=u*PI*2.0;
return sin(a+PI*0.25)*u*offset;
}
float getHeight(float u,float offset){
float a=u*PI*3.0;
return cos(a)*u*offset ;
}
`;
const vertexShader = `
float PI = acos(-1.0);
uniform vec2 uOffset;
varying vec2 vUv;
${vertexMoveHeight}
void main(void) {
vUv = uv;
float m = getMove(uv.x, uOffset.x);
float h = getHeight(uv.x, uOffset.y);
vec3 newPosition = position;
newPosition.x = newPosition.x + m;
newPosition.y = newPosition.y + h;
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}
`;
//同流动光束片元着色器
const fragmentShader = `
varying vec2 vUv;
uniform float uSpeed;
uniform float uTime;
uniform vec2 uFade;
uniform vec3 uColor;
uniform float uDirection;
void main() {
vec3 color = uColor;
//流动方向
float s = -uTime * uSpeed;
float v = 0.0;
if(uDirection == 1.0) {
v = vUv.x;
} else {
v = -vUv.x;
}
float d = mod((v + s), 1.0);
if(d > uFade.y) discard;
else {
//平滑透明度渐变
float alpha = smoothstep(uFade.x, uFade.y, d);
//透明度太小时不显示
if(alpha < 0.001)
discard;
gl_FragColor = vec4(color, alpha);
}
}
`;
for (let i = 0; i < amount; i++) {
const c = new THREE.Color('#000');
const v = i / amount;
c.setHSL(
THREE.MathUtils.lerp(hueStart, hueEnd, v),
1,
THREE.MathUtils.lerp(lightStart, lightEnd, v)
);
const material = new THREE.ShaderMaterial({
side: THREE.DoubleSide,
transparent: true,
uniforms: {
uColor: { value: c },
//uTime设置为随机的开始时间
uTime: { value: THREE.MathUtils.lerp(-1, 1, Math.random()) },
//左侧一半是往前,右侧一半是往回
uDirection: { value: i < amount * 0.5 ? 1 : 0 },
//随机加速
uSpeed: { value: THREE.MathUtils.lerp(1, 1.5, Math.random()) },
...commonUniforms
},
vertexShader: vertexShader,
fragmentShader
});
materials.push(material);
const mesh = new THREE.Mesh(geometry, material);
//x坐标平移到等比的位置
mesh.position.x = i * step + (i > amount * 0.5 - 1 ? gap : 0);
//y坐标随机上移
mesh.position.y = Math.random() * 50;
modArr.add(mesh)
}
modArr.position.set(100, 0, -lineheight / 2)
// modArr.rotateZ(Math.PI / 1)
scene.add(modArr);
function render() {
materials.forEach((m: any) => {
m.uniforms.uTime.value += 0.002;
if (m.uniforms.uTime.value > 1) {
m.uniforms.uTime.value = 0;
}
});
requestAnimationFrame(render);
}
render()
}
linestopFnplus()
export default linestopFnplus;