public override void Update(ApplicationTime time) { IOxRenderPluginAvatar avatar = (IOxRenderPluginAvatar)Ox.Service.Get(typeof(IOxRenderPluginAvatar)); SceneNode sn = avatar.GetAvatarScneNode(Ox.DataStore.World.Agent.ID); if (sn == null || node == null) return; node.Target = sn.Position + Render.RenderData.AgentHeadPosition; Matrix4 rot = new Matrix4(); //rot.RotationDegrees = Util.ToRotationRH(new float[] { // 0, // 0, // (float)(Ox.DataStore.World.Agent.Head * NewMath.RADTODEG) + Util.ROTATION_AND_3DS_OFFSET.Z }); Quaternion q0 = new Quaternion(); Quaternion q1 = new Quaternion(); q0.fromAngleAxis(Ox.DataStore.Camera.Angle[0] + NewMath.DEGTORAD * Util.ROTATION_AND_3DS_OFFSET.Z, new Vector3D(0, 0, 1)); q1.fromAngleAxis(Ox.DataStore.Camera.Angle[1], new Vector3D(1, 0, 0)); q1 = q1 * q0; Vector3D vec = new Vector3D(0, -Ox.DataStore.Camera.Distance, 0); node.Position = node.Target + q1.Matrix.RotateVect(ref vec); if (Ox.DataStore.Camera.Angle[1] < -MathHelper.PIOver2 || MathHelper.PIOver2 < Ox.DataStore.Camera.Angle[1]) node.UpVector = new Vector3D(0, 0, -1); else node.UpVector = new Vector3D(0, 0, 1); base.Update(time); }
// Copy constructor (had to do this because we cannot overload operator "=" in C# public Quaternion(Quaternion other) { m_x = other.X; m_y = other.Y; m_z = other.Z; m_w = other.W; }
public override void Startup() { //Create a New Irrlicht Device //device.Timer.Stop(); Device.Timer.Speed = 1; Device.WindowCaption = "IdealistViewer 0.001"; // viewerRenderPlane.Device = Device; // viewerRenderPlane.Renderer = this; // Device.Resizeable = true; // Sets directory to load assets from Device.FileSystem.WorkingDirectory = m_viewer.StartupDirectory + "/" + Util.MakePath("media", "materials", "textures", ""); //We set Irrlicht's current directory to %application directory%/media Driver = Device.VideoDriver; SceneManager = Device.SceneManager; GuiEnvironment = Device.GUIEnvironment; // Compose Coordinate space converter quaternion IrrlichtNETCP.Matrix4 m4 = new IrrlichtNETCP.Matrix4(); m4.SetM(0, 0, 1); m4.SetM(1, 0, 0); m4.SetM(2, 0, 0); m4.SetM(3, 0, 0); m4.SetM(0, 1, 0); m4.SetM(1, 1, 0); m4.SetM(2, 1, 1); m4.SetM(3, 1, 0); m4.SetM(0, 2, 0); m4.SetM(1, 2, 1); m4.SetM(2, 2, 0); m4.SetM(3, 2, 0); m4.SetM(0, 3, 0); m4.SetM(1, 3, 0); m4.SetM(2, 3, 0); m4.SetM(3, 3, 1); CoordinateConversion_XYZ_XZY = new IrrlichtNETCP.Quaternion(m4); CoordinateConversion_XYZ_XZY.makeInverse(); }
public void UpdateDirection() { DateTime now = Reference.Viewer.WorldTime; TimeSpan span = new DateTime(2009, 1, 1, now.Hour, now.Minute, now.Second) - DateTime.Parse("2009-01-01 07:00:00"); int sec = span.Hours * 3600 + span.Minutes * 60 + span.Seconds; int end = 10 * 3600 + 0 * 60 + 0; float amount = (float)sec / end; amount = Util.Clamp<float>(amount, 0, 1); angle = OpenViewer.Util.Lerp(sunriseAngle, sunsetAngle, amount); qx.fromAngleAxis((float)(Math.PI / 1.25f), new Vector3D(1, 0, 0)); qy.fromAngleAxis(angle, new Vector3D(0, 1, 0)); qy = qx * qy; Vector3D rot; qy.toEuler(out rot); rotation = new Vector3D(rot.X, rot.Y, rot.Z) * OpenMetaverse.Utils.RAD_TO_DEG; }
private void ProcessObjectQueueUpdateToNode(VObject _obj) { // Little known fact. Dead avatar in LibOMV have the word 'dead' in their UUID // Skip over this one and move on to the next one if it's dead. if (((Avatar)_obj.Prim).ID.ToString().Contains("dead")) { return; } if (_obj.Node == null) { return; } //If we don't have an avatar representation yet for this avatar or it's a full update if (_obj.Requesting == false) { if ((_obj._3DiIrrfileUUID != _obj.RequestIrrfileUUID) && (_obj.RequestIrrfileUUID != UUID.Zero)) { if (Reference.Viewer.IrrManager.Contains(_obj.RequestIrrfileUUID) == false) { _obj.requestTexturesDirectlyFromAssetServerWithoutJ2KConversion = true; Reference.Viewer.IrrManager.RequestObject(_obj); Reference.Log.Debug("Request object: UUID:" + _obj.RequestIrrfileUUID.ToString()); } else { _obj._3DiIrrfileUUID = _obj.RequestIrrfileUUID; IrrDatas datas = Reference.Viewer.IrrManager.GetObject(_obj._3DiIrrfileUUID, true); if (datas != null) { // Set avatar mesh. lock (entities) { Reference.Viewer.EffectManager.RemoveGhostNode(_obj.Node); _obj.IsGhost = false; AnimatedMeshSceneNode animeNode = Reference.Viewer.IrrManager.IrrFileLoad(datas, Reference.SceneManager, _obj, "tmpmesh_" + _obj.Prim.LocalID.ToString() + "_"); if (animeNode != null) { animeNode.AnimationEnd += animeNode_AnimationEnd; animeNode.SetTransitionTime(0.1f); _obj.Mesh = animeNode.AnimatedMesh.GetMesh(0); SetAnimation(_obj, _obj.Prim.ParentID != 0 ? "sitstart" : "standing"); } } } Reference.Log.Debug("Loaded object: UUID:" + _obj.RequestIrrfileUUID.ToString()); } } } AnimationFrame(_obj, _obj.Prim.ParentID != 0); _obj.TargetPosition = new Vector3D(_obj.Prim.Position.X, _obj.Prim.Position.Z - 0.83f, _obj.Prim.Position.Y); _obj.Velocity = new Vector3D(_obj.Prim.Velocity.X, _obj.Prim.Velocity.Z, _obj.Prim.Velocity.Y); if (_obj.Prim.ID != userUUID) { // REVIEW NEEDED: a more general calculation //float roll, pitch, yaw; //_obj.Prim.Rotation.GetEulerAngles(out roll, out pitch, out yaw); //_obj.Node.Rotation = new Vector3D(Utils.ToDegrees(roll), Utils.ToDegrees(pi2 - pitch), Utils.ToDegrees(yaw)); Vector3 axis; float angle; _obj.Prim.Rotation.GetAxisAngle(out axis, out angle); _obj.Node.Rotation = new Vector3D(0, Utils.ToDegrees((axis.Z > 0 ? 1 : -1) * (pi2 - angle)), 0); } // If exsit parent prim, set parent. uint parentID = _obj.Prim.ParentID; if (parentID == 0) { _obj.ParentPosition = new Vector3(); if (_obj.IsChildAgent) { _obj.IsChildAgent = false; _obj.SmoothingReset = true; } } else { ulong regionID = Reference.Viewer.ProtocolManager.AvatarConnection.m_user.Network.CurrentSim.Handle; if (Reference.Viewer.EntityManager.Entities.ContainsKey(regionID.ToString() + parentID.ToString())) { VObject parentObj = Reference.Viewer.EntityManager.Entities[regionID.ToString() + parentID.ToString()]; if (parentObj != null) { _obj.ParentPosition = parentObj.Prim.Position; IrrlichtNETCP.Quaternion iquParent = new IrrlichtNETCP.Quaternion (parentObj.Prim.Rotation.X, parentObj.Prim.Rotation.Z, parentObj.Prim.Rotation.Y, parentObj.Prim.Rotation.W); iquParent.makeInverse(); IrrlichtNETCP.Quaternion iquAvatar = new IrrlichtNETCP.Quaternion (_obj.Prim.Rotation.X, _obj.Prim.Rotation.Z, _obj.Prim.Rotation.Y, _obj.Prim.Rotation.W); iquAvatar.makeInverse(); IrrlichtNETCP.Quaternion finalRotation = iquAvatar * iquParent; _obj.Node.Rotation = finalRotation.Matrix.RotationDegrees; _obj.TargetPosition = parentObj.Node.Position + _obj.TargetPosition * iquParent; } _obj.SmoothingReset = true; _obj.IsChildAgent = true; } else { UpdateObjectToPiplineEnqueue(_obj); } } _obj.SyncToChilds(); // If avatar's height position is minus, teleport to current sim center. if (_obj.Prim.ID == Reference.Viewer.ProtocolManager.AvatarConnection.GetSelfUUID && _obj.Prim.Position.Z < 0) Reference.Viewer.ProtocolManager.Teleport(Reference.Viewer.ProtocolManager.GetCurrentSimName(), 128, 128, 128); }
//! Interpolates the Quaternion between to Quaternions based on time public Quaternion Slerp(Quaternion q1, Quaternion q2, float time) { float angle = q1.GetDotProduct(q2); if (angle < 0.0f) { q1 *= -1.0f; angle *= -1.0f; } float scale; float invscale; if ((angle + 1.0f) > 0.05f) { if ((1.0f - angle) >= 0.05f) // spherical interpolation { float theta = (float)Math.Acos(angle); float invsintheta = 1.0f / (float)Math.Sin(theta); scale = (float)Math.Sin(theta * (1.0f - time)) * invsintheta; invscale = (float)Math.Sin(theta * time) * invsintheta; } else // linear interploation { scale = 1.0f - time; invscale = time; } } else { q2 = new Quaternion(-q1.Y, q1.X, -q1.W, q1.Z); scale = (float)Math.Sin(Math.PI * (0.5f - time)); invscale = (float)Math.Sin(Math.PI * time); } Quaternion t_tmp= (q1 * scale) + (q2 * invscale); this.m_x = t_tmp.X; this.m_y = t_tmp.Y; this.m_z = t_tmp.Z; this.m_w = t_tmp.W; return this; }
//! calculates the dot product public float GetDotProduct( Quaternion q2) { return (m_x * q2.X) + (m_y * q2.Y) + (m_z * q2.Z) + (m_w * q2.W); }
//! sets new Quaternion based on euler angles public static Quaternion FromEulerAngles(float x, float y, float z) { Quaternion t_tmp = new Quaternion(); //TODO Duplicated code (Method Set(x,y,z)) double angle; angle = x * 0.5; double sr = (float)Math.Sin(angle); double cr = (float)Math.Cos(angle); angle = y * 0.5; double sp = (float)Math.Sin(angle); double cp = (float)Math.Cos(angle); angle = z * 0.5; double sy = (float)Math.Sin(angle); double cy = (float)Math.Cos(angle); double cpcy = cp * cy; double spcy = sp * cy; double cpsy = cp * sy; double spsy = sp * sy; t_tmp.X = (float)(sr * cpcy - cr * spsy); t_tmp.Y = (float)(cr * spcy + sr * cpsy); t_tmp.Z = (float)(cr * cpsy - sr * spcy); t_tmp.W = (float)(cr * cpcy + sr * spsy); t_tmp.Normalize(); return t_tmp; }
//! multiplication by a quaternion operator public static Quaternion operator *(Quaternion lhs, Quaternion rhs) { Quaternion tmp=new Quaternion(); tmp.W = (rhs.W * lhs.W) - (rhs.X * lhs.X) - (rhs.Y * lhs.Y) - (rhs.Z * lhs.Z); tmp.X = (rhs.W * lhs.X) + (rhs.X * lhs.W) + (rhs.Y * lhs.Z) - (rhs.Z * lhs.Y); tmp.Y = (rhs.W * lhs.Y) + (rhs.Y * lhs.W) + (rhs.Z * lhs.X) - (rhs.X * lhs.Z); tmp.Z = (rhs.W * lhs.Z) + (rhs.Z * lhs.W) + (rhs.X * lhs.Y) - (rhs.Y * lhs.X); return tmp; }
/// <summary> /// Update camera position based on it's current PHI, Theta, and mouse offset. /// </summary> public void UpdateCameraPosition() { Vector3D newpos = new Vector3D(); Vector3D oldTarget = targetTarget; switch (CameraMode) { case ECameraMode.ThirdWithArbitraryOffset: case ECameraMode.Build: { newpos.X = oldTarget.X + (nowDistance * (float)Math.Cos(Reference.Viewer.CamRotationAngleTHETA + loMouseOffsetTHETA) * (float)Math.Sin(Reference.Viewer.CamRotationAnglePHI + loMouseOffsetPHI)); newpos.Y = oldTarget.Y + nowDistance * (float)Math.Cos(Reference.Viewer.CamRotationAnglePHI + loMouseOffsetPHI); newpos.Z = oldTarget.Z + nowDistance * (float)Math.Sin(Reference.Viewer.CamRotationAngleTHETA + loMouseOffsetTHETA) * (float)Math.Sin(Reference.Viewer.CamRotationAnglePHI + loMouseOffsetPHI); targetPosition = newpos; targetTarget = oldTarget; } break; case ECameraMode.Third: if (VOtarget != null) { // in 3rd person camera mode, default setting is 5 meter distance, 10 degree phi elevation, behind avatar. // the "behind" avatar part is tricky. we need to calculate the heading (theta) of the avatar in spherical // cam coordinates and use that theta to compute the final camera position. nowDistance = Reference.Viewer.CameraKeyWalkingDistance; Reference.Viewer.CamRotationAnglePHI = ((90.0f - 10.0f) / 180.0f) * (float)Math.PI; // 10 degree elevation. 0 deg=straight overhead // calculate avatar heading based on its prim's orientation. // this calculation here works, but is pretty confusing because of all the coordinate // system transformations going on. This code should be cleaned up to be more // understandable when there is time. In particular, we need to consider the coordinate // system of the world, the spherical camera coordinate system, and the avatar's orientation. OpenMetaverse.Quaternion primRot = VOtarget.Prim.Rotation; IrrlichtNETCP.Quaternion q = new IrrlichtNETCP.Quaternion(primRot.X, primRot.Y, primRot.Z, primRot.W); IrrlichtNETCP.Matrix4 avMatrix = q.Matrix; Vector3D heading = new Vector3D(avMatrix.GetM(1, 0), avMatrix.GetM(1, 1), avMatrix.GetM(1, 2)); heading.Y *= -1.0f; // convert avatar coords to IV cam spherical coords float headingAngle; // calculate heading (theta) in IV cam spherical coords if (Math.Abs(heading.X) > 0.0) { headingAngle = (float)Math.Atan((double)(heading.Y / heading.X)); if (heading.X < 0.0f) { headingAngle += (float)Math.PI; } if (headingAngle < 0.0) { headingAngle += 2.0f * (float)Math.PI; } } else { if (heading.Y > 0) { headingAngle = 0.5f * (float)Math.PI; // 90 deg } else { headingAngle = 1.5f * (float)Math.PI; // 270 deg } } //Console.WriteLine("avatar heading seems to be " + heading + " angle " + headingAngle * 360.0f / (2.0f*(float)Math.PI)); //Console.WriteLine("avatar matrix seems to be " + avMatrix); Reference.Viewer.CamRotationAngleTHETA = headingAngle - 0.5f * (float)Math.PI; // position camera behind avatar. This calculation is a little strange, but it works; no time to make it cleaner right now. { newpos.X = oldTarget.X + (nowDistance * (float)Math.Cos(Reference.Viewer.CamRotationAngleTHETA + loMouseOffsetTHETA) * (float)Math.Sin(Reference.Viewer.CamDefaultRotationAnglePHI + loMouseOffsetPHI)); newpos.Y = oldTarget.Y + nowDistance * (float)Math.Cos(Reference.Viewer.CamDefaultRotationAnglePHI + loMouseOffsetPHI); newpos.Z = oldTarget.Z + nowDistance * (float)Math.Sin(Reference.Viewer.CamRotationAngleTHETA + loMouseOffsetTHETA) * (float)Math.Sin(Reference.Viewer.CamDefaultRotationAnglePHI + loMouseOffsetPHI); targetPosition = newpos; targetTarget = oldTarget; } } break; } }