webgl 火焰特效(未证实可用)

js

const renderer = new THREE.WebGLRenderer({
    antialias: true
});
document.body.appendChild(renderer.domElement);

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
    45, window.innerWidth / window.innerHeight,
    0.1, 2000);
camera.position.set(0, 0, 10);


let rig = new THREE.Group();
rig.add(camera);

scene.add(rig);

var texture = new THREE.TextureLoader().load(
    "/uploads/1908/Rough.jpg",
    function() {
        console.log("loaded");
    },
    undefined,
    function(e) {
        console.log("error", e);
    }
);
texture.crossOrigin = ""; //"anonymous";

let plane = new THREE.PlaneGeometry(100, 100, 100, 100)
let planeMaterial = new THREE.MeshStandardMaterial({
    color: 0x999999,
    roughness: 0.8,

    displacementMap: texture,
    displacementScale: 2,
    displacementBias: -1.4,
    map: texture,
});
let groundMesh = new THREE.Mesh(plane, planeMaterial);
groundMesh.rotateX(-90 * THREE.Math.DEG2RAD);
groundMesh.position.y = -2;
scene.add(groundMesh);

class fire {

    constructor(density = 30, height = 8, r = 0.2, resolution = 64) {

        this.object = new THREE.Group();

        this.fireballs = [];

        this.height = height;
        this.radius = r;

        var texture = new THREE.TextureLoader().load(
            "/uploads/2103/Tendrils.png",
            function() {
                console.log("loaded");
            },
            undefined,
            function(e) {
                console.log("error", e);
            }
        );
        texture.crossOrigin = ""; //"anonymous";
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;

        var fireGradient = new THREE.TextureLoader().load(
            "/uploads/2103/Fire2.png",
            function() {
                console.log("loaded");
            },
            undefined,
            function(e) {
                console.log("error", e);
            }
        );
        texture.crossOrigin = ""; //"anonymous";

        this.fireMaterial = new THREE.ShaderMaterial({
            uniforms: {
                time: {
                    value: 1.0
                },
                blend: {
                    value: 1.0
                },
                gradient: {
                    type: "t",
                    value: fireGradient
                },
                blendPattern: {
                    type: "t",
                    value: texture
                },
            },
            vertexShader: document.getElementById('vertexShader').textContent,
            fragmentShader: document.getElementById('fragmentShader').textContent,
            transparent: true,
            side: THREE.DoubleSide,
            //blending:THREE.AdditiveBlending
        });

        this.light = new THREE.PointLight(0xFF5500, 1, 100)
        this.light.position.set(0, 0.4, 0);
        this.lightIntensity = Math.random() * 5;

        this.object.add(this.light);
        // this.fireMaterial = new THREE.MeshStandardMaterial(0x661100);

        for (var i = 0; i < density; i++) {
            let geometry = new THREE.SphereGeometry(1, resolution, resolution);
            let mat = this.fireMaterial.clone();
            mat.uniforms.blendPattern.value = texture;
            mat.uniforms.gradient.value = fireGradient;
            mat.needsUpdate = true;
            let sphere = new THREE.Mesh(geometry, mat);
            sphere.position.y = Math.random() * height;
            sphere.position.x = (0.5 - Math.random()) * this.radius;
            sphere.position.z = (0.5 - Math.random()) * this.radius;
            sphere.rotateX(Math.random() * 1);
            sphere.rotateZ(Math.PI + (0.5 - Math.random()));
            sphere.rotateY(Math.random() * 3);
            sphere.dirX = ((0.5 - Math.random()) * 0.02);
            sphere.dirY = 0.02;
            sphere.dirZ = ((0.5 - Math.random()) * 0.02);

            this.fireballs.push(sphere);
        }

        this.object.add(...this.fireballs);

    }

