How to make instance invisible in InstancedBufferGeometry?

geometry

#1
showFlowers(centerPos) {
    this.centerPos = centerPos;
    if(this.inited) {
        this.updateEnable = true;
        this.mesh.position.set(this.centerPos.x, this.centerPos.y, this.centerPos.z)
        return;
    }
    console.log("PinkFlowerNeo......................................", centerPos)
    var instances = 20;
    var tempGeometry = new THREE.PlaneBufferGeometry(0.05, 0.1);
    // copying data from a simple box geometry, but you can specify a custom geometry if you want
    var geometry = new THREE.InstancedBufferGeometry();
    geometry.index = tempGeometry.index;
    geometry.attributes.position = tempGeometry.attributes.position;
    geometry.attributes.uv = tempGeometry.attributes.uv;
    // per instance data
    // var offsets = new Float32Array(instances * 3);
    var position = [];
    var speed = [];
    var orientation = [];
    var rotateDir = [];
    var rotateVelocity = [];
    var relative = [];
    var colors = [];
    // var orientations = new Float32Array(instances * 1);
    for ( var i = 0; i < instances; i ++ ) {
        position.push(0,0,0)
        orientation.push(0,0,0,0);

        var rotateAround = Math.floor(Math.random() * 5)
        rotateDir.push(rotateAround);

        var rotateSpeed= Math.random() * 0.5;
        rotateVelocity.push(rotateSpeed);

        var moveVelocity = Math.random() * 2;
        speed.push(moveVelocity)

        var cirCenter = new THREE.Vector3(this.centerPos.x, this.centerPos.y + 1, this.centerPos.z);
        var angle = Math.PI * 2 * Math.random();
        var r = 1 * Math.sqrt(Math.random());
        var x = r * Math.cos(angle) + cirCenter.x;
        var z = r * Math.sin(angle) + cirCenter.z;

        var pos = new THREE.Vector3(x, cirCenter.y, z);
        var relativeDir = pos.sub(this.centerPos);
        relative.push(relativeDir.x, relativeDir.y, relativeDir.z)

        colors.push( 255/255, 192/255, 203/255, 1);
    }
    this.offsetAttribute = new THREE.InstancedBufferAttribute( new Float32Array( position ), 3 );
    this.velocityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(speed), 1);
    this.orientationAttribute = new THREE.InstancedBufferAttribute( new Float32Array( orientation ), 4 ).setDynamic( true );
    this.rotateAroundAttribute = new THREE.InstancedBufferAttribute(new Float32Array(rotateDir), 1);
    this.rotateVelocityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(rotateVelocity), 1);
    this.relativeDir = new THREE.InstancedBufferAttribute(new Float32Array(relative), 3);
    this.colorAttribute = new THREE.InstancedBufferAttribute(new Float32Array(colors), 4);

    geometry.addAttribute("offset", this.offsetAttribute );
    geometry.addAttribute("speed", this.velocityAttribute);
    geometry.addAttribute("orientation", this.orientationAttribute );
    geometry.addAttribute("rotateAround", this.rotateAroundAttribute );
    geometry.addAttribute("rotateVelocity", this.rotateVelocityAttribute );
    geometry.addAttribute("dir", this.relativeDir);
    geometry.addAttribute("color", this.colorAttribute );
    // material
    var material = new THREE.RawShaderMaterial( {
        side: THREE.DoubleSide,
        transparent: true,
        opacity: 1,
        uniforms:{
            map: {value: new THREE.TextureLoader().load("resource/textures/flower.png")}
        },
        vertexShader: [

            "precision highp float;",

            "uniform mat4 modelViewMatrix;",
            "uniform mat4 projectionMatrix;",

            "attribute vec3 position;",
            "attribute vec2 uv;",

            "attribute vec3 offset;",
            "attribute vec4 orientation;",
            "attribute float speed;",
            "attribute vec3 dir;",
            "attribute vec4 color;",

            "varying vec2 vUv;",
            "varying vec4 vColor;",


            "vec3 applyQuaternionToVector( vec4 q, vec3 v ){",
                "return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );",
            "}",

            "void main() {",

                "vec3 vPosition = applyQuaternionToVector(orientation, position);",
                // "vec3 vPosition = position;",

                "vUv = uv;",

                "vColor = color;",

                "gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );",

            "}"
        ].join("\n"),

        fragmentShader:  [
            "precision highp float;",
            "uniform sampler2D map;",
            "varying vec2 vUv;",
            "varying vec4 vColor;",
            "void main() {",
                // "gl_FragColor = texture2D( map, vUv );",
                "gl_FragColor = vColor;",
            "}",
        ].join("\n")
    } );
    this.mesh = new THREE.Mesh( geometry, material );
    this.mesh.position.set(this.centerPos.x, this.centerPos.y, this.centerPos.z)
    this.scene.add( this.mesh );
    this.updateEnable = true;
}

