找不到用于three.js的粒子系统?

时间:2019-04-15 16:47:09

标签: vue.js three.js

我正在尝试执行以下操作:https://github.com/mrdoob/three.js/blob/master/examples/webgl_gpu_particle_system.html

这是在Threejs示例中;但是,他们提供的代码似乎无效。我也尝试过3 gpu-particle-system npm,但这也不起作用,所以我认为手动导入代码是可行的。但是,我也错了。介意为我解决问题吗?

我目前遇到的错误是警告,除了整个加载过程之外。场景也加载。

./ src / views / Home.vue?vue&type = script&lang = js&

中的警告

在“三个”中找不到导出的“ GPUParticleSystem”(导入为“三个”)

import * as THREE from 'three'
import {TweenMax, TimelineMax} from 'gsap'
import '../particle.js';

export default {
  name: 'home',
  data () {
    return {
      camera: Function,
      scene: Function,
      renderer: Function,
      particleSystem: Function,
      spawnerOptions: {},
      options: {},
      tick: 0,
    }
  },
  mounted () {
    var positions = []

    this.init(positions);
    this.animate();
    document.getElementById('screen').addEventListener('click', this.onClick, false);

  },
  methods: {
    display() {
      if (this.click > 1) {
        document.querySelector('#box_00').style.display = 'none';
      }
    },

    init(positions) {

      var screen = document.querySelector('#screen');
      // Scene Information
      this.camera = new THREE.PerspectiveCamera( 28, window.innerWidth / window.innerHeight, 1, 1000 );
      this.camera.position.set(0,0,100);
      this.scene = new THREE.Scene();
      //this.scene.background = new THREE.Color( 0xebf0f4 );

      // Particle System
      this.particleSystem = new THREE.GPUParticleSystem({
        maxParticles: 25000
      });

      this.scene.add(this.particleSystem);

      // Options passed for each spawn
      this.options = {
                position: new THREE.Vector3(),
                positionRandomness: .3,
                velocity: new THREE.Vector3(),
                velocityRandomness: .5,
                color: 0xaa88ff,
                colorRandomness: .2,
                turbulence: .5,
                lifetime: 2,
                size: 5,
                sizeRandomness: 1
            };
            this.spawnerOptions = {
                spawnRate: 15000,
                horizontalSpeed: 1.5,
                verticalSpeed: 1.33,
                timeScale: 1
      };

      this.renderer = new THREE.WebGLRenderer();
            this.renderer.setPixelRatio( window.devicePixelRatio );
            this.renderer.setSize( window.innerWidth, window.innerHeight );
            screen.appendChild( this.renderer.domElement );


      window.addEventListener( 'resize', this.onWindowResize, false );

    },

    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize( window.innerWidth, window.innerHeight );
    },

    animate() {
      requestAnimationFrame( this.animate );

      var clock = new THREE.Clock();

      var delta = clock.getDelta() * this.spawnerOptions.timeScale;

      this.tick += delta

      if (this.tick <= 0) {
        this.tick = 0
      }

      if ( delta > 0 ) {
                this.options.position.x = Math.sin( this.tick * this.spawnerOptions.horizontalSpeed ) * 20;
                this.options.position.y = Math.sin( this.tick * this.spawnerOptions.verticalSpeed ) * 10;
                this.options.position.z = Math.sin( this.tick * this.spawnerOptions.horizontalSpeed + this.spawnerOptions.verticalSpeed ) * 5;
                for ( var x = 0; x < this.spawnerOptions.spawnRate * delta; x ++ ) {
                    // Yep, that's really it.   Spawning particles is super cheap, and once you spawn them, the rest of
                    // their lifecycle is handled entirely on the GPU, driven by a time uniform updated below
                    this.particleSystem.spawnParticle( this.options );
                }
      }

      this.particleSystem.update(this.tick);


      this.render();
    },

    render() {
      this.renderer.render( this.scene, this.camera );
    },

  }
}
/*
 * GPU Particle System
 * @author flimshaw - Charlie Hoey - http://charliehoey.com
 *
 * I grabbed this from the above author's npm package.
 */

"use strict";
function defaultOnError(err) {
  throw new Error(err);
}

