Three.js method of controlling object display and hiding

This article will explain three JS methods of controlling object display and hiding mainly include the following ways:

  1. visible attribute;
  2. layers property.

The following will introduce the simple use methods of the above methods and some differences between them through simple examples. Unless otherwise specified, the following source code takes r105 version as an example:

visible attribute

visible yes Properties of Object3D . Only when visible is true will the object be rendered. Any object that inherits Object3D can control its display through this attribute, such as Mesh, Group, Sprite, Light, etc.

Take a simple example:

// Controls the display and hiding of individual objects
const geometry = new THREE.PlaneGeometry(1, 1) // One plane of 1 * 1
const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) // Red plane
const plane = new THREE.Mesh(geometry, planeMaterial)
plane.visible = false // Do not display individual objects
scene.add(plane)
// Controls the display and hiding of a group of objects
const geometry = new THREE.PlaneGeometry(1, 1)
const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
const plane = new THREE.Mesh(geometry, planeMaterial)
const group = new THREE.Group()
group.add(plane)
group.visible = false // Do not display a group of objects
scene.add(group)

As can be seen from the following examples, when we want to control the display and hiding of a Group of objects, we can put these objects into a Group and only control the display and hiding of the Group.

The logic of this code is WebGLRenderer.js Implemented in the projectObject method of.

First, the projectObject method is called in the render method:

this.render = function ( scene, camera ) {
  // ...
  projectObject( scene, camera, 0, _this.sortObjects );
  // ...
}

The projectObject method is defined as follows:

function projectObject( object, camera, groupOrder, sortObjects ) {
  if ( object.visible === false ) return; // Note 1: the visible attribute is false and is returned directly
  // ...
  var children = object.children; // Note 2: recursion is applied to children

  for ( var i = 0, l = children.length; i < l; i ++ ) {

    projectObject( children[ i ], camera, groupOrder, sortObjects ); // Note 2: recursion is applied to children

  }
}

It can be seen from note 1 that if the visible of the Group is false, it will not be called recursively on children, so the effect of controlling the display and hiding of a Group of objects through the Group can be achieved.

When visible is false, Raycaster's intersectObject or intersectObjects will not take the object into account. The logic of this code is Raycaster.js:

intersectObject: function ( object, recursive, optionalTarget ) {
  // ...
  intersectObject( object, this, intersects, recursive ); // Note 1: the public method intersectObject is called
  // ...
},

intersectObjects: function ( objects, recursive, optionalTarget ) {
  // ...

  for ( var i = 0, l = objects.length; i < l; i ++ ) {

    intersectObject( objects[ i ], this, intersects, recursive ); // Note 1: the public method intersectObject is called in a loop

  }
  // ...
}

// Note 1: public method intersectObject
function intersectObject( object, raycaster, intersects, recursive ) {

    if ( object.visible === false ) return; // Note 1: if visible is false, return directly

    // ...
}

As can be seen from note 1, if the visible of a Group or a single object is false, no detection will be performed.

layers property

layers property of Object3D It's a Layers Object. Any object that inherits Object3D has this property, such as Camera. Although Raycaster does not inherit from Object3D, it also has layers attribute (version r113 or above).

Like the visible attribute above, the Layers attribute can also control the display and hiding of objects and the behavior of Raycaster. When the object and the camera have at least one same layer, the object is visible, otherwise it is not visible. Similarly, the intersection test will be conducted only when the object and Raycaster have at least one same layer. Here, it is emphasized that there is at least one layer, because Layers can set multiple Layers.

Layers can represent a total of 32 layers, 0 to 31 layers. The internal representation is:

layervalue (binary, 32-bit)explain
000000000000000000000000000000001The 32nd bit is 1
100000000000000000000000000000010The 31st digit is 1
200000000000000000000000000000100The 30th is 1
300000000000000000000000000001000The 29th is 1
.........
3001000000000000000000000000000000The second digit is 1
3110000000000000000000000000000000The first digit is 1

