1

This is a question about javascript and three.js coding style conventions. I prefer to use the latest ES-whatever conventions.

I'm wondering if instead of doing the usual:

var scene = new THREE.Scene();
var cube = new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial(0xffffff))
scene.add(cube)

it would be ok to store the mesh object (and other objects, maybe lights and even camera) as properties of the scene object:

const scene = new THREE.Scene(); // or var, but that's not my question
scene.cube = THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial(0xffffff))
scene.add(scene.cube)

I like the idea of having references to all the three.js objects underneath the scene namespace -- makes it easier for me to access them later. I know I could use this with .name and .getObjectByName but that takes more code and seems messier to me.

foobarbecue
  • 6,780
  • 4
  • 28
  • 54
  • Voting to close as it's primarily opinion based. That said, here is my opinion: it's bad practice. It doesn't really make your code cleaner or easier to reason about. In fact it makes it more complicated. Plus mutating an instance of an object created/managed by a 3rd party library can be unpredictable. If you want to store related data references together, use a regular old object: `const sceneData = {scene, cube};` – jered Mar 11 '19 at 23:12
  • "it's a matter of opinion" would be a satisfactory answer for me. I just want to know if this is absolutely wrong, absolutely right, or somewhere in between. – foobarbecue Mar 11 '19 at 23:15

2 Answers2

3

There is a field on Object3D derived objects called .userData that you can store stuff that should get saved/serialized. But as far as storing props directly on objects.. It works.. but kinda has potential for problems if you end up overwriting something or later revs of three make use of your property name...

Edit: after reading the other posts here, they raise some good point, and I also wanted to throw out there that you can subclass the built-in three objects and make your own custom type that has your stuff. That might be tidier.

manthrax
  • 4,918
  • 1
  • 17
  • 16
2

As far as separation of concern goes, you don't want to use Three's objects as data holders. It might seem like an easy way out, but will greatly reduce maintainability of your code. There is nothing preventing you from doing it today, though. Just consider, that you will have

scene.cube
scene.children[0] //same cube
scene.getObjectById(... cube id ...) //same cube
//... byName, ...byProperty etc. all pointing to the same cube

Remember, Scene extends Object3D with all its methods and properties, so, in the example scene below all objects are Object3D with each having children[] property.

        [scene]
      +----^-----------------------------+
  [chairGroup]                        [light] 
  +--^--+-----+-----+-----+------+
[leg] [leg] [leg] [leg] [back] [seat] 

Doesn't each node above look similar to DOM's Element?

I would encourage you to think about your scene as a tree. In fact, any UI is an n-tree of elements: web, mobile, X11 etc., and every UI framework is a tool to manipulate such tree. All approaches you use to manipulate DOM tree effectively work here.

Hence, below are various ways you can organize your code, from simple to more complex:

  • hello world rotating cube example is fine, 15-20 lines of code are ok as-is
  • rendering context: move scene, camera and renderer into some context object you can pass around your layers. Think of it as an equivalent of document in the browser.
  • high-level "Shadow DOM": organize a tree of your own components that each handle a group of 3d objects, make them react to events - external from UI clicks etc., or from Three, like visitor pattern during rendering. You can either keep references to 3d objects on these components, or recursively pass your structure to a function to adjust scene's hierarchy. Examples of such components in your tree could be Chair, Building, Planet, Starship etc.
  • data model: it might be tempting to store some data inside your components, but you should have a distinction between external data, usually a bit global, like numeberOfPlanets, timeOfDay etc., and internal data, like current rotation speed of a planet. Latter can be kept as part of your scene domain components.
  • full MVC: as with any UI, model-view-controller is applicable here. E.g. you can follow this intro into three.js MVC.
  • mediators, observers and usual workflows. See, e.g. my answer here.
  • ... all the way to Redux-like immutable state management system

I hope, this answer will help people do some tactical architecture around Three.js that suits their project best.

Alex Pakka
  • 9,466
  • 3
  • 45
  • 69