This article will explain three JS methods of controlling object display and hiding mainly include the following ways:
- visible attribute;
- 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:
layer | value (binary, 32-bit) | explain |
---|---|---|
0 | 00000000000000000000000000000001 | The 32nd bit is 1 |
1 | 00000000000000000000000000000010 | The 31st digit is 1 |
2 | 00000000000000000000000000000100 | The 30th is 1 |
3 | 00000000000000000000000000001000 | The 29th is 1 |
... | ... | ... |
30 | 01000000000000000000000000000000 | The second digit is 1 |
31 | 10000000000000000000000000000000 | The first digit is 1 |
Layers can be set to have multiple layers at the same time:
- 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.
- You can only open the current layer through the set method of Layers, and the parameters are 0 to 31 in the above table.
- 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:
attribute | Whether the object is displayed | Whether the children of the object are displayed | Is the object tested by raymaster | Are the children of the object tested by raymaster |
---|---|---|---|---|
visible | no | no | No (under r114 version) | No (under r114 version) |
layers | no | yes | No (r113 version or above) | yes |
I hope you can gain something. If you have any mistakes, please leave a message for discussion.