public void AddNewPolygonList(List<TransparentPolygonReference> p, Transform transform, Frustum frustum, Camera cam) { foreach (var pp in p) { var transformed = new Polygon(); transformed.Vertices.Resize(pp.Polygon.Vertices.Count, () => new Vertex()); transformed.Transform(pp.Polygon, transform); transformed.DoubleSide = pp.Polygon.DoubleSide; if(frustum.IsPolyVisible(transformed, cam)) { addPolygon(ref _root, new BSPFaceRef(transform, pp), transformed); } } }
public static void Mat4_Translate(Transform mat, float x, float y, float z) { Mat4_Translate(mat, new Vector3(x, y, z)); }
public void DrawListDebugLines() { if(World == null || !(drawBoxes || drawRoomBoxes || drawPortals || drawFrustums || drawAxis || drawNormals || drawColl)) { return; } if(World.Character != null) { DebugDrawer.DrawEntityDebugLines(World.Character, this); } // Render world debug information if(drawNormals && World.SkyBox != null) { var tr = new Transform(); tr.SetIdentity(); tr.Origin = Camera.Position + World.SkyBox.Animations[0].Frames[0].BoneTags[0].Offset; tr.Rotation = World.SkyBox.Animations[0].Frames[0].BoneTags[0].QRotate; DebugDrawer.DrawMeshDebugLines(World.SkyBox.MeshTree[0].MeshBase, tr, new List<Vector3>(), new List<Vector3>(), this); } foreach (var room in renderList) { DebugDrawer.DrawRoomDebugLines(room, this, Camera); } if(drawColl) { BtEngineDynamicsWorld.DebugDrawWorld(); } if(!DebugDrawer.IsEmpty) { var shader = ShaderManager.GetDebugLineShader(); GL.UseProgram(shader.Program); GL.Uniform1(shader.Sampler, 0); GL.UniformMatrix4(shader.ModelViewProjection, false, ref Camera.GLViewProjMat); GL.BindTexture(TextureTarget.Texture2D, EngineWorld.Textures.Last()); GL.PointSize(6.0f); GL.LineWidth(3.0f); DebugDrawer.Render(); } }
public void DrawMeshDebugLines(BaseMesh mesh, Transform transform, List<Vector3> overrideVertices, List<Vector3> overrideNormals, Render render) { if(render.drawNormals) { SetColor(0.8f, 0.0f, 0.9f); if(overrideVertices.Any()) { for (var i = 0; i < mesh.Vertices.Count; i++) { var ov = overrideVertices[i]; var on = overrideNormals[i]; var v = transform * ov; buffer.Add(v.ToArray()); buffer.Add(color); v += transform.Basis.MultiplyByVector(on) * 128; buffer.Add(v.ToArray()); buffer.Add(color); } } else { foreach (var mv in mesh.Vertices) { var v = transform * mv.Position; buffer.Add(v.ToArray()); buffer.Add(color); v += transform.Basis.MultiplyByVector(mv.Normal) * 128; buffer.Add(v.ToArray()); buffer.Add(color); } } } }
public void DrawAxis(float r, Transform transform) { var origin = transform.Origin.ToArray(); var v = transform.Basis.Column0 * r; v += transform.Origin; buffer.Add(origin); buffer.Add(new[] {1.0f, 0.0f, 0.0f}); buffer.Add(v.ToArray()); buffer.Add(new[] {1.0f, 0.0f, 0.0f}); v = transform.Basis.Column1 * r; v += transform.Origin; buffer.Add(origin); buffer.Add(new[] { 0.0f, 1.0f, 0.0f }); buffer.Add(v.ToArray()); buffer.Add(new[] { 0.0f, 1.0f, 0.0f }); v = transform.Basis.Column2 * r; v += transform.Origin; buffer.Add(origin); buffer.Add(new[] { 0.0f, 0.0f, 1.0f }); buffer.Add(v.ToArray()); buffer.Add(new[] { 0.0f, 0.0f, 1.0f }); }
public void RenderHair(Character entity, Matrix4 modelViewMatrix, Matrix4 projection) { if (entity == null || entity.Hairs.Count == 0) return; // Calculate lighting var shader = setupEntityLight(entity, modelViewMatrix, true); for (var h = 0; h < entity.Hairs.Count; h++) { // First: Head attachment var globalHead = (Matrix4)(entity.Transform * entity.Bf.BoneTags[(int)entity.Hairs[h].OwnerBody].FullTransform); var globalAttachment = globalHead.MultiplyByTransform(entity.Hairs[h].OwnerBodyHairRoot); var matrixCount = 10; var hairModelToGlobalMatrices = Helper.RepeatValue(16, () => new float[matrixCount]); unsafe { var tmp = modelViewMatrix * globalAttachment; fixed (float* ptr = &hairModelToGlobalMatrices[0][0]) Helper.PointerCopy(&tmp.Row0.X, ptr, 16); } // Then: Individual hair pieces for (var i = 0; i < entity.Hairs[h].Elements.Count; i++) { StaticFuncs.Assert(i + 1 < matrixCount); /* * Definitions: x_o - as in original file. x_h - as in hair model * (translated) * M_ho - translation matrix. x_g = global position (before modelview) * M_go - global position * * We know: * x_h = M_ho * x_o * x_g = M_go * x_o * We want: * M_hg so that x_g = M_gh * x_m * We have: M_oh, M_g * * x_h = M_ho * x_o => x_o = M_oh^-1 * x_h * x_g = M_go * M_ho^-1 * x_h * (M_ho^-1 = M_oh so x_g = M_go * M_oh * x_h) */ var invOriginToHairModel = new Transform(); invOriginToHairModel.SetIdentity(); // Simplification: Always translation matrix, no invert needed invOriginToHairModel.Origin -= entity.Hairs[h].Elements[i].Position; var globalFromHair = entity.Hairs[h].Elements[i].Body.GetWorldTransform().MultiplyByTransform(invOriginToHairModel); unsafe { var tmp = modelViewMatrix * globalFromHair; fixed (float* ptr = &hairModelToGlobalMatrices[i + 1][0]) Helper.PointerCopy(&tmp.Row0.X, ptr, 16); } } unsafe { fixed (float* ptr = &hairModelToGlobalMatrices[0][0]) GL.UniformMatrix4(shader.ModelView, entity.Hairs[h].Elements.Count + 1, false, ptr); } GL.UniformMatrix4(shader.Projection, false, ref projection); RenderMesh(entity.Hairs[h].Mesh); } }
public void Draw() { if (!active) return; var item = EngineWorld.GetBaseItemByID((uint)this.item); if (item == null) return; var anim = item.BoneFrame.Animations.CurrentAnimation; var frame = item.BoneFrame.Animations.CurrentFrame; var time = item.BoneFrame.Animations.FrameTime; item.BoneFrame.Animations.CurrentAnimation = 0; item.BoneFrame.Animations.CurrentFrame = 0; item.BoneFrame.Animations.FrameTime = 0.0f; Gui.Item_Frame(item.BoneFrame, 0.0f); var matrix = new Transform(); matrix.SetIdentity(); VMath.Mat4_Translate(matrix, currPosX, posY, -2048.0f); VMath.Mat4_RotateY(matrix, currRotX + rotX); VMath.Mat4_RotateX(matrix, currRotY + rotY); Gui.RenderItem(item.BoneFrame, size, matrix); item.BoneFrame.Animations.CurrentAnimation = anim; item.BoneFrame.Animations.CurrentFrame = frame; item.BoneFrame.Animations.FrameTime = time; }
/// <summary> /// Creates hair into allocated hair structure, using previously defined setup and entity index. /// </summary> public bool Create(HairSetup setup, Entity parentEntity) { // No setup or parent to link to - bypass function. if (parentEntity == null || setup == null || setup.LinkBody >= parentEntity.Bf.BoneTags.Count || parentEntity.Bt.BtBody[(int)setup.LinkBody] == null) return false; var model = EngineWorld.GetModelByID(setup.Model); // No model to link to - bypass function. if (model == null || model.MeshCount == 0) return false; // Setup engine container. FIXME: DOESN'T WORK PROPERLY ATM. Container = new EngineContainer(); Container.Room = parentEntity.Self.Room; Container.ObjectType = OBJECT_TYPE.Hair; Container.Object = this; // Setup initial hair parameters. OwnerChar = parentEntity; // Entity to refer to. OwnerBody = setup.LinkBody; // Entity body to refer to. // Setup initial position / angles. var ownerBodyTransform = parentEntity.Transform * parentEntity.Bf.BoneTags[(int) OwnerBody].FullTransform; // Number of elements (bodies) is equal to number of hair meshes. Elements = new List<HairElement>(); Elements.Resize(model.MeshCount, () => new HairElement()); // Root index should be always zero, as it is how engine determines that it is // connected to head and renders it properly. Tail index should be always the // last element of the hair, as it indicates absence of "child" constraint. RootIndex = 0; TailIndex = (byte)(Elements.Count - 1); // Weight step is needed to determine the weight of each hair body. // It is derived from root body weight and tail body weight. var weightStep = (setup.RootWeight - setup.TailWeight) / Elements.Count; var currentWeight = setup.RootWeight; for (var i = 0; i < Elements.Count; i++) { // Point to corresponding mesh. Elements[i].Mesh = model.MeshTree[i].MeshBase; // Begin creating ACTUAL physical hair mesh. var localInertia = BulletSharp.Math.Vector3.Zero; // Make collision shape out of mesh. Elements[i].Shape = BT_CSfromMesh(Elements[i].Mesh, true, true, false); Elements[i].Shape.CalculateLocalInertia(currentWeight * setup.HairInertia, out localInertia); // Decrease next body weight to weight_step parameter. currentWeight -= weightStep; // Initialize motion state for body. var startTransform = ownerBodyTransform; var motionState = new DefaultMotionState(((Matrix4)startTransform).ToBullet()); // Make rigid body. Elements[i].Body = new RigidBody(new RigidBodyConstructionInfo(currentWeight, motionState, Elements[i].Shape, localInertia)); // Damping makes body stop in space by itself, to prevent it from continous movement. Elements[i].Body.SetDamping(setup.HairDamping[0], setup.HairDamping[1]); // Restitution and friction parameters define "bounciness" and "dullness" of hair. Elements[i].Body.Restitution = setup.HairRestitution; Elements[i].Body.Friction = setup.HairFriction; // Since hair is always moving with Lara, even if she's in still state (like, hanging // on a ledge), hair bodies shouldn't deactivate over time. Elements[i].Body.ForceActivationState(ActivationState.DisableDeactivation); // Hair bodies must not collide with each other, and also collide ONLY with kinematic // bodies (e. g. animated meshes), or else Lara's ghost object or anything else will be able to // collide with hair! Elements[i].Body.UserObject = Container; BtEngineDynamicsWorld.AddRigidBody(Elements[i].Body, CollisionFilterGroups.CharacterFilter, CollisionFilterGroups.KinematicFilter); Elements[i].Body.Activate(); } // GENERATE CONSTRAINTS. // All constraints are generic 6-DOF type, as they seem perfect fit for hair. // Joint count is calculated from overall body amount multiplied by per-body constraint // count. Joints = new List<Generic6DofConstraint>(); Joints.Resize(Elements.Count); // If multiple joints per body is specified, joints are placed in circular manner, // with obvious step of (SIMD_2_PI) / joint count. It means that all joints will form // circle-like figure. var currJoint = 0; for (var i = 0; i < Elements.Count; i++) { float bodyLength; var localA = new Transform(); localA.SetIdentity(); var localB = new Transform(); localB.SetIdentity(); var jointX = 0.0f; var jointY = 0.0f; RigidBody prevBody; if(i == 0) // First joint group { // Adjust pivot point A to parent body. localA.Origin = setup.HeadOffset + new Vector3(jointX, 0.0f, jointY); Helper.SetEulerZYX(ref localA.Basis, setup.RootAngle.X, setup.RootAngle.Y, setup.RootAngle.Z); // Stealing this calculation because I need it for drawing OwnerBodyHairRoot = localA; localB.Origin = new Vector3(jointX, 0.0f, jointY); Helper.SetEulerZYX(ref localB.Basis, 0, -HalfPI, 0); prevBody = parentEntity.Bt.BtBody[(int) OwnerBody]; // Previous body is parent body. } else { // Adjust pivot point A to previous mesh's length, considering mesh overlap multiplier. bodyLength = Math.Abs(Elements[i - 1].Mesh.BBMax.Y - Elements[i - 1].Mesh.BBMin.Y) * setup.JointOverlap; localA.Origin = new Vector3(jointX, bodyLength, jointY); Helper.SetEulerZYX(ref localA.Basis, 0, -HalfPI, 0); // Pivot point B is automatically adjusted by Bullet. localB.Origin = new Vector3(jointX, 0.0f, jointY); Helper.SetEulerZYX(ref localB.Basis, 0, -HalfPI, 0); prevBody = Elements[i - 1].Body; // Previous body is preceding hair mesh. } // Create 6DOF constraint. Joints[currJoint] = new Generic6DofConstraint(prevBody, Elements[i].Body, ((Matrix4) localA).ToBullet(), ((Matrix4) localB).ToBullet(), true); // CFM and ERP parameters are critical for making joint "hard" and link // to Lara's head. With wrong values, constraints may become "elastic". for (var axis = 0; axis < 6; axis++) { Joints[currJoint].SetParam(ConstraintParam.StopCfm, setup.JointCfm, axis); Joints[currJoint].SetParam(ConstraintParam.StopErp, setup.JointErp, axis); } Joints[currJoint].LinearLowerLimit = BulletSharp.Math.Vector3.Zero; Joints[currJoint].LinearUpperLimit = BulletSharp.Math.Vector3.Zero; if(i == 0) { // First joint group should be more limited in motion, as it is connected // right to the head. NB: Should we make it scriptable as well? Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(-HalfPI, 0.0f, -HalfPI * 0.4f); Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(-HalfPI * 0.3f, 0.0f, HalfPI * 0.4f); // Increased solver iterations make constraint even more stable. Joints[currJoint].OverrideNumSolverIterations = 100; } else { // Normal joint with more movement freedom. Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(-HalfPI * 0.5f, 0.0f, -HalfPI * 0.5f); Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(HalfPI * 0.5f, 0.0f, HalfPI * 0.5f); } Joints[currJoint].DebugDrawSize = 5.0f; // Draw constraint axes. // Add constraint to the world. BtEngineDynamicsWorld.AddConstraint(Joints[currJoint], true); currJoint++; // Point to the next joint. } createHairMesh(model); return true; }
public void UpdateRigidBody(bool force) { if(TypeFlags.HasFlag(ENTITY_TYPE.Dynamic)) { Transform = (Transform)Bt.BtBody[0].WorldTransform.ToOpenTK(); UpdateRoomPos(); for(var i = 0; i < Bf.BoneTags.Count; i++) { Bf.BoneTags[i].FullTransform = Transform.Inverse * Bt.BtBody[i].WorldTransform.ToOpenTK(); } // that cycle is necessary only for skinning models foreach (var t in Bf.BoneTags) { t.Transform = t.Parent != null ? t.Parent.FullTransform.Inverse * t.FullTransform : t.FullTransform; } UpdateGhostRigidBody(); Bf.BBMin = Bf.BoneTags[0].MeshBase.BBMin; Bf.BBMax = Bf.BoneTags[0].MeshBase.BBMax; if(Bf.BoneTags.Count > 1) { foreach (var b in Bf.BoneTags) { var pos = b.FullTransform.Origin; var bbmin = b.MeshBase.BBMin; var bbmax = b.MeshBase.BBMax; var r = bbmax.X - bbmin.X; var t = bbmax.Y - bbmin.Y; r = Math.Max(t, r); t = bbmax.Z - bbmin.Z; r = Math.Max(t, r); r *= 0.5f; Bf.BBMin = Helper.Vec3Min(Bf.BBMin, pos.AddF(-r)); Bf.BBMax = Helper.Vec3Max(Bf.BBMax, pos.AddF(r)); } } } else { if (Bf.Animations.Model == null || Bt.BtBody.Count == 0 || !force && Bf.Animations.Model.Animations.Count == 1 && Bf.Animations.Model.Animations[0].Frames.Count == 1) { return; } UpdateRoomPos(); if(Self.CollisionType != COLLISION_TYPE.Static) { for(var i = 0; i < Bf.BoneTags.Count; i++) { if(Bt.BtBody[i] != null) { Bt.BtBody[i].WorldTransform = ((Matrix4)(Transform * Bf.BoneTags[i].FullTransform)).ToBullet(); } } } } RebuildBV(); }
public Entity(uint id) { ID = id; MoveType = MoveType.OnFloor; Self = new EngineContainer(); Transform = new Transform(); Transform.SetIdentity(); Self.Object = this; Self.ObjectType = OBJECT_TYPE.Entity; Self.Room = null; Self.CollisionType = COLLISION_TYPE.None; OBB = new OBB(); OBB.Transform = Transform; Bt = new BtEntityData(); Bt.BtBody = new List<RigidBody>(); Bt.BtJoints = new List<TypedConstraint>(); Bt.NoFixAll = false; Bt.NoFixBodyParts = 0x0000000; Bt.ManifoldArray = null; Bt.Shapes = new List<CollisionShape>(); Bt.GhostObjects = new List<PairCachingGhostObject>(); Bt.LastCollisions = new List<EntityCollisionNode>(); Bf = new SSBoneFrame(); Bf.Animations = new SSAnimation(); Bf.Animations.Model = null; Bf.Animations.ClearOnFrame(); Bf.Animations.FrameTime = 0.0f; Bf.Animations.LastState = TR_STATE.LaraWalkForward; Bf.Animations.NextState = TR_STATE.LaraWalkForward; Bf.Animations.Lerp = 0.0f; Bf.Animations.CurrentAnimation = TR_ANIMATION.LaraRun; Bf.Animations.CurrentFrame = 0; Bf.Animations.NextAnimation = TR_ANIMATION.LaraRun; Bf.Animations.NextFrame = 0; Bf.Animations.Next = null; Bf.BoneTags = new List<SSBoneTag>(); Bf.BBMax = Vector3.Zero; Bf.BBMin = Vector3.Zero; Bf.Centre = Vector3.Zero; Bf.Position = Vector3.Zero; Speed = Vector3.Zero; }
public bool CreateRagdoll(RDSetup setup) { // No entity, setup or body count overflow - bypass function. if (setup == null || setup.BodySetup.Count > Bf.BoneTags.Count) { return false; } var result = true; // If ragdoll already exists, overwrite it with new one. if (Bt.BtJoints.Count > 0) { result = DeleteRagdoll(); } // Setup bodies. Bt.BtJoints.Clear(); // update current character animation and full fix body to avoid starting ragdoll partially inside the wall or floor... UpdateCurrentBoneFrame(Bf, Transform); Bt.NoFixAll = false; Bt.NoFixBodyParts = 0x00000000; #if NOPE int map_size = m_bf.animations.model->collision_map.size(); // does not works, strange... m_bf.animations.model->collision_map.size() = m_bf.animations.model->mesh_count; fixPenetrations(nullptr); m_bf.animations.model->collision_map.size() = map_size; #else FixPenetrations(Vector3.Zero); #endif for(var i = 0; i < setup.BodySetup.Count; i++) { // TODO: First check useless? if(i >= Bf.BoneTags.Count || Bt.BtBody[i] == null) { result = false; continue; // If body is absent, return false and bypass this body setup. } var inertia = BulletSharp.Math.Vector3.Zero; var mass = setup.BodySetup[i].Mass; BtEngineDynamicsWorld.RemoveRigidBody(Bt.BtBody[i]); Bt.BtBody[i].CollisionShape.CalculateLocalInertia(mass, out inertia); Bt.BtBody[i].SetMassProps(mass, inertia); Bt.BtBody[i].UpdateInertiaTensor(); Bt.BtBody[i].ClearForces(); Bt.BtBody[i].LinearFactor = BulletSharp.Math.Vector3.One; Bt.BtBody[i].AngularFactor = BulletSharp.Math.Vector3.One; Bt.BtBody[i].SetDamping(setup.BodySetup[i].Damping[0], setup.BodySetup[i].Damping[1]); Bt.BtBody[i].Restitution = setup.BodySetup[i].Restitution; Bt.BtBody[i].Friction = setup.BodySetup[i].Friction; Bt.BtBody[i].SetSleepingThresholds(RD_DEFAULT_SLEEPING_THRESHOLD, RD_DEFAULT_SLEEPING_THRESHOLD); if(Bf.BoneTags[i].Parent == null) { var r = GetInnerBBRadius(Bf.BoneTags[i].MeshBase.BBMin, Bf.BoneTags[i].MeshBase.BBMax); Bt.BtBody[i].CcdMotionThreshold = 0.8f * r; Bt.BtBody[i].CcdSweptSphereRadius = r; } } UpdateRigidBody(true); for(var i = 0; i < Bf.BoneTags.Count; i++) { BtEngineDynamicsWorld.AddRigidBody(Bt.BtBody[i]); Bt.BtBody[i].Activate(); Bt.BtBody[i].LinearVelocity = Speed.ToBullet(); if (i < Bt.GhostObjects.Count && Bt.GhostObjects[i] != null) { BtEngineDynamicsWorld.RemoveCollisionObject(Bt.GhostObjects[i]); BtEngineDynamicsWorld.AddCollisionObject(Bt.GhostObjects[i], CollisionFilterGroups.None, CollisionFilterGroups.None); } } // Setup constraints. Bt.BtJoints.Resize(setup.JointSetup.Count); for(var i = 0; i < setup.JointSetup.Count; i++) { if(setup.JointSetup[i].BodyIndex >= Bf.BoneTags.Count || Bt.BtBody[setup.JointSetup[i].BodyIndex] == null) { result = false; break; // If body 1 or body 2 are absent, return false and bypass this joint. } var localA = new Transform(); var localB = new Transform(); var btB = Bf.BoneTags[setup.JointSetup[i].BodyIndex]; var btA = btB.Parent; if(btA == null) { result = false; break; } #if NOPE localA.setFromOpenGLMatrix(btB->transform); localB.setIdentity(); #else Helper.SetEulerZYX(ref localA.Basis, setup.JointSetup[i].Body1Angle); //localA.Origin = setup.JointSetup[i].Body1Offset; localA.Origin = btB.Transform.Origin; Helper.SetEulerZYX(ref localB.Basis, setup.JointSetup[i].Body2Angle); //localB.Origin = setup.JointSetup[i].Body2Offset; localB.Origin = Vector3.Zero; #endif switch(setup.JointSetup[i].JointType) { case RDJointSetup.Type.Point: Bt.BtJoints[i] = new Point2PointConstraint(Bt.BtBody[btA.Index], Bt.BtBody[btB.Index], localA.Origin.ToBullet(), localB.Origin.ToBullet()); break; case RDJointSetup.Type.Hinge: var hingeC = new HingeConstraint(Bt.BtBody[btA.Index], Bt.BtBody[btB.Index], ((Matrix4) localA).ToBullet(), ((Matrix4) localB).ToBullet()); hingeC.SetLimit(setup.JointSetup[i].JointLimit[0], setup.JointSetup[i].JointLimit[1], 0.9f, 0.3f, 0.3f); Bt.BtJoints[i] = hingeC; break; case RDJointSetup.Type.Cone: var coneC = new ConeTwistConstraint(Bt.BtBody[btA.Index], Bt.BtBody[btB.Index], ((Matrix4)localA).ToBullet(), ((Matrix4)localB).ToBullet()); coneC.SetLimit(setup.JointSetup[i].JointLimit[0], setup.JointSetup[i].JointLimit[1], setup.JointSetup[i].JointLimit[2], 0.9f, 0.3f, 0.7f); Bt.BtJoints[i] = coneC; break; } Bt.BtJoints[i].SetParam(ConstraintParam.StopCfm, setup.JointCfm, -1); Bt.BtJoints[i].SetParam(ConstraintParam.StopErp, setup.JointErp, -1); Bt.BtJoints[i].DebugDrawSize = 64.0f; BtEngineDynamicsWorld.AddConstraint(Bt.BtJoints[i], true); } if(!result) { DeleteRagdoll(); // PARANOID: Clean up the mess, if something went wrong. } else { TypeFlags |= ENTITY_TYPE.Dynamic; } return result; }
public static void UpdateCurrentBoneFrame(SSBoneFrame bf, Transform etr) { var btag = bf.BoneTags[0]; var model = bf.Animations.Model; var nextBf = model.Animations[(int) bf.Animations.NextAnimation].Frames[bf.Animations.NextFrame]; var currBf = model.Animations[(int) bf.Animations.CurrentAnimation].Frames[bf.Animations.CurrentFrame]; var tr = Vector3.Zero; var cmd_tr = Vector3.Zero; if (etr != null && currBf.Command.HasFlagUns(ANIM_CMD.Move)) { tr = etr.Basis.MultiplyByVector(currBf.Move); cmd_tr = tr * bf.Animations.Lerp; } bf.BBMax = currBf.BBMax.Lerp(nextBf.BBMax, bf.Animations.Lerp) + cmd_tr; bf.BBMin = currBf.BBMin.Lerp(nextBf.BBMin, bf.Animations.Lerp) + cmd_tr; bf.Centre = currBf.Centre.Lerp(nextBf.Centre, bf.Animations.Lerp) + cmd_tr; bf.Position = currBf.Position.Lerp(nextBf.Position, bf.Animations.Lerp) + cmd_tr; var next_btag = nextBf.BoneTags[0]; var src_btag = currBf.BoneTags[0]; for (var k = 0; k < currBf.BoneTags.Count;) { btag.Offset = src_btag.Offset.Lerp(next_btag.Offset, bf.Animations.Lerp); btag.Transform.Origin = btag.Offset; btag.Transform.Origin.Z = 1.0f; if(k == 0) { btag.Transform.Origin += bf.Position; btag.QRotate = Quaternion.Slerp(src_btag.QRotate, next_btag.QRotate, bf.Animations.Lerp); } else { var ov_src_btag = src_btag; var ov_next_btag = next_btag; var ov_lerp = bf.Animations.Lerp; for (var ov_anim = bf.Animations.Next; ov_anim != null; ov_anim = ov_anim.Next) { if (ov_anim.Model != null && ov_anim.Model.MeshTree[k].ReplaceAnim != 0) { var ov_curr_bf = ov_anim.Model.Animations[(int) ov_anim.CurrentAnimation].Frames[ov_anim.CurrentFrame]; var ov_next_bf = ov_anim.Model.Animations[(int) ov_anim.NextAnimation].Frames[ov_anim.NextFrame]; ov_src_btag = ov_curr_bf.BoneTags[k]; ov_next_btag = ov_next_bf.BoneTags[k]; ov_lerp = ov_anim.Lerp; break; } } btag.QRotate = Quaternion.Slerp(ov_src_btag.QRotate, ov_next_btag.QRotate, ov_lerp); } btag.Transform.Rotation = btag.QRotate; k++; if (k < bf.BoneTags.Count) { btag = bf.BoneTags[k]; src_btag = currBf.BoneTags[k]; next_btag = nextBf.BoneTags[k]; } } // build absolute coordinate matrix system var btagI = 0; btag = bf.BoneTags[btagI]; btag.FullTransform = btag.Transform; var incBtag = new Action(() => { btagI++; btag = btagI < bf.BoneTags.Count ? bf.BoneTags[btagI] : null; }); for(var k = 1; k < currBf.BoneTags.Count; k++, incBtag()) { btag.FullTransform = (btag.Parent?.FullTransform ?? new Transform()) * btag.Transform; } }
public static void Mat4_Translate(Transform mat, Vector3 v) { mat.Origin += mat.Basis.MultiplyByVector(v); }
public static void Mat4_RotateZ(Transform mat, float ang) { var tmp = ang * RadPerDeg; var sina = (float)Math.Sin(tmp); var cosa = (float)Math.Cos(tmp); var m = Matrix3.Transpose(mat.Basis); m.Row0 = mat.Basis.Column0 * cosa + mat.Basis.Column1 * sina; m.Row1 = -mat.Basis.Column0 * sina + mat.Basis.Column1 * cosa; mat.Basis = Matrix3.Transpose(m); }
public static void Mat4_Scale(Transform mat, float x, float y, float z) { mat.Basis = mat.Basis.Scaled(new Vector3(x, y, z)); }
public ClimbInfo CheckClimbability(Vector3 offset, HeightInfo nfc, float testHeight) { Vector3 from, to; float d; var pos = Transform.Origin; var t1 = new Transform(); var t2 = new Transform(); byte upFounded; var castRay = new float[6]; // init callbacks functions nfc.Cb = RayCb; nfc.Ccb = ConvexCb; var tmp = pos + offset; var ret = new ClimbInfo(); ret.HeightInfo = CheckNextStep(offset + new Vector3(0, 0, 128), nfc); ret.CanHang = false; ret.EdgeHit = false; ret.EdgeObject = null; ret.FloorLimit = HeightInfo.FloorHit ? HeightInfo.FloorPoint.Z : -9e10f; ret.CeilingLimit = HeightInfo.CeilingHit ? HeightInfo.CeilingPoint.Z : 9e10f; if (nfc.CeilingHit && nfc.CeilingPoint.Z < ret.CeilingLimit) { ret.CeilingLimit = nfc.CeilingPoint.Z; } ret.Point = Climb.Point; // check max height if (HeightInfo.CeilingHit && tmp.Z > HeightInfo.CeilingPoint.Z - ClimbR - 1.0f) { tmp.Z = HeightInfo.CeilingPoint.Z - ClimbR - 1.0f; } // let's calculate edge from.X = pos.X - Transform.Basis.Column1.X * ClimbR * 2.0f; from.Y = pos.Y - Transform.Basis.Column1.Y * ClimbR * 2.0f; from.Z = pos.Z; to = tmp; t1.SetIdentity(); t2.SetIdentity(); upFounded = 0; testHeight = Math.Max(testHeight, MaxStepUpHeight); d = pos.Z + Bf.BBMax.Z - testHeight; to.CopyToArray(castRay, 0); to.CopyToArray(castRay, 3); castRay[5] -= d; var n0 = Vector3.Zero; var n1 = Vector3.Zero; var n0d = 0.0f; var n1d = 0.0f; do { t1.Origin = from; t2.Origin = to; nfc.Ccb.ClosestHitFraction = 1.0f; nfc.Ccb.HitCollisionObject = null; BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) t1).ToBullet(), ((Matrix4) t2).ToBullet(), nfc.Ccb); if (nfc.Ccb.HasHit) { if (nfc.Ccb.HitNormalWorld.Z >= 0.1f) { upFounded = 1; n0 = nfc.Ccb.HitNormalWorld.ToOpenTK(); n0d = -n0.Dot(nfc.Ccb.HitPointWorld.ToOpenTK()); } if (upFounded != 0 && nfc.Ccb.HitNormalWorld.Z < 0.001f) { n1 = nfc.Ccb.HitNormalWorld.ToOpenTK(); n1d = -n1.Dot(nfc.Ccb.HitPointWorld.ToOpenTK()); Climb.EdgeObject = nfc.Ccb.HitCollisionObject; upFounded = 2; break; } } else { tmp.X = to.X; tmp.Y = to.Y; tmp.Z = d; t1.Origin = to; t2.Origin = tmp; t1.Origin = from; t2.Origin = to; nfc.Ccb.ClosestHitFraction = 1.0f; nfc.Ccb.HitCollisionObject = null; BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) t1).ToBullet(), ((Matrix4) t2).ToBullet(), nfc.Ccb); if (nfc.Ccb.HasHit) { upFounded = 1; n0 = nfc.Ccb.HitNormalWorld.ToOpenTK(); n0d = -n0.Dot(nfc.Ccb.HitPointWorld.ToOpenTK()); } else { return ret; } } // mult 0.66 is magic, but it must be less than 1.0 and greater than 0.0; // close to 1.0 - bad precision, good speed; // close to 0.0 - bad speed, bad precision; // close to 0.5 - middle speed, good precision from.Z -= 0.66f * ClimbR; to.Z -= 0.66f * ClimbR; } while (to.Z >= d); // we can't climb under floor! if (upFounded != 2) { return ret; } // get the character plane equation var n2 = Transform.Basis.Column0; var n2d = -n2.Dot(pos); Assert(!n0.FuzzyZero()); Assert(!n1.FuzzyZero()); Assert(!n2.FuzzyZero()); /* * Solve system of the linear equations by Kramer method! * I know - It may be slow, but it has a good precision! * The root is point of 3 planes intersection. */ d = -n0[0] * (n1[1] * n2[2] - n1[2] * n2[1]) + n1[0] * (n0[1] * n2[2] - n0[2] * n2[1]) - n2[0] * (n0[1] * n1[2] - n0[2] * n1[1]); if (Math.Abs(d) < 0.005f) { return ret; } ret.EdgePoint[0] = n0d * (n1[1] * n2[2] - n1[2] * n2[1]) - n1d * (n0[1] * n2[2] - n0[2] * n2[1]) + n2d * (n0[1] * n1[2] - n0[2] * n1[1]); ret.EdgePoint[0] /= d; ret.EdgePoint[1] = n0[0] * (n1d * n2[2] - n1[2] * n2d) - n1[0] * (n0d * n2[2] - n0[2] * n2d) + n2[0] * (n0d * n1[2] - n0[2] * n1d); ret.EdgePoint[1] /= d; ret.EdgePoint[2] = n0[0] * (n1[1] * n2d - n1d * n2[1]) - n1[0] * (n0[1] * n2d - n0d * n2[1]) + n2[0] * (n0[1] * n1d - n0d * n1[1]); ret.EdgePoint[2] /= d; ret.Point = ret.EdgePoint; ret.Point.CopyToArray(castRay, 3); /* * unclimbable edge slant %) */ n2 = n0.Cross(n1); d = CriticalSlantZComponent; d *= d * (n2[0] * n2[0] + n2[1] * n2[1] + n2[2] * n2[2]); if (n2[2] * n2[2] > d) { return ret; } /* * Now, let us calculate z_angle */ ret.EdgeHit = true; n2.Z = n2.X; n2.X = n2.Y; n2.Y = -n2.Z; n2.Z = 0.0f; if (n2.X * Transform.Basis.Column1.X + n2.Y * Transform.Basis.Column1.Y > 0) // direction fixing { n2.X = -n2.X; n2.Y = -n2.Y; } ret.N = n2; ret.Up.X = 0.0f; ret.Up.Y = 0.0f; ret.Up.Z = 1.0f; ret.EdgeZAngle = Helper.Atan2(n2.X, -n2.Y) * DegPerRad; ret.EdgeTanXY.X = -n2.Y; ret.EdgeTanXY.Y = n2.X; ret.EdgeTanXY.Z = 0.0f; ret.EdgeTanXY /= (float) Math.Sqrt(n2.X * n2.X + n2.Y * n2.Y); ret.Right = ret.EdgeTanXY; if (!HeightInfo.FloorHit || ret.EdgePoint.Z - HeightInfo.FloorPoint.Z >= Height) { ret.CanHang = true; } ret.NextZSpace = 2.0f * Height; if (nfc.FloorHit && nfc.CeilingHit) { ret.NextZSpace = nfc.CeilingPoint.Z - nfc.FloorPoint.Z; } return ret; }
public ClimbInfo CheckWallsClimbability() { var ret = new ClimbInfo(); ret.CanHang = false; ret.WallHit = ClimbType.None; ret.EdgeHit = false; ret.EdgeObject = null; ret.FloorLimit = HeightInfo.FloorHit ? HeightInfo.FloorPoint.Z : -9e10f; ret.CeilingLimit = HeightInfo.CeilingHit ? HeightInfo.CeilingPoint.Z : 9e10f; ret.Point = Climb.Point; if (!HeightInfo.WallsClimb) { return ret; } ret.Up = Vector3.UnitZ; var pos = Transform.Origin; var from = pos + Transform.Basis.Column2 * Bf.BBMax.Z - Transform.Basis.Column1 * ClimbR; var to = from; var t = ForwardSize + Bf.BBMax.Y; to += Transform.Basis.Column1 * t; var ccb = ConvexCb; ccb.ClosestHitFraction = 1.0f; ccb.HitCollisionObject = null; var tr1 = new Transform(); tr1.SetIdentity(); tr1.Origin = from; var tr2 = new Transform(); tr2.SetIdentity(); tr2.Origin = to; BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) tr1).ToBullet(), ((Matrix4) tr2).ToBullet(), ccb); if (!ccb.HasHit) { return ret; } ret.Point = ccb.HitPointWorld.ToOpenTK(); ret.N = ccb.HitNormalWorld.ToOpenTK(); var wn2 = new[] {ret.N.X, ret.N.Y}; t = (float) Math.Sqrt(wn2[0] * wn2[0] + wn2[1] * wn2[1]); wn2[0] /= t; wn2[1] /= t; ret.Right.X = -wn2[1]; ret.Right.Y = wn2[0]; ret.Right.Z = 0.0f; // now we have wall normale in XOY plane. Let us check all flags if (HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbNorth) && wn2[1] < -0.7f || HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbEast) && wn2[0] < -0.7f || HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbSouth) && wn2[1] > 0.7f || HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbWest) && wn2[0] > 0.7f) { ret.WallHit = ClimbType.HandsOnly; } if (ret.WallHit != ClimbType.None) { t = 0.67f * Height; from -= Transform.Basis.Column2 * t; to = from; t = ForwardSize + Bf.BBMax.Y; to += Transform.Basis.Column1 * t; ccb.ClosestHitFraction = 1.0f; ccb.HitCollisionObject = null; tr1.SetIdentity(); tr1.Origin = from; tr2.SetIdentity(); tr2.Origin = to; BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) tr1).ToBullet(), ((Matrix4) tr2).ToBullet(), ccb); if (ccb.HasHit) { ret.WallHit = ClimbType.FullBody; } } return ret; }
public BSPFaceRef(Transform matrix, TransparentPolygonReference polygon) { Transform = matrix; Polygon = polygon; }
public void Render() { if(CurrentState != InventoryState.Disabled && inventory != null && inventory.Count > 0 && Global.FontManager != null) { var num = 0; foreach (var i in inventory) { var bi = EngineWorld.GetBaseItemByID(i.ID); if(bi == null || bi.Type != currentItemsType) { continue; } var matrix = new Transform(); matrix.SetIdentity(); VMath.Mat4_Translate(matrix, 0.0f, 0.0f, -baseRingRadius * 2.0f); //VMath.Mat4_RotateX(matrix, 25.0f); VMath.Mat4_RotateX(matrix, 25.0f + ringVerticalAngle); var ang = ringAngleStep * (-itemsOffset + num) + ringAngle; VMath.Mat4_RotateY(matrix, ang); VMath.Mat4_Translate(matrix, 0.0f, verticalOffset, ringRadius); VMath.Mat4_RotateX(matrix, -90.0f); VMath.Mat4_RotateZ(matrix, 90.0f); if(num == itemsOffset) { if(bi.Name[0] != 0) { LabelItemName.Text = bi.Name; if(i.Count > 1) { var counter = EngineLua.GetString(STR_GEN_MASK_INVHEADER); LabelItemName.Text = Helper.Format(counter, bi.Name, i.Count); } } VMath.Mat4_RotateZ(matrix, 90.0f + itemAngle - ang); Gui.Item_Frame(bi.BoneFrame, 0.0f); // here will be time != 0 for using items animation } else { VMath.Mat4_RotateZ(matrix, 90.0f - ang); Gui.Item_Frame(bi.BoneFrame, 0.0f); } VMath.Mat4_Translate(matrix, -0.5f * bi.BoneFrame.Centre); VMath.Mat4_Scale(matrix, 0.7f, 0.7f, 0.7f); Gui.RenderItem(bi.BoneFrame, 0.0f, matrix); num++; } } }
public void VTransform(Polygon src, Transform tr) { Plane.Normal = tr.Basis.MultiplyByVector(src.Plane.Normal); for (var i = 0; i < src.Vertices.Count; i++) { Vertices[i].Position = tr * src.Vertices[i].Position; } Plane.MoveTo(Vertices[0].Position); }
public void RenderSkeletalModelSkin(LitShaderDescription shader, Entity ent, Matrix4 mvMatrix, Matrix4 pMatrix) { GL.UniformMatrix4(shader.Projection, false, ref pMatrix); foreach (var btag in ent.Bf.BoneTags) { var transforms = new float[32]; var mvTransforms = mvMatrix.MultiplyByTransform(btag.FullTransform); unsafe { Array.Copy(Helper.GetArrayFromPointer(&mvTransforms.Row0.X, 16), transforms, 16); } // Calculate parent transform var parentTransform = btag.Parent == null ? ent.Transform : btag.Parent.FullTransform; var translate = new Transform(); translate.SetIdentity(); translate.Origin += btag.Offset; var secondTransform = parentTransform * translate; var mvTransforms2 = mvMatrix.MultiplyByTransform(secondTransform); unsafe { Array.Copy(Helper.GetArrayFromPointer(&mvTransforms2.Row0.X, 16), 0, transforms, 16, 16); } GL.UniformMatrix4(shader.ModelView, 2, false, transforms); if(btag.MeshSkin != null) { RenderMesh(btag.MeshSkin); } } }
public void Transform(Polygon src, Transform tr) { Vertices.Resize(src.Vertices.Count, () => new Vertex()); Plane.Normal = tr.Basis.MultiplyByVector(src.Plane.Normal); for (var i = 0; i < src.Vertices.Count; i++) { Vertices[i].Position = tr * src.Vertices[i].Position; Vertices[i].Normal = tr.Basis.MultiplyByVector(src.Vertices[i].Normal); } Plane.MoveTo(Vertices[0].Position); }
public void RenderSkyBox(Matrix4 modelViewProjectionMatrix) { if (drawSkybox && World?.SkyBox != null) { GL.DepthMask(false); var tr = new Transform(); tr.Origin = Camera.Position + World.SkyBox.Animations[0].Frames[0].BoneTags[0].Offset; tr.Rotation = World.SkyBox.Animations[0].Frames[0].BoneTags[0].QRotate; var fullView = modelViewProjectionMatrix.MultiplyByTransform(tr); var shader = ShaderManager.GetStaticMeshShader(); GL.UseProgram(shader.Program); GL.UniformMatrix4(shader.ModelViewProjection, false, ref fullView); GL.Uniform1(shader.Sampler, 0); var tint = new float[] {1, 1, 1, 1}; GL.Uniform4(shader.TintMult, 1, tint); RenderMesh(World.SkyBox.MeshTree[0].MeshBase); GL.DepthMask(true); } }
public void TransformSelf(Transform tr) { Plane.Normal = tr.Basis.MultiplyByVector(Plane.Normal); foreach (var t in Vertices) { t.Position *= tr; t.Normal = tr.Basis.MultiplyByVector(t.Normal); } Plane.MoveTo(Vertices[0].Position); }
public void DrawBBox(Vector3 bbMin, Vector3 bbMax, Transform transform) { obb.Rebuild(bbMin, bbMax); obb.Transform = transform; obb.DoTransform(); DrawOBB(obb); }
public static bool Cam_HasHit(BtEngineClosestConvexResultCallback cb, Transform cameraFrom, Transform cameraTo) { var cameraSphere = new SphereShape(COLLISION_CAMERA_SPHERE_RADIUS) { Margin = COLLISION_MARGIN_DEFAULT }; cb.ClosestHitFraction = 1.0f; cb.HitCollisionObject = null; BtEngineDynamicsWorld.ConvexSweepTest(cameraSphere, ((Matrix4)cameraFrom).ToBullet(), ((Matrix4)cameraTo).ToBullet(), cb); return cb.HasHit; }
public void DrawSkeletalModelDebugLines(SSBoneFrame bframe, Transform transform, Render render) { if(render.drawNormals) { foreach (var btag in bframe.BoneTags) { var tr = transform * btag.FullTransform; DrawMeshDebugLines(btag.MeshBase, tr, new List<Vector3>(), new List<Vector3>(), render); } } }
public static void Cam_FollowEntity(Camera cam, Entity ent, float dx, float dz) { var cameraFrom = new Transform(); var cameraTo = new Transform(); // Reset to initial cameraFrom.SetIdentity(); cameraTo.SetIdentity(); var cb = ent.CallbackForCamera(); var camPos = cam.Position; // Basic camera override, completely placeholder until a system classic-like is created if (!ControlStates.MouseLook) // If mouse look is off { var currentAngle = CamAngles.X * RadPerDeg; // Current is the current cam angle var targetAngle = ent.Angles.X * RadPerDeg; // Target is the target angle which is the entity's angle itself var rotSpeed = 2.0f; // Speed of rotation //@FIXME // If Lara is in a specific state we want to rotate -75 deg or +75 deg depending on camera collision if(ent.Bf.Animations.LastState == TR_STATE.LaraReach) { if(cam.TargetDir == TR_CAM_TARG.Back) { var camPos2 = camPos; cameraFrom.Origin = camPos2; camPos2.X += (float) (Math.Sin((ent.Angles.X - 90.0f) * RadPerDeg) * ControlStates.CamDistance); camPos2.Y -= (float) (Math.Cos((ent.Angles.X - 90.0f) * RadPerDeg) * ControlStates.CamDistance); cameraTo.Origin = camPos2; // If collided we want to go right otherwise stay left if(Cam_HasHit(cb, cameraFrom, cameraTo)) { camPos2 = camPos; cameraFrom.Origin = camPos2; camPos2.X += (float)(Math.Sin((ent.Angles.X + 90.0f) * RadPerDeg) * ControlStates.CamDistance); camPos2.Y -= (float)(Math.Cos((ent.Angles.X + 90.0f) * RadPerDeg) * ControlStates.CamDistance); cameraTo.Origin = camPos2; // If collided we want to go to back else right cam.TargetDir = Cam_HasHit(cb, cameraFrom, cameraTo) ? TR_CAM_TARG.Back : TR_CAM_TARG.Right; } else { cam.TargetDir = TR_CAM_TARG.Left; } } } else if(ent.Bf.Animations.LastState == TR_STATE.LaraJumpBack) { cam.TargetDir = TR_CAM_TARG.Front; } // ReSharper disable once RedundantCheckBeforeAssignment else if(cam.TargetDir != TR_CAM_TARG.Back) { cam.TargetDir = TR_CAM_TARG.Back; // Reset to back } // If target mis-matches current we need to update the camera's angle to reach target! if (currentAngle != targetAngle) { switch (cam.TargetDir) { case TR_CAM_TARG.Back: targetAngle = ent.Angles.X * RadPerDeg; break; case TR_CAM_TARG.Front: targetAngle = (ent.Angles.X - 180.0f) * RadPerDeg; break; case TR_CAM_TARG.Left: targetAngle = (ent.Angles.X - 75.0f) * RadPerDeg; break; case TR_CAM_TARG.Right: targetAngle = (ent.Angles.X + 75.0f) * RadPerDeg; break; default: targetAngle = ent.Angles.X * RadPerDeg; // Same as TR_CAM_TARG_BACK (default pos) break; } var dAngle = CamAngles.X - targetAngle; if (dAngle > Rad90) { dAngle -= 1 * RadPerDeg; } else { dAngle += 1 * RadPerDeg; } CamAngles.X = (CamAngles.X + Helper.Atan2((float) Math.Sin(currentAngle - dAngle), (float) Math.Cos(currentAngle + dAngle)) * EngineFrameTime * rotSpeed) % Rad360; // Update camera's angle } } camPos = ent.CamPosForFollowing(dz); // Code to manage screen shaking effects if(Renderer.Camera.ShakeTime > 0.0f && Renderer.Camera.ShakeValue > 0.0f) { camPos = camPos.AddF((Helper.CPPRand() % Math.Abs(Renderer.Camera.ShakeValue) - Renderer.Camera.ShakeValue / 2.0f) * Renderer.Camera.ShakeTime); Renderer.Camera.ShakeTime = Renderer.Camera.ShakeTime < 0.0f ? 0.0f : Renderer.Camera.ShakeTime - EngineFrameTime; } cameraFrom.Origin = camPos; camPos.Z += dz; cameraTo.Origin = camPos; if(Cam_HasHit(cb, cameraFrom, cameraTo)) { Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction); camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK(); } if(dx != 0.0f) { cameraFrom.Origin = camPos; camPos += dx * cam.RightDirection; cameraTo.Origin = camPos; if (Cam_HasHit(cb, cameraFrom, cameraTo)) { Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction); camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK(); } cameraFrom.Origin = camPos; var cosAy = Math.Cos(CamAngles.Y); var camDx = Math.Sin(CamAngles.X) * cosAy; var camDy = -Math.Cos(CamAngles.X) * cosAy; var camDz = -Math.Sin(CamAngles.Y); camPos.X += (float) (camDx * ControlStates.CamDistance); camPos.Y += (float) (camDy * ControlStates.CamDistance); camPos.Z += (float) (camDz * ControlStates.CamDistance); cameraTo.Origin = camPos; if (Cam_HasHit(cb, cameraFrom, cameraTo)) { Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction); camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK(); } } // Update cam pos cam.Position = camPos; // Modify cam pos for quicksand rooms cam.CurrentRoom = Room.FindPosCogerrence(cam.Position - new Vector3(0, 0, 128), cam.CurrentRoom); if(cam.CurrentRoom != null && cam.CurrentRoom.Flags.HasFlagUns(RoomFlag.Quicksand)) { var pos = cam.Position; pos.Z = cam.CurrentRoom.BBMax.Z + 2.0f * 64.0f; cam.Position = pos; } cam.SetRotation(CamAngles); cam.CurrentRoom = Room.FindPosCogerrence(cam.Position, cam.CurrentRoom); }
public void RenderDynamicEntitySkin(LitShaderDescription shader, Entity ent, Matrix4 mvMatrix, Matrix4 pMatrix) { GL.UniformMatrix4(shader.Projection, false, ref pMatrix); for (var i = 0; i < ent.Bf.BoneTags.Count; i++) { var mat0 = mvMatrix * ent.Bt.BtBody[i].GetWorldTransform(); var tr1 = new Matrix4(); // Calculate parent transform var btag = ent.Bf.BoneTags[i]; var foundParentTransform = false; for (var j = 0; j < ent.Bf.BoneTags.Count; j++) { if(ent.Bf.BoneTags[i] == btag.Parent) { tr1 = ent.Bt.BtBody[j].GetWorldTransform(); foundParentTransform = true; break; } } if (!foundParentTransform) tr1 = (Matrix4) ent.Transform; var translate = new Transform(); translate.SetIdentity(); translate.Origin += btag.Offset; var secondTransform = tr1.MultiplyByTransform(translate); var mat1 = mvMatrix * secondTransform; var transforms = new float[32]; unsafe { Array.Copy(Helper.GetArrayFromPointer(&mat0.Row0.X, 16), transforms, 16); Array.Copy(Helper.GetArrayFromPointer(&mat1.Row0.X, 16), 0, transforms, 16, 16); } GL.UniformMatrix4(shader.ModelView, 2, false, transforms); if (btag.MeshSkin != null) { RenderMesh(btag.MeshSkin); } } }
public static void PrimaryMouseDown() { var cont = new EngineContainer(); var dbgR = 128.0f; var v = EngineCamera.Position; var dir = EngineCamera.ViewDirection; var localInertia = BulletSharp.Math.Vector3.Zero; var cshape = new SphereShape(dbgR); cshape.Margin = COLLISION_MARGIN_DEFAULT; var startTransform = new Transform(); startTransform.SetIdentity(); var newPos = v; startTransform.Origin = newPos; cshape.CalculateLocalInertia(12.0f, out localInertia); var motionState = new DefaultMotionState(((Matrix4)startTransform).ToBullet()); var body = new RigidBody(new RigidBodyConstructionInfo(12.0f, motionState, cshape, localInertia)); BtEngineDynamicsWorld.AddRigidBody(body); body.LinearVelocity = (dir * 6000).ToBullet(); cont.Room = Room.FindPosCogerrence(newPos, EngineCamera.CurrentRoom); cont.ObjectType = OBJECT_TYPE.BulletMisc; // bullet have to destroy this user pointer body.UserObject = cont; body.CcdMotionThreshold = dbgR; // disable tunneling effect body.CcdSweptSphereRadius = dbgR; }