Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
TransformationComponent.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Collections.Specialized;
6 using SiliconStudio.Core.Serialization.Converters;
7 using SiliconStudio.Core.Serialization.Serializers;
8 using SiliconStudio.Paradox.Effects;
9 using SiliconStudio.Paradox.Engine;
10 using SiliconStudio.Paradox.EntityModel;
11 using SiliconStudio.Paradox.Games;
12 using SiliconStudio.Core;
13 using SiliconStudio.Core.Collections;
14 using SiliconStudio.Core.Mathematics;
15 
16 namespace SiliconStudio.Paradox.Engine
17 {
18  /// <summary>
19  /// Defines Position, Rotation and Scale of its <see cref="Entity"/>.
20  /// </summary>
21  [DataConverter(AutoGenerate = true)]
22  [DataContract("TransformationComponent")]
23  [DataSerializerGlobal(null, typeof(TrackingCollection<TransformationComponent>))]
25  {
27  new AccessorMetadata((ref PropertyContainer props) => ((Entity)props.Owner).Transformation, (ref PropertyContainer props, object value) => ((Entity)props.Owner).Transformation = (TransformationComponent)value));
28 
29  // When false, transformation should be computed in TransformationProcessor (no dependencies).
30  // When true, transformation is computed later by another system.
31  // This is useful for scenario such as binding a node to a bone, where it first need to run TransformationProcessor for the hierarchy,
32  // run MeshProcessor to update ModelViewHierarchy, copy Node/Bone transformation to another Entity with special root and then update its children transformations.
33  internal bool isSpecialRoot = false;
34  private bool useTRS = true;
35  private TransformationComponent parent;
36 
37  /// <summary>
38  /// The world matrix.
39  /// Use <see cref="UpdateWorldMatrix"/> to ensure it is updated.
40  /// </summary>
41  public Matrix WorldMatrix = Matrix.Identity;
42 
43  /// <summary>
44  /// The local matrix.
45  /// Use <see cref="UpdateLocalMatrix"/> to ensure it is updated.
46  /// </summary>
47  public Matrix LocalMatrix = Matrix.Identity;
48 
49  /// <summary>
50  /// The translation relative to the parent transformation.
51  /// </summary>
52  [DataMemberConvert]
54 
55  /// <summary>
56  /// The rotation relative to the parent transformation.
57  /// </summary>
58  [DataMemberConvert]
60 
61  /// <summary>
62  /// The scaling relative to the parent transformation.
63  /// </summary>
64  [DataMemberConvert]
65  public Vector3 Scaling;
66 
67  /// <summary>
68  /// Initializes a new instance of the <see cref="TransformationComponent" /> class.
69  /// </summary>
71  {
72  var children = new TrackingCollection<TransformationComponent>();
73  children.CollectionChanged += ChildrenCollectionChanged;
74 
75  Children = children;
76 
77  UseTRS = true;
78  Scaling = Vector3.One;
79  }
80 
81  [DataMemberConvert]
82  public bool UseTRS
83  {
84  get { return useTRS; }
85  set { useTRS = value; }
86  }
87 
88  /// <summary>
89  /// Gets the children of this <see cref="TransformationComponent"/>.
90  /// </summary>
91  /// <value>
92  /// The children.
93  /// </value>
94  [DataMemberConvert]
95  public FastCollection<TransformationComponent> Children { get; private set; }
96 
97  /// <summary>
98  /// Gets or sets the euler rotation, with XYZ order.
99  /// Not stable: setting value and getting it again might return different value as it is internally encoded as a <see cref="Quaternion"/> in <see cref="Rotation"/>.
100  /// </summary>
101  /// <value>
102  /// The euler rotation.
103  /// </value>
104  public Vector3 RotationEulerXYZ
105  {
106  get
107  {
108  var rotation = Rotation;
109  Vector3 rotationEuler;
110 
111  // Equivalent to:
112  // Matrix rotationMatrix;
113  // Matrix.Rotation(ref cachedRotation, out rotationMatrix);
114  // rotationMatrix.DecomposeXYZ(out rotationEuler);
115 
116  float xx = rotation.X * rotation.X;
117  float yy = rotation.Y * rotation.Y;
118  float zz = rotation.Z * rotation.Z;
119  float xy = rotation.X * rotation.Y;
120  float zw = rotation.Z * rotation.W;
121  float zx = rotation.Z * rotation.X;
122  float yw = rotation.Y * rotation.W;
123  float yz = rotation.Y * rotation.Z;
124  float xw = rotation.X * rotation.W;
125 
126  rotationEuler.Y = (float)Math.Asin(2.0f * (yw - zx));
127  double test = Math.Cos(rotationEuler.Y);
128  if (test > 1e-6f)
129  {
130  rotationEuler.Z = (float)Math.Atan2(2.0f * (xy + zw), 1.0f - (2.0f * (yy + zz)));
131  rotationEuler.X = (float)Math.Atan2(2.0f * (yz + xw), 1.0f - (2.0f * (yy + xx)));
132  }
133  else
134  {
135  rotationEuler.Z = (float)Math.Atan2(2.0f * (zw - xy), 2.0f * (zx + yw));
136  rotationEuler.X = 0.0f;
137  }
138  return rotationEuler;
139  }
140  set
141  {
142  // Equilvalent to:
143  // Quaternion quatX, quatY, quatZ;
144  //
145  // Quaternion.RotationX(value.X, out quatX);
146  // Quaternion.RotationY(value.Y, out quatY);
147  // Quaternion.RotationZ(value.Z, out quatZ);
148  //
149  // rotation = quatX * quatY * quatZ;
150 
151  var halfAngles = value * 0.5f;
152 
153  var fSinX = (float)Math.Sin(halfAngles.X);
154  var fCosX = (float)Math.Cos(halfAngles.X);
155  var fSinY = (float)Math.Sin(halfAngles.Y);
156  var fCosY = (float)Math.Cos(halfAngles.Y);
157  var fSinZ = (float)Math.Sin(halfAngles.Z);
158  var fCosZ = (float)Math.Cos(halfAngles.Z);
159 
160  var fCosXY = fCosX * fCosY;
161  var fSinXY = fSinX * fSinY;
162 
163  Rotation.X = fSinX * fCosY * fCosZ - fSinZ * fSinY * fCosX;
164  Rotation.Y = fSinY * fCosX * fCosZ + fSinZ * fSinX * fCosY;
165  Rotation.Z = fSinZ * fCosXY - fSinXY * fCosZ;
166  Rotation.W = fCosZ * fCosXY + fSinXY * fSinZ;
167  }
168  }
169 
170  /// <summary>
171  /// Gets or sets the parent of this <see cref="TransformationComponent"/>.
172  /// </summary>
173  /// <value>
174  /// The parent.
175  /// </value>
176  public TransformationComponent Parent
177  {
178  get { return parent; }
179  set
180  {
181  var oldParent = Parent;
182  if (oldParent == value)
183  return;
184 
185  if (oldParent != null)
186  oldParent.Children.Remove(this);
187  if (value != null)
188  value.Children.Add(this);
189  }
190  }
191 
192  /// <summary>
193  /// Updates the local matrix.
194  /// If <see cref="UseTRS"/> is true, <see cref="LocalMatrix"/> will be updated from <see cref="Translation"/>, <see cref="Rotation"/> and <see cref="Scaling"/>.
195  /// </summary>
196  public void UpdateLocalMatrix()
197  {
198  if (UseTRS)
199  {
200  CreateMatrixTRS(ref Translation, ref Rotation, ref Scaling, out LocalMatrix);
201  }
202  }
203 
204  /// <summary>
205  /// Updates the world matrix.
206  /// It will first call <see cref="UpdateLocalMatrix"/> on self, and <see cref="UpdateWorldMatrix"/> on <see cref="Parent"/> if not null.
207  /// Then <see cref="WorldMatrix"/> will be updated by multiplying <see cref="LocalMatrix"/> and parent <see cref="WorldMatrix"/> (if any).
208  /// </summary>
209  public void UpdateWorldMatrix()
210  {
211  UpdateLocalMatrix();
212 
213  if (Parent != null && !isSpecialRoot)
214  {
215  Parent.UpdateWorldMatrix();
216  Matrix.Multiply(ref LocalMatrix, ref Parent.WorldMatrix, out WorldMatrix);
217  }
218  else
219  {
220  WorldMatrix = LocalMatrix;
221  }
222  }
223 
224  internal void UpdateWorldMatrixNonRecursive()
225  {
226  if (Parent != null && !isSpecialRoot)
227  {
228  Matrix.Multiply(ref LocalMatrix, ref Parent.WorldMatrix, out WorldMatrix);
229  }
230  else
231  {
232  WorldMatrix = LocalMatrix;
233  }
234  }
235 
236  private void AddItem(TransformationComponent item)
237  {
238  if (item.Parent != null)
239  throw new InvalidOperationException("This TransformationComponent already has a Parent, detach it first.");
240 
241  item.parent = this;
242  }
243 
244  private void RemoveItem(TransformationComponent item)
245  {
246  if (item.Parent != this)
247  throw new InvalidOperationException("This TransformationComponent's parent is not the expected value.");
248 
249  item.parent = null;
250  }
251 
252  private void ChildrenCollectionChanged(object sender, TrackingCollectionChangedEventArgs e)
253  {
254  switch (e.Action)
255  {
256  case NotifyCollectionChangedAction.Add:
257  AddItem((TransformationComponent)e.Item);
258  break;
259  case NotifyCollectionChangedAction.Remove:
260  RemoveItem((TransformationComponent)e.Item);
261  break;
262  default:
263  throw new NotSupportedException();
264  }
265  }
266 
267  /// <summary>
268  /// Creates a matrix that contains both the X, Y and Z rotation, as well as scaling and translation.
269  /// </summary>
270  /// <param name="translation">The translation.</param>
271  /// <param name="rotation">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
272  /// <param name="scaling">The scaling.</param>
273  /// <param name="result">When the method completes, contains the created rotation matrix.</param>
274  public static void CreateMatrixTRS(ref Vector3 translation, ref Quaternion rotation, ref Vector3 scaling, out Matrix result)
275  {
276  // Equivalent to:
277  //result =
278  // Matrix.Scaling(scaling)
279  // *Matrix.RotationX(rotation.X)
280  // *Matrix.RotationY(rotation.Y)
281  // *Matrix.RotationZ(rotation.Z)
282  // *Matrix.Translation(translation);
283 
284  // Rotation
285  float xx = rotation.X * rotation.X;
286  float yy = rotation.Y * rotation.Y;
287  float zz = rotation.Z * rotation.Z;
288  float xy = rotation.X * rotation.Y;
289  float zw = rotation.Z * rotation.W;
290  float zx = rotation.Z * rotation.X;
291  float yw = rotation.Y * rotation.W;
292  float yz = rotation.Y * rotation.Z;
293  float xw = rotation.X * rotation.W;
294 
295  result.M11 = 1.0f - (2.0f * (yy + zz));
296  result.M12 = 2.0f * (xy + zw);
297  result.M13 = 2.0f * (zx - yw);
298  result.M21 = 2.0f * (xy - zw);
299  result.M22 = 1.0f - (2.0f * (zz + xx));
300  result.M23 = 2.0f * (yz + xw);
301  result.M31 = 2.0f * (zx + yw);
302  result.M32 = 2.0f * (yz - xw);
303  result.M33 = 1.0f - (2.0f * (yy + xx));
304 
305  // Translation
306  result.M41 = translation.X;
307  result.M42 = translation.Y;
308  result.M43 = translation.Z;
309 
310  // Scaling
311  if (scaling.X != 1.0f)
312  {
313  result.M11 *= scaling.X;
314  result.M12 *= scaling.X;
315  result.M13 *= scaling.X;
316  }
317  if (scaling.Y != 1.0f)
318  {
319  result.M21 *= scaling.Y;
320  result.M22 *= scaling.Y;
321  result.M23 *= scaling.Y;
322  }
323  if (scaling.Z != 1.0f)
324  {
325  result.M31 *= scaling.Z;
326  result.M32 *= scaling.Z;
327  result.M33 *= scaling.Z;
328  }
329 
330  result.M14 = 0.0f;
331  result.M24 = 0.0f;
332  result.M34 = 0.0f;
333  result.M44 = 1.0f;
334  }
335 
336  public override PropertyKey DefaultKey
337  {
338  get { return Key; }
339  }
340  }
341 }
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
Vector3 Translation
The translation relative to the parent transformation.
Defines Position, Rotation and Scale of its Entity.
TransformationComponent()
Initializes a new instance of the TransformationComponent class.
Represents a container that can hold properties, lightweight to embed (lazy initialized).
Base class for converters to/from a data type.
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
Vector3 Scaling
The scaling relative to the parent transformation.
Quaternion Rotation
The rotation relative to the parent transformation.
Represents a four dimensional mathematical quaternion.
Definition: Quaternion.cs:45
object Item
Gets the added or removed item (if dictionary, value only).
NotifyCollectionChangedAction Action
Gets the type of action performed. Allowed values are NotifyCollectionChangedAction.Add and NotifyCollectionChangedAction.Remove.
TransformationComponent Parent
Gets or sets the parent of this TransformationComponent.
static void CreateMatrixTRS(ref Vector3 translation, ref Quaternion rotation, ref Vector3 scaling, out Matrix result)
Creates a matrix that contains both the X, Y and Z rotation, as well as scaling and translation...
void UpdateLocalMatrix()
Updates the local matrix. If UseTRS is true, LocalMatrix will be updated from Translation, Rotation and Scaling.
A class that represents a tag propety.
Definition: PropertyKey.cs:17
void UpdateWorldMatrix()
Updates the world matrix. It will first call UpdateLocalMatrix on self, and UpdateWorldMatrix on Pare...
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47