往事越千年、魏武挥鞭、东临碣石有遗篇

69 阅读3分钟

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;