Layers can be set to have multiple layers at the same time:

  1. You can turn on and off the current layer through the enable and disable methods of Layers. The parameters are 0 to 31 in the above table.
  2. You can only open the current layer through the set method of Layers, and the parameters are 0 to 31 in the above table.
  3. You can judge whether there is at least one common layer between two Layers objects through the test method of Layers.

When multiple layers are opened, it is actually the binary in the above table for bit or operation. For example, if layers 0, 2 and 31 are opened at the same time, the internally stored value is 1000000000000000000 101.

The layers property only turns on layer 0 by default.

As in the above example, let's see how to control the display and hiding of objects:

// Controls the display and hiding of individual objects
const geometry = new THREE.PlaneGeometry(1, 1)
const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
const plane = new THREE.Mesh(geometry, planeMaterial)
plane.layers.set(1) // The setting plane has only layer 1, and the camera defaults to layer 0, so the object will not be displayed
scene.add(plane)
// Controls the display and hiding of a group of objects
const geometry = new THREE.PlaneGeometry(1, 1)
const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
const plane = new THREE.Mesh(geometry, planeMaterial)
const group = new THREE.Group()
group.layers.set(1) // Note 1: set the group to have only the first layer, and the camera is at layer 0 by default, but the plane object is still displayed at this time?
group.add(plane)
scene.add(group)

Setting the layer of a single object can see that the object is not displayed successfully. However, when we set the layer for the group, we found that the children (plane objects) of the group are still displayed. So what is the reason? Let's look at the source code, which is also the projectObject method above:

function projectObject( object, camera, groupOrder, sortObjects ) {

  if ( object.visible === false ) return;

  var visible = object.layers.test( camera.layers ); // Note 1: judge whether there is a common layer between the object and the camera

  if ( visible ) { // Note 1: if it exists, carry out the following treatment on the object
    // ...
  }

  var children = object.children; // Note 1: children will be recursion whether the object has a common layer with the camera or not

  for ( var i = 0, l = children.length; i < l; i ++ ) {

    projectObject( children[ i ], camera, groupOrder, sortObjects );

  }
}

As can be seen from note 1 above, even if there is no common layer between the object and the camera, the children display of the object is not affected. This explains why layers are set for the group, but plane objects can still be displayed. From this point of view, the layers and visible attributes are different in controlling the display and hiding of objects.

Like the visible attribute, let's take a look at the influence of Layers on Raycaster. I saw it again Raycaster.js File, but it is found that there is no layers field at all. Later, I read the latest version of r140 Raycaster.js:

function intersectObject( object, raycaster, intersects, recursive ) {

  if ( object.layers.test( raycaster.layers ) ) { // Note 1: judge whether the object and Raycaster have a common layer

    object.raycast( raycaster, intersects );

  }

  if ( recursive === true ) { // Note 1: whether the object and Raycaster have a common layer or not does not affect children

    const children = object.children;

    for ( let i = 0, l = children.length; i < l; i ++ ) {

      intersectObject( children[ i ], raycaster, intersects, true );

    }
  }
}

Unlike the previous ones, both visible and layers can be used to control the display and hiding of objects. Only one of visible and layers can be used to control the behavior of Raycaster. You can see which one works Three.js migration guide.

It can be seen that from r114 version, visible is abolished and layers are used to control the behavior of Raycaster:

r113 → r114
Raycaster honors now invisible 3D objects in intersection tests. Use the new property Raycaster.layers for selectively ignoring 3D objects during raycasting.

summary

It can be seen from the above that visible and layers are different in controlling the display and hiding of objects and whether Raycaster is carried out.

When the visible attribute of the object is false and the layers attribute test fails, the behavior is summarized as follows:

attributeWhether the object is displayedWhether the children of the object are displayedIs the object tested by raymasterAre the children of the object tested by raymaster
visiblenonoNo (under r114 version)No (under r114 version)
layersnoyesNo (r113 version or above)yes

I hope you can gain something. If you have any mistakes, please leave a message for discussion.

Tags: Front-end Three.js

Posted by theredking on Sun, 22 May 2022 18:33:52 +0300