0
votes

I want to make transforms around a pivot point using webgl. Inspired by Three.js and this comment

Create a object that will act as pivot:

mesh.position.y = 10;

var pivot = new THREE.Object3D(); pivot.add( mesh );

scene.add( pivot );

I am trying to set the pivot to some point and rotate the object. Here's my code to do these:

  let transforms = {};

  this.makeTransform = (name, transform) => {

    transforms[name] = modelMatrix(transform);

  };

  const modelMatrix = transform => {
    let matrix = transforms[transform.transform] || mat4.identity();

    return mat4.transform(matrix, transform);
  };


  const mvpMatrix = modelMatrix => {
    const { pos: camPos, target, up } = camera;
    const { fov, aspect, near, far } = camera;

    let camMatrix = mat4.lookAt(camPos, target, up);
    let viewMatrix = mat4.inverse(camMatrix);

    let projectionMatrix = mat4.perspective(fov, aspect, near, far);

    let viewProjectionMatrix = mat4.multiply(projectionMatrix, viewMatrix);

    return mat4.multiply(viewProjectionMatrix, modelMatrix);
  };



  this.drawMesh = (name, transform) => {    
    const uMatrix = mvpMatrix(modelMatrix(transform));
    // set uMatrix as uniform and draw
  }

Usage (render code):

r.makeTransform('root', {
  translate: [100, 0, 0]
});

r.drawMesh('sample', {
  transform: 'root',
  translate: [0.0, 0.0, 2.0],
  rotate: [0.0,
           Math.PI,
           0.0]
});

So I don't have a scene graph, but I make transform matrices and apply them to objects. Here sample mesh is applied a root transform. This translates the object on the x axis, and still rotates the object around it's origin.

But I can't rotate the object around a pivot point using the mentioned approach.

Based on gman answer this works:

r.makeTransform('root', {
  translate: [0, 0, 0],
  rotate: [0.0, u.PI, 0.0]
});

r.drawMesh('sample', {
  transform: 'root',
  translate: [100.0, 0.0, 0.0]
});

How does THREE.js rotate around the center of the object by default?

Because the vertices in geometries are defined so that the object center is at 0,0 origin.

like here

 var x = ix * segmentWidth - widthHalf;

or here

  for (let i = 0; i < vertices.length; i+=3) {
    vertices[i] -= widthHalf;
    vertices[i+1] -= heightHalf;
    vertices[i+2] -= depthHalf;
  }
1

1 Answers

1
votes

A scene graph is just a way to represent a hierarchy of matrices. Here's a simple human scene graph

root
 └─base
    └─waist
       ├─chest
       │  ├─neck
       │  │  └─head
       │  ├─left arm
       │  │  └─left forearm
       │  │     └─left hand
       │  └─right arm
       │     └─right forearm
       │        └─right hand
       ├─left thigh
       │  └─left leg
       │     └─left foot
       └─right thigh
          └─right left
             └─right foot

So to draw the right arm based on stereotypical webgl matrix math its

projectionMatrix * viewMatrix * rootMatrix * baseMatrix
   * waistMatrix * chestMatrix * rightArmMatrix * rightForeArmMatrix
   * rightHandMatrix 

So looking at that you can translate any three.js scenegraph into plain matrix math. If it's

scene.add(pivot);
pivot.add(mesh);

Then your scene graph looks like

scene
 └─pivot
    └─mesh

so you need to end up with

projectionMatrix * viewMatrix * sceneMatrix * pivotMatrix * meshMatrix

Or to look at it another way

modelMatrix = sceneMatrix * pivotMatrix * meshMatrix

projectMatrix * viewMatrix * modelMatrix

The scenegraph itself just a way to make it easy it organize the matrices in a generic and flexible way rather than hard code all the math.

Note: sceneMatrix is usually the identity so you can leave it out but technically the scene in three.js is another node in the scene graph and so itself represents a matrix.