TransformControlsGizmo constructor

TransformControlsGizmo(
  1. TransformControls controls
)

Implementation

TransformControlsGizmo(this.controls) : super() {
  type = 'TransformControlsGizmo';

  // shared materials

  var gizmoMaterial = MeshBasicMaterial(
      {"depthTest": false, "depthWrite": false, "fog": false, "toneMapped": false, "transparent": true});

  var gizmoLineMaterial = LineBasicMaterial(
      {"depthTest": false, "depthWrite": false, "fog": false, "toneMapped": false, "transparent": true});

  // Make unique material for each axis/color

  var matInvisible = gizmoMaterial.clone();
  matInvisible.opacity = 0.15;

  var matHelper = gizmoLineMaterial.clone();
  matHelper.opacity = 0.5;

  var matRed = gizmoMaterial.clone();
  matRed.color.setHex(0xff0000);

  var matGreen = gizmoMaterial.clone();
  matGreen.color.setHex(0x00ff00);

  var matBlue = gizmoMaterial.clone();
  matBlue.color.setHex(0x0000ff);

  var matRedTransparent = gizmoMaterial.clone();
  matRedTransparent.color.setHex(0xff0000);
  matRedTransparent.opacity = 0.5;

  var matGreenTransparent = gizmoMaterial.clone();
  matGreenTransparent.color.setHex(0x00ff00);
  matGreenTransparent.opacity = 0.5;

  var matBlueTransparent = gizmoMaterial.clone();
  matBlueTransparent.color.setHex(0x0000ff);
  matBlueTransparent.opacity = 0.5;

  var matWhiteTransparent = gizmoMaterial.clone();
  matWhiteTransparent.opacity = 0.25;

  var matYellowTransparent = gizmoMaterial.clone();
  matYellowTransparent.color.setHex(0xffff00);
  matYellowTransparent.opacity = 0.25;

  var matYellow = gizmoMaterial.clone();
  matYellow.color.setHex(0xffff00);

  var matGray = gizmoMaterial.clone();
  matGray.color.setHex(0x787878);

  // reusable geometry

  var arrowGeometry = CylinderGeometry(0, 0.04, 0.1, 12);
  arrowGeometry.translate(0, 0.05, 0);

  var scaleHandleGeometry = BoxGeometry(0.08, 0.08, 0.08);
  scaleHandleGeometry.translate(0, 0.04, 0);

  var lineGeometry = BufferGeometry();
  lineGeometry.setAttribute('position', Float32BufferAttribute(Float32Array.from([0.0, 0.0, 0.0, 1.0, 0.0, 0.0]), 3));

  var lineGeometry2 = CylinderGeometry(0.0075, 0.0075, 0.5, 3);
  lineGeometry2.translate(0, 0.25, 0);

  circleGeometry(radius, arc) {
    var geometry = TorusGeometry(radius, 0.0075, 3, 64, arc * Math.pi * 2);
    geometry.rotateY(Math.pi / 2);
    geometry.rotateX(Math.pi / 2);
    return geometry;
  }

  // Special geometry for transform helper. If scaled with position vector it spans from [0,0,0] to position

  translateHelperGeometry() {
    var geometry = BufferGeometry();

    geometry.setAttribute(
        'position', Float32BufferAttribute(Float32Array.fromList([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]), 3));

    return geometry;
  }

  // Gizmo definitions - custom hierarchy definitions for setupGizmo() function

  var gizmoTranslate = {
    "X": [
      [
        Mesh(arrowGeometry, matRed),
        [0.5, 0.0, 0.0],
        [0.0, 0.0, -Math.pi / 2]
      ],
      [
        Mesh(arrowGeometry, matRed),
        [-0.5, 0.0, 0.0],
        [0.0, 0.0, Math.pi / 2]
      ],
      [
        Mesh(lineGeometry2, matRed),
        [0.0, 0.0, 0.0],
        [0.0, 0.0, -Math.pi / 2]
      ]
    ],
    "Y": [
      [
        Mesh(arrowGeometry, matGreen),
        [0, 0.5, 0]
      ],
      [
        Mesh(arrowGeometry, matGreen),
        [0, -0.5, 0],
        [Math.pi, 0, 0]
      ],
      [Mesh(lineGeometry2, matGreen)]
    ],
    "Z": [
      [
        Mesh(arrowGeometry, matBlue),
        [0, 0, 0.5],
        [Math.pi / 2, 0, 0]
      ],
      [
        Mesh(arrowGeometry, matBlue),
        [0, 0, -0.5],
        [-Math.pi / 2, 0, 0]
      ],
      [
        Mesh(lineGeometry2, matBlue),
        null,
        [Math.pi / 2, 0, 0]
      ]
    ],
    "XYZ": [
      [
        Mesh(OctahedronGeometry(0.1, 0), matWhiteTransparent.clone()),
        [0, 0, 0]
      ]
    ],
    "XY": [
      [
        Mesh(BoxGeometry(0.15, 0.15, 0.01), matBlueTransparent.clone()),
        [0.15, 0.15, 0]
      ]
    ],
    "YZ": [
      [
        Mesh(BoxGeometry(0.15, 0.15, 0.01), matRedTransparent.clone()),
        [0, 0.15, 0.15],
        [0, Math.pi / 2, 0]
      ]
    ],
    "XZ": [
      [
        Mesh(BoxGeometry(0.15, 0.15, 0.01), matGreenTransparent.clone()),
        [0.15, 0, 0.15],
        [-Math.pi / 2, 0, 0]
      ]
    ]
  };

  var pickerTranslate = {
    "X": [
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0.3, 0, 0],
        [0, 0, -Math.pi / 2]
      ],
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [-0.3, 0, 0],
        [0, 0, Math.pi / 2]
      ]
    ],
    "Y": [
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, 0.3, 0]
      ],
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, -0.3, 0],
        [0, 0, Math.pi]
      ]
    ],
    "Z": [
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, 0, 0.3],
        [Math.pi / 2, 0, 0]
      ],
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, 0, -0.3],
        [-Math.pi / 2, 0, 0]
      ]
    ],
    "XYZ": [
      [Mesh(OctahedronGeometry(0.2, 0), matInvisible)]
    ],
    "XY": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.01), matInvisible),
        [0.15, 0.15, 0]
      ]
    ],
    "YZ": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.01), matInvisible),
        [0, 0.15, 0.15],
        [0, Math.pi / 2, 0]
      ]
    ],
    "XZ": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.01), matInvisible),
        [0.15, 0, 0.15],
        [-Math.pi / 2, 0, 0]
      ]
    ]
  };

  var helperTranslate = {
    "START": [
      [Mesh(OctahedronGeometry(0.01, 2), matHelper), null, null, null, 'helper']
    ],
    "END": [
      [Mesh(OctahedronGeometry(0.01, 2), matHelper), null, null, null, 'helper']
    ],
    "DELTA": [
      [Line(translateHelperGeometry(), matHelper), null, null, null, 'helper']
    ],
    "X": [
      [
        Line(lineGeometry, matHelper.clone()),
        [-1e3, 0, 0],
        null,
        [1e6, 1, 1],
        'helper'
      ]
    ],
    "Y": [
      [
        Line(lineGeometry, matHelper.clone()),
        [0, -1e3, 0],
        [0, 0, Math.pi / 2],
        [1e6, 1, 1],
        'helper'
      ]
    ],
    "Z": [
      [
        Line(lineGeometry, matHelper.clone()),
        [0, 0, -1e3],
        [0, -Math.pi / 2, 0],
        [1e6, 1, 1],
        'helper'
      ]
    ]
  };

  var gizmoRotate = {
    "XYZE": [
      [
        Mesh(circleGeometry(0.5, 1), matGray),
        null,
        [0, Math.pi / 2, 0]
      ]
    ],
    "X": [
      [Mesh(circleGeometry(0.5, 0.5), matRed)]
    ],
    "Y": [
      [
        Mesh(circleGeometry(0.5, 0.5), matGreen),
        null,
        [0, 0, -Math.pi / 2]
      ]
    ],
    "Z": [
      [
        Mesh(circleGeometry(0.5, 0.5), matBlue),
        null,
        [0, Math.pi / 2, 0]
      ]
    ],
    "E": [
      [
        Mesh(circleGeometry(0.75, 1), matYellowTransparent),
        null,
        [0, Math.pi / 2, 0]
      ]
    ]
  };

  var helperRotate = {
    "AXIS": [
      [
        Line(lineGeometry, matHelper.clone()),
        [-1e3, 0, 0],
        null,
        [1e6, 1, 1],
        'helper'
      ]
    ]
  };

  var pickerRotate = {
    "XYZE": [
      [Mesh(SphereGeometry(0.25, 10, 8), matInvisible)]
    ],
    "X": [
      [
        Mesh(TorusGeometry(0.5, 0.1, 4, 24), matInvisible),
        [0, 0, 0],
        [0, -Math.pi / 2, -Math.pi / 2]
      ],
    ],
    "Y": [
      [
        Mesh(TorusGeometry(0.5, 0.1, 4, 24), matInvisible),
        [0, 0, 0],
        [Math.pi / 2, 0, 0]
      ],
    ],
    "Z": [
      [
        Mesh(TorusGeometry(0.5, 0.1, 4, 24), matInvisible),
        [0, 0, 0],
        [0, 0, -Math.pi / 2]
      ],
    ],
    "E": [
      [Mesh(TorusGeometry(0.75, 0.1, 2, 24), matInvisible)]
    ]
  };

  var gizmoScale = {
    "X": [
      [
        Mesh(scaleHandleGeometry, matRed),
        [0.5, 0, 0],
        [0, 0, -Math.pi / 2]
      ],
      [
        Mesh(lineGeometry2, matRed),
        [0, 0, 0],
        [0, 0, -Math.pi / 2]
      ],
      [
        Mesh(scaleHandleGeometry, matRed),
        [-0.5, 0, 0],
        [0, 0, Math.pi / 2]
      ],
    ],
    "Y": [
      [
        Mesh(scaleHandleGeometry, matGreen),
        [0, 0.5, 0]
      ],
      [Mesh(lineGeometry2, matGreen)],
      [
        Mesh(scaleHandleGeometry, matGreen),
        [0, -0.5, 0],
        [0, 0, Math.pi]
      ],
    ],
    "Z": [
      [
        Mesh(scaleHandleGeometry, matBlue),
        [0, 0, 0.5],
        [Math.pi / 2, 0, 0]
      ],
      [
        Mesh(lineGeometry2, matBlue),
        [0, 0, 0],
        [Math.pi / 2, 0, 0]
      ],
      [
        Mesh(scaleHandleGeometry, matBlue),
        [0, 0, -0.5],
        [-Math.pi / 2, 0, 0]
      ]
    ],
    "XY": [
      [
        Mesh(BoxGeometry(0.15, 0.15, 0.01), matBlueTransparent),
        [0.15, 0.15, 0]
      ]
    ],
    "YZ": [
      [
        Mesh(BoxGeometry(0.15, 0.15, 0.01), matRedTransparent),
        [0, 0.15, 0.15],
        [0, Math.pi / 2, 0]
      ]
    ],
    "XZ": [
      [
        Mesh(BoxGeometry(0.15, 0.15, 0.01), matGreenTransparent),
        [0.15, 0, 0.15],
        [-Math.pi / 2, 0, 0]
      ]
    ],
    "XYZ": [
      [Mesh(BoxGeometry(0.1, 0.1, 0.1), matWhiteTransparent.clone())],
    ]
  };

  var pickerScale = {
    "X": [
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0.3, 0, 0],
        [0, 0, -Math.pi / 2]
      ],
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [-0.3, 0, 0],
        [0, 0, Math.pi / 2]
      ]
    ],
    "Y": [
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, 0.3, 0]
      ],
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, -0.3, 0],
        [0, 0, Math.pi]
      ]
    ],
    "Z": [
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, 0, 0.3],
        [Math.pi / 2, 0, 0]
      ],
      [
        Mesh(CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
        [0, 0, -0.3],
        [-Math.pi / 2, 0, 0]
      ]
    ],
    "XY": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.01), matInvisible),
        [0.15, 0.15, 0]
      ],
    ],
    "YZ": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.01), matInvisible),
        [0, 0.15, 0.15],
        [0, Math.pi / 2, 0]
      ],
    ],
    "XZ": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.01), matInvisible),
        [0.15, 0, 0.15],
        [-Math.pi / 2, 0, 0]
      ],
    ],
    "XYZ": [
      [
        Mesh(BoxGeometry(0.2, 0.2, 0.2), matInvisible),
        [0, 0, 0]
      ],
    ]
  };

  var helperScale = {
    "X": [
      [
        Line(lineGeometry, matHelper.clone()),
        [-1e3, 0, 0],
        null,
        [1e6, 1, 1],
        'helper'
      ]
    ],
    "Y": [
      [
        Line(lineGeometry, matHelper.clone()),
        [0, -1e3, 0],
        [0, 0, Math.pi / 2],
        [1e6, 1, 1],
        'helper'
      ]
    ],
    "Z": [
      [
        Line(lineGeometry, matHelper.clone()),
        [0, 0, -1e3],
        [0, -Math.pi / 2, 0],
        [1e6, 1, 1],
        'helper'
      ]
    ]
  };

  // Creates an Object3D with gizmos described in custom hierarchy definition.

  setupGizmo(gizmoMap) {
    var gizmo = Object3D();

    for (var name in gizmoMap.keys) {
      var len = gizmoMap[name].length;

      for (var i = (len - 1); i >= 0; i--) {
        var gi = gizmoMap[name][i];

        dynamic object;
        if (gi.length > 0) {
          object = gi[0].clone();
        }

        List<num>? position;
        if (gi.length > 1) {
          position = gi[1];
        }

        List<num>? rotation;
        if (gi.length > 2) {
          rotation = gi[2];
        }

        List<num>? scale;
        if (gi.length > 3) {
          scale = gi[3];
        }

        dynamic tag;
        if (gi.length > 4) {
          tag = gi[4];
        }

        // name and tag properties are essential for picking and updating logic.
        object.name = name;
        object.tag = tag;

        if (position != null) {
          object.position.set(position[0].toDouble(), position[1].toDouble(), position[2].toDouble());
        }

        if (rotation != null) {
          object.rotation.set(rotation[0].toDouble(), rotation[1].toDouble(), rotation[2].toDouble());
        }

        if (scale != null) {
          object.scale.set(scale[0].toDouble(), scale[1].toDouble(), scale[2].toDouble());
        }

        object.updateMatrix();

        var tempGeometry = object.geometry.clone();
        tempGeometry.applyMatrix4(object.matrix);
        object.geometry = tempGeometry;
        object.renderOrder = Math.infinity;

        object.position.set(0.0, 0.0, 0.0);
        object.rotation.set(0.0, 0.0, 0.0);
        object.scale.set(1.0, 1.0, 1.0);

        gizmo.add(object);
      }
    }

    return gizmo;
  }

  // Gizmo creation

  gizmo['translate'] = setupGizmo(gizmoTranslate);
  gizmo['rotate'] = setupGizmo(gizmoRotate);
  gizmo['scale'] = setupGizmo(gizmoScale);
  picker['translate'] = setupGizmo(pickerTranslate);
  picker['rotate'] = setupGizmo(pickerRotate);
  picker['scale'] = setupGizmo(pickerScale);
  helper['translate'] = setupGizmo(helperTranslate);
  helper['rotate'] = setupGizmo(helperRotate);
  helper['scale'] = setupGizmo(helperScale);

  add(gizmo['translate']);
  add(gizmo['rotate']);
  add(gizmo['scale']);
  add(picker['translate']);
  add(picker['rotate']);
  add(picker['scale']);
  add(helper['translate']);
  add(helper['rotate']);
  add(helper['scale']);

  // Pickers should be hidden always

  picker['translate'].visible = false;
  picker['rotate'].visible = false;
  picker['scale'].visible = false;
}