reset() {
    this.updateEnable = false;
    this.scene.remove(this.mesh)
    this.mesh.traverse(function(child) {
        if (child.isMesh) {
            child.material.dispose();
            if(child.material.map) {
                child.material.map.dispose();
            }
            child.geometry.dispose();
        }
    });
    this.elapsed = 0;
}

update(dt) {
    if(!this.updateEnable) {
        return;
    }

    this.elapsed += dt;
    if(this.elapsed >= 2.5) {
        return;
    }

    for ( var i = 0; i < this.offsetAttribute.count; i ++ ) {
        var velocity = this.velocityAttribute.getX(i)
        var speed = Math.sin(this.elapsed/2.5 * Math.PI + Math.PI /4) * velocity;
        var x = this.relativeDir.getX(i);
        var y = this.relativeDir.getY(i);
        var z = this.relativeDir.getZ(i);
        var dir = new THREE.Vector3(x, y, z);
        var deltaPos = dir.multiplyScalar(speed * dt);
        var newX = this.offsetAttribute.getX(i) + deltaPos.x;
        var newY = this.offsetAttribute.getY(i) + deltaPos.y;
        var newZ = this.offsetAttribute.getZ(i) + deltaPos.z;
        this.offsetAttribute.setX(i, newX);
        this.offsetAttribute.setY(i, newY);
        this.offsetAttribute.setZ(i, newZ);

        var r = this.colorAttribute.getX(i);
        var g = this.colorAttribute.getY(i);
        var b = this.colorAttribute.getZ(i);
        var a = this.colorAttribute.getW(i);

        this.colorAttribute.setW(i, 1 - this.elapsed / 2.5)

        // var desArr = [new THREE.Vector4()]
        // var rx = this.orientationAttribute.copyVector4sArray(desArr)
        var quaternion = new THREE.Quaternion()

        var rotateAround = this.rotateAroundAttribute.getX(i);
        var rotateVelocity = this.rotateVelocityAttribute.getX(i);
        if(rotateAround == 0) {
            quaternion.setFromAxisAngle(new THREE.Vector3(1,0,0), this.elapsed * rotateVelocity);
        }
        else if(rotateAround == 1) {
            quaternion.setFromAxisAngle(new THREE.Vector3(0,1,0), this.elapsed * rotateVelocity);
        }
        else if(rotateAround == 2) {
            quaternion.setFromAxisAngle(new THREE.Vector3(0,0,1), this.elapsed * rotateVelocity);
        }

        this.orientationAttribute.setXYZW(i, quaternion.x, quaternion.y, quaternion.z, quaternion.w);

    }

    this.offsetAttribute.needsUpdate = true; // important!
    this.colorAttribute.needsUpdate = true;
    this.orientationAttribute.needsUpdate = true;

    **//HELP THERE**************************************************************
    // var dist = this.mesh.position.distanceToSquared(this.centerPos)
    // if(dist >= 1.5) {
    //     this.mesh.visible = false;
    // }

As you see, I crated a lots similar mesh using instancedBufferGeometry, like a particle system, each instance mesh has it’s own position/speed/rotation, when it move away, I want It dissappear at some distance from the origin.
But this.mesh.visible = false; will make all instance mesh disappear


#2

You need an additional attribute that controls the visibility on instance level.


#3

Thanks. I use discard to make disappear. Is there any other approach ?


#4

You can also set the scale to 0 or move that instance behind the camera.


#5

Like @pailhead said, scale it down to zero, u can also do this in the vertex shader and your opacity attribute by multiplying the position with ceil(opacity), so you don’t have to do it on the JS side.


#6

In the vertex shader i usually do something like this

if( !visible ) {
  gl_Position = vec4(2.,2.,2.,1.);
}

#7

Might not worth solving anything with GLSL any more though, one should look into /examples/js/nodes, i wanted to write an example but actually couldnt figure it out :frowning: