three.jsbuffer-geometry

How to rotate individual planes of buffer geometry along their own origin


There's buffer geometry that consists of many planes on sphere. I'm trying to rotate each plane indidividually along its own origin, so overall animation will look more like explosion. But instead of rotating along their own axis this planes is kind of floating on a sphere.

Here are vertex shader code and codepen with all code, and button to trigger animation.

uniform float uTime;
uniform float uProgress;
uniform float uGravity;

attribute vec3 attributePositionDest;
attribute vec3 attributeCentroid;
attribute vec3 attributeAxis;
attribute float attributeGravityVelocity;

varying vec3 vEye;
varying vec3 vNormal;
varying vec3 vReflect;

// http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/
vec4 quat_from_axis_angle(vec3 axis, float angle) {
  vec4 qr;
  float half_angle = (angle * 0.5) * 3.14159 / 180.0;
  qr.x = axis.x * sin(half_angle);
  qr.y = axis.y * sin(half_angle);
  qr.z = axis.z * sin(half_angle);
  qr.w = cos(half_angle);
  return qr;
}
vec3 rotate_vertex_position(vec3 position, vec3 axis, float angle) { 
  vec4 q = quat_from_axis_angle(axis, angle);
  vec3 v = position.xyz;
  return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
}

// main
void main() {
  vec3 positionAdjusted = position;
  float vTemp =  1. - ((attributeCentroid.x + attributeCentroid.y)*0.5 + 1.)/2.;

  float tProgress = max(0.0, (uProgress - vTemp*0.5) / 0.25) * uProgress;
  float vectorLength = length(position);
  float gravityAdjustment = (uGravity + attributeGravityVelocity) * uTime * vectorLength * 0.25;

  positionAdjusted = mix(positionAdjusted, attributePositionDest, tProgress); // translate to destination
  positionAdjusted = rotate_vertex_position(positionAdjusted, attributeAxis, max(1., uTime * 0.5)); // rotate plane
  positionAdjusted = vec3(positionAdjusted.x, positionAdjusted.y + gravityAdjustment, positionAdjusted.z); // add gravity

  vec4 worldPosition = modelMatrix * vec4(positionAdjusted, 1.0);
  vec3 worldNormal = normalize(mat3(modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz) * normal);
  vec3 I = worldPosition.xyz - cameraPosition;

  // set varying vars
  vNormal = normal;
  vEye = normalize(vec3(modelViewMatrix * vec4(positionAdjusted, 1.0)));
  vReflect = reflect(I, worldNormal);

  gl_Position = projectionMatrix * modelViewMatrix * vec4(positionAdjusted, 1.);
}

https://codepen.io/olhapi/pen/vYWrXMK?editors=0010


Solution

  • You have a problem with half_angle unit in quat_from_axis_angle()

    remove the rad conversion and it will turn , when utime > 1 second :

    vec4 quat_from_axis_angle(vec3 axis, float angle) {
      vec4 qr;
      float half_angle = (angle * 0.5); // * 3.14159 / 180.0;
      qr.x = axis.x * sin(half_angle);
      qr.y = axis.y * sin(half_angle);
      qr.z = axis.z * sin(half_angle);
      qr.w = cos(half_angle);
      return qr;
    }