    update() {

        this.fireballs.forEach(ball => {

            ball.position.y += ball.dirY + Math.sin(ball.position.y * 0.002);
            ball.position.x += Math.sin(ball.position.y * 0.5) * ball.dirX;
            ball.position.z += Math.cos(ball.position.y * 0.25) * ball.dirZ;
            if (ball.position.y > this.height) {
                ball.position.y = -0.01
                ball.position.x = (0.5 - Math.random()) * this.radius;
                ball.position.z = (0.5 - Math.random()) * this.radius;
            }

            let p = ball.position.y / this.height;

            // ball.rotateZ((1.2-p)*0.01);
            ball.rotateY((1.2 - p) * 0.01)
            ball.scale.set(0.4 + p, 0.4 + p, 0.4 + p);
            ///ball.opacity = p;
            ball.material.uniforms.blend.value = p;
            //ball.material.needsUpdate = true;
        })

        this.light.intensity += (this.lightIntensity - this.light.intensity) * 0.02;

        if (Math.random() > 0.8) {
            this.lightIntensity = Math.random() * 5;
        }

    }
    env(val, envelope = [0., 0., 0.1, 1., 1., 0.]) {

        function lerp(v0, v1, t) {
            return v0 * (1 - t) + v1 * t
        }

    }

}

let f = new fire();
f.object.position.y = -2.4;

scene.add(f.object)

// let cubeGeometry = new THREE.CubeGeometry(2, 2)
// let cubeMaterial = new THREE.MeshStandardMaterial();

// let cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial);

// scene.add(cubeMesh)



let light = new THREE.PointLight(0xffffff, 1, 100)
light.position.set(10, 10, 20);

scene.add(light);

function resize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
}

window.addEventListener("resize", resize)

let mx = 0;
let my = 0;


window.addEventListener("mousemove", (e) => {

    mx = -(0.5 - (e.clientX / window.innerWidth)) * 2.;
    my = -(0.8 - (e.clientY / window.innerHeight)) * 2.;


})
var targetIntensity = Math.random() * 5;

function draw() {
    requestAnimationFrame(draw)
    f.update();
    rig.rotation.y += (mx * .2 - rig.rotation.y) * 0.2;
    rig.rotation.x += (my * 0.02 - rig.rotation.x) * 0.2;

    camera.rotation.z += (mx * 0.5 - camera.rotation.z) * 0.2;
    camera.rotation.y += (-mx - camera.rotation.y) * 0.1;
    camera.rotation.x += (my * -0.2 - camera.rotation.x) * 0.1;
    camera.position.z += ((7 + (my * 3)) - camera.position.z) * 0.2;
    camera.position.y += (my - camera.position.y) * 0.2;

    //f.object.rotateY(0.01)
    // mesh.rotateX(0.01);
    // mesh.rotateY(0.02);
    // mesh.rotateZ(0.03)
    renderer.render(scene, camera);
}

resize();
draw();

html

<script id="vertexShader" type="x-shader/x-vertex">
			precision mediump float;
			precision mediump int;
			attribute vec4 color;
	
			uniform float blend;
			uniform sampler2D gradient;
			uniform sampler2D blendPattern;
	
      varying vec2 vUv;
      varying float vFade;
			varying float dissolve;
			void main()	{
        vUv = uv;
				dissolve = texture2D(blendPattern, vUv).r * 0.1;
        vec4 localPosition = vec4( position*(1.+(dissolve*5.)), 1);
				
        vFade = clamp((localPosition.y + 3.0) / 6.0, 0.0, 1.0);
				gl_Position = projectionMatrix * modelViewMatrix * localPosition;
			}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">

			precision mediump float;
			precision mediump int;
	
			uniform float time;
			uniform float blend;
	
			uniform sampler2D gradient;
			uniform sampler2D blendPattern;
	
      varying float vFade;
      varying vec2 vUv;
  		varying float dissolve;
  
			void main()	{
        
        float spread = 0.2;
        
        float fadeAmount = smoothstep(
          max(0., vFade - spread),
          min(1., vFade + spread),
          blend + dissolve*1.2
	      );
				
				gl_FragColor = texture2D(gradient, vec2(vUv.x, fadeAmount));
			}
</script>

css

body {
    margin: 0;
    overflow: hidden;
}
img {
    display: none;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值