///// <summary> ///// Get model matrix. ///// </summary> ///// <param name="model"></param> ///// <returns></returns> //public static mat4 GetModelMatrix(this IWorldSpace model) //{ // mat4 matrix = glm.translate(mat4.identity(), model.WorldPosition); // matrix = glm.scale(matrix, model.Scale); // matrix = glm.rotate(matrix, model.RotationAngle, model.RotationAxis); // var node = model as RendererBase; // if (node != null) // { // var parent = node.Parent as RendererBase; // if (parent != null) // { // matrix = parent.modelMat * matrix; // } // node.modelMat = matrix; // } // return matrix; //} /// <summary> /// Rotate this model based on all previous rotation actions. /// Thus all rotations will take part in model's rotation result. /// <para>在目前的旋转状态下继续旋转一次,即所有的旋转操作都会(按照发生顺序)生效。</para> /// </summary> /// <param name="model"></param> /// <param name="angleDegree">Angle in Degree.</param> /// <param name="axis"></param> public static void Rotate(this IWorldSpace model, float angleDegree, vec3 axis) { mat4 currentRotationMatrix = glm.rotate(model.RotationAngle, model.RotationAxis); mat4 newRotationMatrix = glm.rotate(angleDegree, axis); mat4 latestRotationMatrix = newRotationMatrix * currentRotationMatrix; Quaternion quaternion = latestRotationMatrix.ToQuaternion(); float latestAngle; vec3 latestAxis; quaternion.Parse(out latestAngle, out latestAxis); model.RotationAngle = latestAngle; model.RotationAxis = latestAxis; }
void IMouseHandler.canvas_MouseMove(object sender, GLMouseEventArgs e) { if (mouseDownFlag && ((e.Button & this.lastBindingMouseButtons) != GLMouseButtons.None)) { if (!cameraState.IsSameState(this.camera)) { SetCamera(this.camera.Position, this.camera.Target, this.camera.UpVector); } this._endPosition = GetArcBallPosition(e.X, e.Y); var cosRadian = _startPosition.dot(_endPosition) / (_startPosition.length() * _endPosition.length()); if (cosRadian > 1.0f) { cosRadian = 1.0f; } else if (cosRadian < -1) { cosRadian = -1.0f; } float angle = MouseSensitivity * (float)(Math.Acos(cosRadian) / Math.PI * 180); _normalVector = _startPosition.cross(_endPosition).normalize(); if (! ((_normalVector.x == 0 && _normalVector.y == 0 && _normalVector.z == 0) || float.IsNaN(_normalVector.x) || float.IsNaN(_normalVector.y) || float.IsNaN(_normalVector.z))) { _startPosition = _endPosition; mat4 newRotation = glm.rotate(angle, _normalVector); this.totalRotation = newRotation * this.totalRotation; { var rotated = this.Rotated; if (rotated != null) { Quaternion quaternion = this.totalRotation.ToQuaternion(); float angleInDegree; vec3 axis; quaternion.Parse(out angleInDegree, out axis); rotated(this, new Rotation(axis, angleInDegree, e.Button, e.Clicks, e.X, e.Y, e.Delta)); } } } IGLCanvas canvas = this.canvas; if (canvas != null && canvas.RenderTrigger == RenderTrigger.Manual) { canvas.Repaint(); } } }
// https://blog.csdn.net/hunter_wwq/article/details/21473519 // https://blog.csdn.net/lql0716/article/details/72597719 /// <summary> /// Parse <paramref name="rotation"/>, <paramref name="scale"/> and <paramref name="worldPosition"/>(Translation) inside this matrix. /// <paramref name="rotation"/>.xyz is axis, <paramref name="rotation"/>.w is rotation angle in degrees. /// </summary> /// <param name="worldPosition"></param> /// <param name="scale"></param> /// <param name="rotation"></param> public void ParseRST(out vec3 worldPosition, out vec3 scale, out vec4 rotation) { worldPosition = new vec3(this.col3.x, this.col3.y, this.col3.z); float l0 = this.col0.length(); float l1 = this.col1.length(); float l2 = this.col2.length(); scale = new vec3(l0, l1, l2); vec3 col0 = new vec3(this.col0.x / l0, this.col0.y / l0, this.col0.z / l0); vec3 col1 = new vec3(this.col1.x / l1, this.col1.y / l1, this.col1.z / l1); vec3 col2 = new vec3(this.col2.x / l2, this.col2.y / l2, this.col2.z / l2); /* * col0 is vec3(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw)); * col1 is vec3(2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw)); * col2 is vec3(2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy)); */ float w, x, y, z; //+col0.x + col1.y + col2.z = 4ww - 1 w = (float)(Math.Sqrt(+col0.x + col1.y + col2.z + 1) / 2.0); //+col0.x - col1.y - col2.z = 4xx - 1 x = (float)(Math.Sqrt(+col0.x - col1.y - col2.z + 1) / 2.0); //-col0.x + col1.y - col2.z = 4yy - 1 y = (float)(Math.Sqrt(-col0.x + col1.y - col2.z + 1) / 2.0); //-col0.x - col1.y + col2.z = 4zz - 1 z = (float)(Math.Sqrt(-col0.x - col1.y + col2.z + 1) / 2.0); int maxIndex = GetMaxIndex(w, x, y, z); switch (maxIndex) { case 0: // based on w x = (col1.z - col2.y) * 0.25f / w; y = (col2.x - col0.z) * 0.25f / w; z = (col0.y - col1.x) * 0.25f / w; break; case 1: // based on x w = (col1.z - col2.y) * 0.25f / x; y = (col0.y + col1.x) * 0.25f / x; z = (col2.x + col0.z) * 0.25f / x; break; case 2: // based on y w = (col2.x - col0.z) * 0.25f / y; x = (col0.y + col1.x) * 0.25f / y; z = (col1.z + col2.y) * 0.25f / y; break; case 3: // based on z w = (col0.y - col1.x) * 0.25f / z; x = (col2.x + col0.z) * 0.25f / z; y = (col1.z + col2.y) * 0.25f / z; break; } // from quaternion to axis+angle. vec3 axis; float angle; var quaternion = new Quaternion(w, x, y, z); quaternion.Parse(out angle, out axis); rotation = new vec4(axis, angle); }