How to make instance invisible in InstancedBufferGeometry?

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

1 Like

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

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

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

2 Likes

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.

In the vertex shader i usually do something like this

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

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:

Could you explain it more detail(clearly)? I also encountered this problem.:joy:

@Zongyan86
Hi!
Take a look at this post:
https://discourse.threejs.org/t/clouds-of-cubes/3218?u=prisoner849
and its jsfiddle.
Visibility of cubes is controlled in the vertex shader with simple scaling to zero:

float c = smoothNoise( ip * 20. ); // noise for scaling the clouds' cubes

vec3 n = position * step( 0.51, c ) + instancePosition; // scaled by noise

Thank you very much!

This way doesn’t reduce drawCall and triangles