Browse Source

improved Node rotation API

Daniel Salvadori 7 years ago
parent
commit
eb5d332001
1 changed files with 80 additions and 71 deletions
  1. 80 71
      core/node.go

+ 80 - 71
core/node.go

@@ -22,14 +22,15 @@ type INode interface {
 
 // Node represents an object in 3D space existing within a hierarchy.
 type Node struct {
-	Dispatcher             // Embedded event dispatcher
-	parent     INode       // Parent node
-	children   []INode     // Children nodes
-	name       string      // Optional node name
-	loaderID   string      // ID used by loader
-	visible    bool        // Whether the node is visible
-	changed    bool        // Whether the position/orientation/scale changed
-	userData   interface{} // Generic user data
+	Dispatcher                 // Embedded event dispatcher
+	parent         INode       // Parent node
+	children       []INode     // Children nodes
+	name           string      // Optional node name
+	loaderID       string      // ID used by loader
+	visible        bool        // Whether the node is visible
+	matNeedsUpdate bool        // Whether the the local matrix needs to be updated because position or scale has changed
+	rotNeedsUpdate bool        // Whether the euler rotation and local matrix need to be updated because the quaternion has changed
+	userData       interface{} // Generic user data
 
 	// Spatial properties
 	position    math32.Vector3    // Node position in 3D space (relative to parent)
@@ -57,7 +58,6 @@ func (n *Node) Init() {
 
 	n.children = make([]INode, 0)
 	n.visible = true
-	n.changed = true
 
 	// Initialize spatial properties
 	n.position.Set(0, 0, 0)
@@ -132,7 +132,7 @@ func (n *Node) LoaderID() string {
 func (n *Node) SetVisible(state bool) {
 
 	n.visible = state
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // Visible returns the visibility of the node.
@@ -141,16 +141,16 @@ func (n *Node) Visible() bool {
 	return n.visible
 }
 
-// SetChanged sets the changed flag of the node.
+// SetChanged sets the matNeedsUpdate flag of the node.
 func (n *Node) SetChanged(changed bool) {
 
-	n.changed = changed
+	n.matNeedsUpdate = changed
 }
 
-// Changed returns the changed flag of the node.
+// Changed returns the matNeedsUpdate flag of the node.
 func (n *Node) Changed() bool {
 
-	return n.changed
+	return n.matNeedsUpdate
 }
 
 // SetUserData sets the generic user data associated to the node.
@@ -360,35 +360,35 @@ func (n *Node) DisposeChildren(recurs bool) {
 func (n *Node) SetPosition(x, y, z float32) {
 
 	n.position.Set(x, y, z)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetPositionVec sets the position based on the specified vector pointer.
 func (n *Node) SetPositionVec(vpos *math32.Vector3) {
 
 	n.position = *vpos
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetPositionX sets the X coordinate of the position.
 func (n *Node) SetPositionX(x float32) {
 
 	n.position.X = x
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetPositionY sets the Y coordinate of the position.
 func (n *Node) SetPositionY(y float32) {
 
 	n.position.Y = y
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetPositionZ sets the Z coordinate of the position.
 func (n *Node) SetPositionZ(z float32) {
 
 	n.position.Z = z
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // Position returns the position as a vector.
@@ -397,118 +397,127 @@ func (n *Node) Position() math32.Vector3 {
 	return n.position
 }
 
-// SetRotation sets the rotation in radians.
-// The stored quaternion is updated accordingly.
+// SetRotation sets the global rotation in Euler angles (radians).
 func (n *Node) SetRotation(x, y, z float32) {
 
 	n.rotation.Set(x, y, z)
 	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
-// SetRotationVec sets the rotation in radians based on the specified vector pointer.
-// The stored quaternion is updated accordingly.
+// SetRotationVec sets the global rotation in Euler angles (radians) based on the specified vector pointer.
 func (n *Node) SetRotationVec(vrot *math32.Vector3) {
 
 	n.rotation = *vrot
 	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
-// SetRotationQuat sets the rotation based on the specified quaternion pointer.
-// The stored quaternion is updated accordingly.
+// SetRotationQuat sets the global rotation based on the specified quaternion pointer.
 func (n *Node) SetRotationQuat(quat *math32.Quaternion) {
 
 	n.quaternion = *quat
-	n.changed = true
+	n.rotNeedsUpdate = true
 }
 
-// SetRotationX sets the X rotation to the specified angle in radians.
-// The stored quaternion is updated accordingly.
+// SetRotationX sets the global X rotation to the specified angle in radians.
 func (n *Node) SetRotationX(x float32) {
 
+	if n.rotNeedsUpdate {
+		n.rotation.SetFromQuaternion(&n.quaternion)
+		n.rotNeedsUpdate = false
+	}
 	n.rotation.X = x
 	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
-// SetRotationY sets the Y rotation to the specified angle in radians.
-// The stored quaternion is updated accordingly.
+// SetRotationY sets the global Y rotation to the specified angle in radians.
 func (n *Node) SetRotationY(y float32) {
 
+	if n.rotNeedsUpdate {
+		n.rotation.SetFromQuaternion(&n.quaternion)
+		n.rotNeedsUpdate = false
+	}
 	n.rotation.Y = y
 	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
-// SetRotationZ sets the Z rotation to the specified angle in radians.
-// The stored quaternion is updated accordingly.
+// SetRotationZ sets the global Z rotation to the specified angle in radians.
 func (n *Node) SetRotationZ(z float32) {
 
+	if n.rotNeedsUpdate {
+		n.rotation.SetFromQuaternion(&n.quaternion)
+		n.rotNeedsUpdate = false
+	}
 	n.rotation.Z = z
 	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
-// AddRotationX adds to the current X rotation the specified angle in radians.
-// The stored quaternion is updated accordingly.
-func (n *Node) AddRotationX(x float32) {
+// Rotation returns the current global rotation in Euler angles (radians).
+func (n *Node) Rotation() math32.Vector3 {
 
-	n.rotation.X += x
-	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	if n.rotNeedsUpdate {
+		n.rotation.SetFromQuaternion(&n.quaternion)
+		n.rotNeedsUpdate = false
+	}
+	return n.rotation
 }
 
-// AddRotationY adds to the current Y rotation the specified angle in radians.
-// The stored quaternion is updated accordingly.
-func (n *Node) AddRotationY(y float32) {
+// RotateOnAxis rotates around the specified local axis the specified angle in radians.
+func (n *Node) RotateOnAxis(axis *math32.Vector3, angle float32) {
 
-	n.rotation.Y += y
-	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	var rotQuat math32.Quaternion
+	rotQuat.SetFromAxisAngle(axis, angle)
+	n.QuaternionMult(&rotQuat)
 }
 
-// AddRotationZ adds to the current Z rotation the specified angle in radians.
-// The stored quaternion is updated accordingly.
-func (n *Node) AddRotationZ(z float32) {
+// RotateX rotates around the local X axis the specified angle in radians.
+func (n *Node) RotateX(x float32) {
 
-	n.rotation.Z += z
-	n.quaternion.SetFromEuler(&n.rotation)
-	n.changed = true
+	n.RotateOnAxis(&math32.Vector3{1,0,0}, x)
 }
 
-// Rotation returns the current rotation.
-func (n *Node) Rotation() math32.Vector3 {
+// RotateY rotates around the local Y axis the specified angle in radians.
+func (n *Node) RotateY(y float32) {
 
-	return n.rotation
+	n.RotateOnAxis(&math32.Vector3{0,1,0}, y)
+}
+
+// RotateZ rotates around the local Z axis the specified angle in radians.
+func (n *Node) RotateZ(z float32) {
+
+	n.RotateOnAxis(&math32.Vector3{0,0,1}, z)
 }
 
 // SetQuaternion sets the quaternion based on the specified quaternion unit multiples.
 func (n *Node) SetQuaternion(x, y, z, w float32) {
 
 	n.quaternion.Set(x, y, z, w)
-	n.changed = true
+	n.rotNeedsUpdate = true
 }
 
 // SetQuaternionVec sets the quaternion based on the specified quaternion unit multiples vector.
 func (n *Node) SetQuaternionVec(q *math32.Vector4) {
 
 	n.quaternion.Set(q.X, q.Y, q.Z, q.W)
-	n.changed = true
+	n.rotNeedsUpdate = true
 }
 
 // SetQuaternionQuat sets the quaternion based on the specified quaternion pointer.
 func (n *Node) SetQuaternionQuat(q *math32.Quaternion) {
 
 	n.quaternion = *q
-	n.changed = true
+	n.rotNeedsUpdate = true
 }
 
 // QuaternionMult multiplies the current quaternion by the specified quaternion.
 func (n *Node) QuaternionMult(q *math32.Quaternion) {
 
 	n.quaternion.Multiply(q)
-	n.changed = true
+	n.rotNeedsUpdate = true
 }
 
 // Quaternion returns the current quaternion.
@@ -521,35 +530,35 @@ func (n *Node) Quaternion() math32.Quaternion {
 func (n *Node) SetScale(x, y, z float32) {
 
 	n.scale.Set(x, y, z)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetScaleVec sets the scale based on the specified vector pointer.
 func (n *Node) SetScaleVec(scale *math32.Vector3) {
 
 	n.scale = *scale
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetScaleX sets the X scale.
 func (n *Node) SetScaleX(sx float32) {
 
 	n.scale.X = sx
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetScaleY sets the Y scale.
 func (n *Node) SetScaleY(sy float32) {
 
 	n.scale.Y = sy
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetScaleZ sets the Z scale.
 func (n *Node) SetScaleZ(sz float32) {
 
 	n.scale.Z = sz
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // Scale returns the current scale.
@@ -562,14 +571,14 @@ func (n *Node) Scale() math32.Vector3 {
 func (n *Node) SetDirection(x, y, z float32) {
 
 	n.direction.Set(x, y, z)
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // SetDirectionVec sets the direction based on a vector pointer.
 func (n *Node) SetDirectionVec(vdir *math32.Vector3) {
 
 	n.direction = *vdir
-	n.changed = true
+	n.matNeedsUpdate = true
 }
 
 // Direction returns the direction.
@@ -648,11 +657,11 @@ func (n *Node) MatrixWorld() math32.Matrix4 {
 // of this node based on its position, quaternion, and scale.
 func (n *Node) UpdateMatrix() bool {
 
-	if !n.changed {
+	if !n.matNeedsUpdate && !n.rotNeedsUpdate {
 		return false
 	}
 	n.matrix.Compose(&n.position, &n.quaternion, &n.scale)
-	n.changed = false
+	n.matNeedsUpdate = false
 	return true
 }