3

This article will explain how Three.js controls the display and hiding of objects, including the following methods:

  1. visible property;
  2. layers property.

The following will introduce the simple usage of the above methods and some differences between them through simple examples. If there are no special instructions, the following source code takes the r105 version as an example:

visible property

visible is a property of Object3D . The object will only be rendered if visible is true . Object3D 35cc71852add796b75627ccd4ecf9453---的对象都可以通过该属性去控制它的显示与否,比如: MeshGroupSpriteLight etc.

Take a simple example:

 // 控制单个物体的显示和隐藏
const geometry = new THREE.PlaneGeometry(1, 1) // 1*1的一个平面
const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) // 红色平面
const plane = new THREE.Mesh(geometry, planeMaterial)
plane.visible = false // 不显示单个物体
scene.add(plane)
 // 控制一组物体的显示和隐藏
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 // 不显示一组物体
scene.add(group)

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

The code logic of this block is implemented in the --- d4308f33bb04f1f8ec6d3b3046c3bf5a projectObject method of WebGLRenderer.js.

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

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

projectObject The method is defined as follows:

 function projectObject( object, camera, groupOrder, sortObjects ) {
  if ( object.visible === false ) return; // 注释1:visible属性是false直接返回
  // ...
  var children = object.children; // 注释2:递归应用在children上

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

    projectObject( children[ i ], camera, groupOrder, sortObjects ); // 注释2:递归应用在children上

  }
}

As can be seen from Note 1, if the Group of visible is false , then it will not be called recursively on children It can achieve the effect of controlling the display and hiding of a group of objects through Group .

visiblefalse的时候, RaycasterintersectObject intersectObjects Inside. The code logic of this block is in Raycaster.js :

 intersectObject: function ( object, recursive, optionalTarget ) {
  // ...
  intersectObject( object, this, intersects, recursive ); // 注释1:调用了公共方法intersectObject
  // ...
},

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

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

    intersectObject( objects[ i ], this, intersects, recursive ); // 注释1:循环调用了公共方法intersectObject

  }
  // ...
}

// 注释1:公共方法intersectObject
function intersectObject( object, raycaster, intersects, recursive ) {

    if ( object.visible === false ) return; // 注释1:如果visible是false,直接return

    // ...
}

As can be seen from Note 1, if Group or a single object visible is false , it will not be detected.

layers property

The layers property of Object3D is a Layers object. Any object that inherits Object3D has this property, for example Camera . Raycaster Although not inherited from Object3D , it also has the layers attribute (r113 and above).

Like the visible property above, the --- layers property can also control the display and hiding of objects, and the behavior of Raycaster . An object is visible when it has at least one same layer as the camera, otherwise it is invisible. Likewise, the intersection test will only be done when the object and Raycaster have at least one of the same layers. Here, it is emphasized that there is at least one , because Layers can set multiple layers.

Layers a total of 32 layers, 0 to 31 layers. Internally represented as:

layer value (binary, 32 bits) illustrate
0 00000000000000000000000000000001 bit 32 is 1
1 00000000000000000000000000000010 bit 31 is 1
2 00000000000000000000000000000100 Bit 30 is 1
3 00000000000000000000000000001000 bit 29 is 1
... ... ...
30 010000000000000000000000000000000 bit 2 is 1
31 10000000000000000000000000000000 1st bit is 1

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

  1. Layersenable disable关闭当前层,参数是上面表格中的031 .
  2. Only the current layer can be opened by the Layers set method of 0 31 .
  3. You can use the Layers method of test to determine whether two Layers objects have at least one common layer .

When multiple layers are turned on, it is actually the binary in the above table that performs a bitwise OR operation. For example, if the --- 0 , 2 , 31 layers are enabled at the same time , then the internally stored value is 10000000000000000000000000000101

layers property is enabled by default only 0 layer.

Still the above example, let's see how to control the display and hide of 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) // 设置平面只有第1层,相机默认是在第0层,所以该物体不会显示出来
scene.add(plane)
 // 控制一组物体的显示和隐藏
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) // 注释1: 设置group只有第一层,相机默认是在第0层,但是此时平面物体还是显示出来了?
group.add(plane)
scene.add(group)

Set a single object layer to see that the object is successfully not displayed. However, when we set layer group we found that group of children (plane object) is still displayed. So, what is the reason for this? Let's take a look at the source code, the same as above projectObject method:

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

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

  var visible = object.layers.test( camera.layers ); // 注释1:判断物体和相机是否存在一个公共层

  if ( visible ) { // 注释1:如果存在,对物体进行下面的处理
    // ...
  }

  var children = object.children; // 注释1:不管该物体是否和相机存在一个公共层,都会对children进行递归

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

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

  }
}

As can be seen from the above note 1, even if the object and the camera do not have a common layer, it does not affect the children display of the object. This also explains why group is set to layers above, but plane objects can still be displayed. From this point of view, the layers and visible properties differ in how they control how objects are shown and hidden.

Same as the visible attribute, let's look at the effect of Layers on Raycaster . I also looked at the Raycaster.js file, but found that there is no layers field at all. Later, I looked at the latest version of r140 :

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

  if ( object.layers.test( raycaster.layers ) ) { // 注释1:判断物体和Raycaster是否有公共层

    object.raycast( raycaster, intersects );

  }

  if ( recursive === true ) { // 注释1:不管该物体和Raycaster是否有公共层,都不影响children

    const children = object.children;

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

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

    }
  }
}

Different from the previous, visible and layers can be used to control the display and hide of objects, visible and layers only one db7cf7af9---can be used To control the behavior of Raycaster , which one takes effect, you can see the migration guide of Three.js .

It can be seen that from the r114 version, the visible is abolished, and the behavior of layers is controlled by 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.

Summarize

As can be seen from the above, there are differences between visible and layers in controlling the display and hiding of objects, Raycaster and so on.

When the object's visible property is false and the layers property test fails, the behavior is summarized as follows:

Attributes Whether the object is displayed Whether the children of the object are displayed Whether the object is raycaster tested Whether the children of the object are tested by raycaster
visible no no No (below version r114) No (below version r114)
layers no Yes No (above version r113) Yes

I hope everyone has gained something, and if there are any mistakes, please leave a message for discussion.


luckness
6.2k 声望5.1k 粉丝