Questions on:

(1) There are two renderers. One for the 3D objects (renderer) and one for the 2D objects (labelRenderer). When rendering a scene it is necessary to call them both, one after the other

However, the following line

   const controls = new OrbitControls( camera, labelRenderer.domElement );

assigns controls to ONLY to labelRenderer.

Why not renderer instead?
Why not renderer also?

(2) Assigning the position of a label takes these calls:

moonLabel.position.set( 1.5 * MOON_RADIUS, 0, 0 ); 0, 1 );

In the second call, what is the center and what does (0,1) mean?


CSS2DRenderer is an extra 2D div that overlays the main 3D canvas, it’s simply a container to place created CSS2DObjects in, if you look at the “elements” panel of dev tools you will see this overlay, as this is on top of the 3D canvas, using the CSS2D “layer” makes sense as it’s just referring to the overlaid div element, there’s no need for both to be referenced and trying to use the usual renderer.domElement would have it’s pointer events “blocked” by the 2D div in front of it…

it’s just a vector2 that allows you to specify where the 2DObject is centered, I guess this is normalized so no matter the dims of the 2DObjects div element content (0.5,0.5) will displace the content by half it’s width and height as to be central to it’s point of origin ( the Object3D “pivot point” that the class extends…)


In the following code snippet taken from the same example,

				const earthLabel = new CSS2DObject( earthDiv );
				earthLabel.position.set( 1.5 * EARTH_RADIUS, 0, 0 ); 0, 1 );
				earth.add( earthLabel );

is the position of (1.5*EARTH_RADIUS, 0, 0) being defined RELATIVE to the center of the “earth” object?
Or is it an ABSOLUTE position relative to the global origin?

If relative, in this case since the “earth” object is a sphere, the center is obvious. But what if it a general mesh? What would be the center?


Chrome/Edge devtools has a 3D view in which you can see DOM layers. If you take a look, you’ll see that the red layer on top covers all the rest. For this reason the example uses the layer that is on top for catching pointer events because that’s layer that is receiving the pointer interaction (the layers behind are blocked). Imagine your pointer casts a ray onto these layers, and it stops at the first surface that it hits (this is in the browser’s CSS space).

The browser does its own raycasting on CSS 3D surfaces too, but those are not pictured in the devtools 3D view, the 3D view only shows the CSS render layers. You might think of these layers roughly as quads with a texture onto which the CSS engine renders to. One of those quads includes the content of the renderer’s <canvas>, and the other quad’s texture includes all of the CSS 2D content from labelRenderer.

Did that make any sense? :smiley:

You can see and treat the CSS2DObject as any other Object3D (it is an extension of the Object3D class) if for instance in the case you used…


Yes the label position would be and stay relative to the earth object, in the case of example in question though, both the earth object and label are being added to the scene so will be relative to the global origin, eg. If the earth object is moved the label will stay relative to it’s own global origin, to update it’s position in the scene (relative to the earth object) you would set it’s position from the earth objects localToWorld position and then add 1.5*EARTH_RADIUS to it’s position.x

^ True. Just remember: objects are always positioned relative to their parent’s origin (0,0,0).

The center of a mesh doesn’t come into play in this case, and the center of a mesh is not necessarily the origin. A mesh has an origin (0,0,0), and any geometry vertices are just points that are relative to the object’s (0,0,0). So it is very possibly you can have a mesh where all of its vertices are more than 100 in every axis, which means the origin of the mesh object will always be outside of the actual geometry (or in other words, the geometry will always be away from the object’s origin).

With the above in mind, when any child of a Mesh is positioned, the child is always positioned relative to the mesh’s origin (0,0,0) and has nothing to do with the geometry.

Think of it kinda like this:

  • a Mesh object has .children, and those children are position relative to the Mesh’s origin (0,0,0)
  • a Mesh also has geometry, which are a bag of vertices, and similar to children, those vertices are also positioned relative to the Mesh’s origin (0,0,0), and this has no effect on positioning of .children.
  • If you modify the Mesh’s geometry vertices, this does nothing to the positioning of .children
  • it is as if .geometry is a separate special child that is not inside of .children.