module.exports = function() {
    let THREE = require('three');
    THREE.GPUParticleSystem = function(options) {

    var self = this;
    var options = options || {};

    // parse options and use defaults
    self.PARTICLE_COUNT = options.maxParticles || 1000000;
    self.PARTICLE_CONTAINERS = options.containerCount || 1;
    self.PARTICLES_PER_CONTAINER = Math.ceil(self.PARTICLE_COUNT / self.PARTICLE_CONTAINERS);
    self.PARTICLE_CURSOR = 0;
    self.time = 0;


    // Custom vertex and fragement shader
    var GPUParticleShader = {

        vertexShader: [

        'precision highp float;',
        'const vec4 bitSh = vec4(256. * 256. * 256., 256. * 256., 256., 1.);',
        'const vec4 bitMsk = vec4(0.,vec3(1./256.0));',
        'const vec4 bitShifts = vec4(1.) / bitSh;',

        '#define FLOAT_MAX  1.70141184e38',
        '#define FLOAT_MIN  1.17549435e-38',

        'lowp vec4 encode_float(highp float v) {',
        'highp float av = abs(v);',

        '//Handle special cases',
        'if(av < FLOAT_MIN) {',
        'return vec4(0.0, 0.0, 0.0, 0.0);',
        '} else if(v > FLOAT_MAX) {',
        'return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;',
        '} else if(v < -FLOAT_MAX) {',
        'return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;',
        '}',

        'highp vec4 c = vec4(0,0,0,0);',

        '//Compute exponent and mantissa',
        'highp float e = floor(log2(av));',
        'highp float m = av * pow(2.0, -e) - 1.0;',

        //Unpack mantissa
        'c[1] = floor(128.0 * m);',
        'm -= c[1] / 128.0;',
        'c[2] = floor(32768.0 * m);',
        'm -= c[2] / 32768.0;',
        'c[3] = floor(8388608.0 * m);',

        '//Unpack exponent',
        'highp float ebias = e + 127.0;',
        'c[0] = floor(ebias / 2.0);',
        'ebias -= c[0] * 2.0;',
        'c[1] += floor(ebias) * 128.0;',

        '//Unpack sign bit',
        'c[0] += 128.0 * step(0.0, -v);',

        '//Scale back to range',
        'return c / 255.0;',
        '}',

        'vec4 pack(const in float depth)',
        '{',
        'const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);',
        'const vec4 bit_mask  = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);',
        'vec4 res = mod(depth*bit_shift*vec4(255), vec4(256))/vec4(255);',
        'res -= res.xxyz * bit_mask;',
        'return res;',
        '}',

        'float unpack(const in vec4 rgba_depth)',
        '{',
        'const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);',
        'float depth = dot(rgba_depth, bit_shift);',
        'return depth;',
        '}',

        'uniform float uTime;',
        'uniform float uScale;',
        'uniform sampler2D tNoise;',

        'attribute vec4 particlePositionsStartTime;',
        'attribute vec4 particleVelColSizeLife;',

        'varying vec4 vColor;',
        'varying float lifeLeft;',

        'void main() {',

        '// unpack things from our attributes',
        'vColor = encode_float( particleVelColSizeLife.y );',

        '// convert our velocity back into a value we can use',
        'vec4 velTurb = encode_float( particleVelColSizeLife.x );',
        'vec3 velocity = vec3( velTurb.xyz );',
        'float turbulence = velTurb.w;',

        'vec3 newPosition;',

        'float timeElapsed = uTime - particlePositionsStartTime.a;',

        'lifeLeft = 1. - (timeElapsed / particleVelColSizeLife.w);',

        'gl_PointSize = ( uScale * particleVelColSizeLife.z ) * lifeLeft;',

        'velocity.x = ( velocity.x - .5 ) * 3.;',
        'velocity.y = ( velocity.y - .5 ) * 3.;',
        'velocity.z = ( velocity.z - .5 ) * 3.;',

        'newPosition = particlePositionsStartTime.xyz + ( velocity * 10. ) * ( uTime - particlePositionsStartTime.a );',

        'vec3 noise = texture2D( tNoise, vec2( newPosition.x * .015 + (uTime * .05), newPosition.y * .02 + (uTime * .015) )).rgb;',
        'vec3 noiseVel = ( noise.rgb - .5 ) * 30.;',

        'newPosition = mix(newPosition, newPosition + vec3(noiseVel * ( turbulence * 5. ) ), (timeElapsed / particleVelColSizeLife.a) );',

        'if( velocity.y > 0. && velocity.y < .05 ) {',
        'lifeLeft = 0.;',
        '}',

        'if( velocity.x < -1.45 ) {',
        'lifeLeft = 0.;',
        '}',

        'if( timeElapsed > 0. ) {',
        'gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );',
        '} else {',
        'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
        'lifeLeft = 0.;',
        'gl_PointSize = 0.;',
        '}',
        '}'

        ].join("\n"),

        fragmentShader: [

        'float scaleLinear(float value, vec2 valueDomain) {',
        'return (value - valueDomain.x) / (valueDomain.y - valueDomain.x);',
        '}',

        'float scaleLinear(float value, vec2 valueDomain, vec2 valueRange) {',
        'return mix(valueRange.x, valueRange.y, scaleLinear(value, valueDomain));',
        '}',

        'varying vec4 vColor;',
        'varying float lifeLeft;',

        'uniform sampler2D tSprite;',

        'void main() {',

        'float alpha = 0.;',

        'if( lifeLeft > .995 ) {',
        'alpha = scaleLinear( lifeLeft, vec2(1., .995), vec2(0., 1.));//mix( 0., 1., ( lifeLeft - .95 ) * 100. ) * .75;',
        '} else {',
        'alpha = lifeLeft * .75;',
        '}',

        'vec4 tex = texture2D( tSprite, gl_PointCoord );',

        'gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );',
        '}'

        ].join("\n")

    };

    // preload a million random numbers
    self.rand = [];

    for (var i = 1e5; i > 0; i--) {
        self.rand.push(Math.random() - .5);
    }

    self.random = function() {
        return ++i >= self.rand.length ? self.rand[i = 1] : self.rand[i];
    }

    var textureLoader = new THREE.TextureLoader();

    self.particleNoiseTex = textureLoader.load("assets/img/perlin-512.png");
    self.particleNoiseTex.wrapS = self.particleNoiseTex.wrapT = THREE.RepeatWrapping;

    self.particleSpriteTex = textureLoader.load("assets/img/particle2.png");
    self.particleSpriteTex.wrapS = self.particleSpriteTex.wrapT = THREE.RepeatWrapping;

    self.particleShaderMat = new THREE.ShaderMaterial({
        transparent: true,
        depthWrite: false,
        uniforms: {
        "uTime": {
            type: "f",
            value: 0.0
        },
        "uScale": {
            type: "f",
            value: 1.0
        },
        "tNoise": {
            type: "t",
            value: self.particleNoiseTex
        },
        "tSprite": {
            type: "t",
            value: self.particleSpriteTex
        }
        },
        blending: THREE.AdditiveBlending,
        vertexShader: GPUParticleShader.vertexShader,
        fragmentShader: GPUParticleShader.fragmentShader
    });

    // define defaults for all values
    self.particleShaderMat.defaultAttributeValues.particlePositionsStartTime = [0, 0, 0, 0];
    self.particleShaderMat.defaultAttributeValues.particleVelColSizeLife = [0, 0, 0, 0];

    self.particleContainers = [];


    // extend Object3D
    THREE.Object3D.apply(this, arguments);

    this.init = function() {

        for (var i = 0; i < self.PARTICLE_CONTAINERS; i++) {

        var c = new THREE.GPUParticleContainer(self.PARTICLES_PER_CONTAINER, self);
        self.particleContainers.push(c);
        self.add(c);

        }

    }

    this.spawnParticle = function(options) {

        self.PARTICLE_CURSOR++;
        if (self.PARTICLE_CURSOR >= self.PARTICLE_COUNT) {
        self.PARTICLE_CURSOR = 1;
        }

        var currentContainer = self.particleContainers[Math.floor(self.PARTICLE_CURSOR / self.PARTICLES_PER_CONTAINER)];

        currentContainer.spawnParticle(options);

    }

    this.update = function(time) {
        for (var i = 0; i < self.PARTICLE_CONTAINERS; i++) {

        self.particleContainers[i].update(time);

        }
    };

    this.init();

    }

    THREE.GPUParticleSystem.prototype = Object.create(THREE.Object3D.prototype);
    THREE.GPUParticleSystem.prototype.constructor = THREE.GPUParticleSystem;


    // Subclass for particle containers, allows for very large arrays to be spread out
    THREE.GPUParticleContainer = function(maxParticles, particleSystem) {

    var self = this;
    self.PARTICLE_COUNT = maxParticles || 100000;
    self.PARTICLE_CURSOR = 0;
    self.time = 0;
    self.DPR = window.devicePixelRatio;
    self.GPUParticleSystem = particleSystem;

    var particlesPerArray = Math.floor(self.PARTICLE_COUNT / self.MAX_ATTRIBUTES);

    // extend Object3D
    THREE.Object3D.apply(this, arguments);

    // construct a couple small arrays used for packing variables into floats etc
    var UINT8_VIEW = new Uint8Array(4)
    var FLOAT_VIEW = new Float32Array(UINT8_VIEW.buffer)

    function decodeFloat(x, y, z, w) {
        UINT8_VIEW[0] = Math.floor(w)
        UINT8_VIEW[1] = Math.floor(z)
        UINT8_VIEW[2] = Math.floor(y)
        UINT8_VIEW[3] = Math.floor(x)
        return FLOAT_VIEW[0]
    }

    function componentToHex(c) {
        var hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }

    function rgbToHex(r, g, b) {
        return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }

    function hexToRgb(hex) {
        var r = hex >> 16;
        var g = (hex & 0x00FF00) >> 8;
        var b = hex & 0x0000FF;

        if (r > 0) r--;
        if (g > 0) g--;
        if (b > 0) b--;

        return [r, g, b];
    };

    self.particles = [];
    self.deadParticles = [];
    self.particlesAvailableSlot = [];

    // create a container for particles
    self.particleUpdate = false;

    // Shader Based Particle System
    self.particleShaderGeo = new THREE.BufferGeometry();

    // new hyper compressed attributes
    self.particleVertices = new Float32Array(self.PARTICLE_COUNT * 3); // position
    self.particlePositionsStartTime = new Float32Array(self.PARTICLE_COUNT * 4); // position
    self.particleVelColSizeLife = new Float32Array(self.PARTICLE_COUNT * 4);

    for (var i = 0; i < self.PARTICLE_COUNT; i++) {
        self.particlePositionsStartTime[i * 4 + 0] = 100; //x
        self.particlePositionsStartTime[i * 4 + 1] = 0; //y
        self.particlePositionsStartTime[i * 4 + 2] = 0.0; //z
        self.particlePositionsStartTime[i * 4 + 3] = 0.0; //startTime

        self.particleVertices[i * 3 + 0] = 0; //x
        self.particleVertices[i * 3 + 1] = 0; //y
        self.particleVertices[i * 3 + 2] = 0.0; //z

        self.particleVelColSizeLife[i * 4 + 0] = decodeFloat(128, 128, 0, 0); //vel
        self.particleVelColSizeLife[i * 4 + 1] = decodeFloat(0, 254, 0, 254); //color
        self.particleVelColSizeLife[i * 4 + 2] = 1.0; //size
        self.particleVelColSizeLife[i * 4 + 3] = 0.0; //lifespan
    }

    self.particleShaderGeo.addAttribute('position', new THREE.BufferAttribute(self.particleVertices, 3));
    self.particleShaderGeo.addAttribute('particlePositionsStartTime', new THREE.BufferAttribute(self.particlePositionsStartTime, 4).setDynamic(true));
    self.particleShaderGeo.addAttribute('particleVelColSizeLife', new THREE.BufferAttribute(self.particleVelColSizeLife, 4).setDynamic(true));

    self.posStart = self.particleShaderGeo.getAttribute('particlePositionsStartTime')
    self.velCol = self.particleShaderGeo.getAttribute('particleVelColSizeLife');

    self.particleShaderMat = self.GPUParticleSystem.particleShaderMat;

    this.init = function() {
        self.particleSystem = new THREE.Points(self.particleShaderGeo, self.particleShaderMat);
        self.particleSystem.frustumCulled = false;
        this.add(self.particleSystem);
    };

    var options = {},
        position = new THREE.Vector3(),
        velocity = new THREE.Vector3(),
        positionRandomness = 0.,
        velocityRandomness = 0.,
        color = 0xffffff,
        colorRandomness = 0.,
        turbulence = 0.,
        lifetime = 0.,
        size = 0.,
        sizeRandomness = 0.,
        i;

    var maxVel = 2;
    var maxSource = 250;
    this.offset = 0;
    this.count = 0;

    this.spawnParticle = function(options) {

        options = options || {};

        // setup reasonable default values for all arguments
        position = options.position !== undefined ? position.copy(options.position) : position.set(0., 0., 0.);
        velocity = options.velocity !== undefined ? velocity.copy(options.velocity) : velocity.set(0., 0., 0.);
        positionRandomness = options.positionRandomness !== undefined ? options.positionRandomness : 0.0;
        velocityRandomness = options.velocityRandomness !== undefined ? options.velocityRandomness : 0.0;
        color = options.color !== undefined ? options.color : 0xffffff;
        colorRandomness = options.colorRandomness !== undefined ? options.colorRandomness : 1.0;
        turbulence = options.turbulence !== undefined ? options.turbulence : 1.0;
        lifetime = options.lifetime !== undefined ? options.lifetime : 5.0;
        size = options.size !== undefined ? options.size : 10;
        sizeRandomness = options.sizeRandomness !== undefined ? options.sizeRandomness : 0.0,
        smoothPosition = options.smoothPosition !== undefined ? options.smoothPosition : false;

        if (self.DPR !== undefined) size *= self.DPR;

        i = self.PARTICLE_CURSOR;

        self.posStart.array[i * 4 + 0] = position.x + ((particleSystem.random()) * positionRandomness); // - ( velocity.x * particleSystem.random() ); //x
        self.posStart.array[i * 4 + 1] = position.y + ((particleSystem.random()) * positionRandomness); // - ( velocity.y * particleSystem.random() ); //y
        self.posStart.array[i * 4 + 2] = position.z + ((particleSystem.random()) * positionRandomness); // - ( velocity.z * particleSystem.random() ); //z
        self.posStart.array[i * 4 + 3] = self.time + (particleSystem.random() * 2e-2); //startTime

        if (smoothPosition === true) {
        self.posStart.array[i * 4 + 0] += -(velocity.x * particleSystem.random()); //x
        self.posStart.array[i * 4 + 1] += -(velocity.y * particleSystem.random()); //y
        self.posStart.array[i * 4 + 2] += -(velocity.z * particleSystem.random()); //z
        }

        var velX = velocity.x + (particleSystem.random()) * velocityRandomness;
        var velY = velocity.y + (particleSystem.random()) * velocityRandomness;
        var velZ = velocity.z + (particleSystem.random()) * velocityRandomness;

        // convert turbulence rating to something we can pack into a vec4
        var turbulence = Math.floor(turbulence * 254);

        // clamp our value to between 0. and 1.
        velX = Math.floor(maxSource * ((velX - -maxVel) / (maxVel - -maxVel)));
        velY = Math.floor(maxSource * ((velY - -maxVel) / (maxVel - -maxVel)));
        velZ = Math.floor(maxSource * ((velZ - -maxVel) / (maxVel - -maxVel)));

        self.velCol.array[i * 4 + 0] = decodeFloat(velX, velY, velZ, turbulence); //vel

        var rgb = hexToRgb(color);

        for (var c = 0; c < rgb.length; c++) {
        rgb[c] = Math.floor(rgb[c] + ((particleSystem.random()) * colorRandomness) * 254);
        if (rgb[c] > 254) rgb[c] = 254;
        if (rgb[c] < 0) rgb[c] = 0;
        }

        self.velCol.array[i * 4 + 1] = decodeFloat(rgb[0], rgb[1], rgb[2], 254); //color
        self.velCol.array[i * 4 + 2] = size + (particleSystem.random()) * sizeRandomness; //size
        self.velCol.array[i * 4 + 3] = lifetime; //lifespan

        if (this.offset == 0) {
        this.offset = self.PARTICLE_CURSOR;
        }

        self.count++;

        self.PARTICLE_CURSOR++;

        if (self.PARTICLE_CURSOR >= self.PARTICLE_COUNT) {
        self.PARTICLE_CURSOR = 0;
        }

        self.particleUpdate = true;

    }

    this.update = function(time) {

        self.time = time;
        self.particleShaderMat.uniforms['uTime'].value = time;

        this.geometryUpdate();

    };

    this.geometryUpdate = function() {
        if (self.particleUpdate == true) {
        self.particleUpdate = false;

        // if we can get away with a partial buffer update, do so
        if (self.offset + self.count < self.PARTICLE_COUNT) {
            self.posStart.updateRange.offset = self.velCol.updateRange.offset = self.offset * 4;
            self.posStart.updateRange.count = self.velCol.updateRange.count = self.count * 4;
        } else {
            self.posStart.updateRange.offset = 0;
            self.posStart.updateRange.count = self.velCol.updateRange.count = (self.PARTICLE_COUNT * 4);
        }

        self.posStart.needsUpdate = true;
        self.velCol.needsUpdate = true;

        self.offset = 0;
        self.count = 0;
        }
    }

    this.init();

    }

    THREE.GPUParticleContainer.prototype = Object.create(THREE.Object3D.prototype);
    THREE.GPUParticleContainer.prototype.constructor = THREE.GPUParticleContainer;
    return THREE.GPUParticleContainer;
};

我从前面提到的npm包中获取了第二部分代码,因为threejs示例代码的源代码也不起作用。

我的最终结果是:https://threejs.org/examples/#webgl_gpu_particle_system

祝你好运,谢谢大家!

0 个答案:

没有答案