void SubscribeToEvents() { Engine.SubscribeToPostUpdate(args => { if (vehicle == null) return; Node vehicleNode = vehicle.Node; // Physics update has completed. Position camera behind vehicle Quaternion dir = Quaternion.FromAxisAngle(Vector3.UnitY, vehicleNode.Rotation.YawAngle); dir = dir * Quaternion.FromAxisAngle(Vector3.UnitY, vehicle.Controls.Yaw); dir = dir * Quaternion.FromAxisAngle(Vector3.UnitX, vehicle.Controls.Pitch); Vector3 cameraTargetPos = vehicleNode.Position - (dir * new Vector3(0.0f, 0.0f, CameraDistance)); Vector3 cameraStartPos = vehicleNode.Position; // Raycast camera against static objects (physics collision mask 2) // and move it closer to the vehicle if something in between Ray cameraRay = new Ray(cameraStartPos, cameraTargetPos - cameraStartPos); float cameraRayLength = (cameraTargetPos - cameraStartPos).Length; PhysicsRaycastResult result = new PhysicsRaycastResult(); scene.GetComponent<PhysicsWorld>().RaycastSingle(ref result, cameraRay, cameraRayLength, 2); if (result.Body != null) { cameraTargetPos = cameraStartPos + cameraRay.Direction * (result.Distance - 0.5f); } CameraNode.Position = cameraTargetPos; CameraNode.Rotation = dir; }); scene.GetComponent<PhysicsWorld>().SubscribeToPhysicsPreStep(args => vehicle?.FixedUpdate(args.TimeStep)); }
void HandlePostUpdate(PostUpdateEventArgs args) { if (character == null) { return; } Node characterNode = character.Node; // Get camera lookat dir from character yaw + pitch Quaternion rot = characterNode.Rotation; Quaternion dir = rot * Quaternion.FromAxisAngle(Vector3.UnitX, character.Controls.Pitch); // Turn head to camera pitch, but limit to avoid unnatural animation Node headNode = characterNode.GetChild("Bip01_Head", true); if (headNode != null) { float limitPitch = MathHelper.Clamp(character.Controls.Pitch, -45.0f, 45.0f); Quaternion headDir = rot * Quaternion.FromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), limitPitch); // This could be expanded to look at an arbitrary target, now just look at a point in front Vector3 headWorldTarget = headNode.WorldPosition + headDir * new Vector3(0.0f, 0.0f, 1.0f); headNode.LookAt(headWorldTarget, new Vector3(0.0f, 1.0f, 0.0f), TransformSpace.World); // Correct head orientation because LookAt assumes Z = forward, but the bone has been authored differently (Y = forward) headNode.Rotate(new Quaternion(0.0f, 90.0f, 90.0f), TransformSpace.Local); } if (firstPerson) { if (headNode != null) { CameraNode.Position = headNode.WorldPosition + rot * new Vector3(0.0f, 0.15f, 0.2f); CameraNode.Rotation = dir; } } else { // Third person camera: position behind the character Vector3 aimPoint = characterNode.Position + rot * new Vector3(0.0f, 1.7f, 0.0f); // Collide camera ray with static physics objects (layer bitmask 2) to ensure we see the character properly Vector3 rayDir = dir * new Vector3(0f, 0f, -1f); float rayDistance = touch != null ? touch.CameraDistance : CameraInitialDist; PhysicsRaycastResult result = new PhysicsRaycastResult(); scene.GetComponent <PhysicsWorld>().RaycastSingle(ref result, new Ray(aimPoint, rayDir), rayDistance, 2); if (result.Body != null) { rayDistance = Math.Min(rayDistance, result.Distance); } rayDistance = MathHelper.Clamp(rayDistance, CameraMinDist, CameraMaxDist); CameraNode.Position = aimPoint + rayDir * rayDistance; CameraNode.Rotation = dir; } }
void SubscribeToEvents() { SubscribeToEvent <PostUpdateEvent>(e => { if (vehicle == null) { return; } Node vehicleNode = vehicle.Node; // Physics update has completed. Position camera behind vehicle Quaternion dir = Quaternion.FromAxisAngle(Vector3.UnitY, vehicleNode.Rotation.YawAngle); dir = dir * Quaternion.FromAxisAngle(Vector3.UnitY, vehicle.Controls.Yaw); dir = dir * Quaternion.FromAxisAngle(Vector3.UnitX, vehicle.Controls.Pitch); Vector3 cameraTargetPos = vehicleNode.Position - (dir * new Vector3(0.0f, 0.0f, CameraDistance)); Vector3 cameraStartPos = vehicleNode.Position; // and move it closer to the vehicle if something in between Ray cameraRay = new Ray(cameraStartPos, cameraTargetPos - cameraStartPos); float cameraRayLength = (cameraTargetPos - cameraStartPos).Length; // Raycast camera against static objects (physics collision mask 2) var query = new RayOctreeQuery(cameraRay, RayQueryLevel.RAY_TRIANGLE, cameraRayLength, Constants.DRAWABLE_ANY, 2); PhysicsRaycastResult result = new PhysicsRaycastResult(); scene.GetComponent <PhysicsWorld>().RaycastSingle(ref result, cameraRay, cameraRayLength, 2); if (result.Body != null) { cameraTargetPos = cameraStartPos + cameraRay.Direction * (result.Distance - 0.5f); } CameraNode.Position = cameraTargetPos; CameraNode.Rotation = dir; }); }
void SubscribeToEvents() { Engine.PostUpdate += args => { if (vehicle == null) { return; } Node vehicleNode = vehicle.Node; // Physics update has completed. Position camera behind vehicle Quaternion dir = Quaternion.FromAxisAngle(Vector3.UnitY, vehicleNode.Rotation.YawAngle); dir *= Quaternion.FromAxisAngle(Vector3.UnitY, vehicle.Controls.Yaw); dir *= Quaternion.FromAxisAngle(Vector3.UnitX, vehicle.Controls.Pitch); Vector3 cameraTargetPos = vehicleNode.Position - (dir * new Vector3(0.0f, 0.0f, CameraDistance)); Vector3 cameraStartPos = vehicleNode.Position; // Raycast camera against static objects (physics collision mask 2) // and move it closer to the vehicle if something in between Ray cameraRay = new Ray(cameraStartPos, cameraTargetPos - cameraStartPos); float cameraRayLength = (cameraTargetPos - cameraStartPos).Length; PhysicsRaycastResult result = new PhysicsRaycastResult(); scene.GetComponent <PhysicsWorld>().RaycastSingle(ref result, cameraRay, cameraRayLength, 2); if (result.Body != null) { cameraTargetPos = cameraStartPos + cameraRay.Direction * (result.Distance - 0.5f); } CameraNode.Position = cameraTargetPos; CameraNode.Rotation = dir; }; scene.GetComponent <PhysicsWorld>().PhysicsPreStep += args => vehicle?.FixedUpdate(args.TimeStep); }
void HandlePostUpdate(PostUpdateEventArgs args) { if (character == null) return; Node characterNode = character.Node; // Get camera lookat dir from character yaw + pitch Quaternion rot = characterNode.Rotation; Quaternion dir = rot * Quaternion.FromAxisAngle(Vector3.UnitX, character.Controls.Pitch); // Turn head to camera pitch, but limit to avoid unnatural animation Node headNode = characterNode.GetChild("Bip01_Head", true); float limitPitch = MathHelper.Clamp(character.Controls.Pitch, -45.0f, 45.0f); Quaternion headDir = rot * Quaternion.FromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), limitPitch); // This could be expanded to look at an arbitrary target, now just look at a point in front Vector3 headWorldTarget = headNode.WorldPosition + headDir * new Vector3(0.0f, 0.0f, 1.0f); headNode.LookAt(headWorldTarget, new Vector3(0.0f, 1.0f, 0.0f), TransformSpace.World); // Correct head orientation because LookAt assumes Z = forward, but the bone has been authored differently (Y = forward) headNode.Rotate(new Quaternion(0.0f, 90.0f, 90.0f), TransformSpace.Local); if (firstPerson) { CameraNode.Position = headNode.WorldPosition + rot * new Vector3(0.0f, 0.15f, 0.2f); CameraNode.Rotation = dir; } else { // Third person camera: position behind the character Vector3 aimPoint = characterNode.Position + rot * new Vector3(0.0f, 1.7f, 0.0f); // Collide camera ray with static physics objects (layer bitmask 2) to ensure we see the character properly Vector3 rayDir = dir * new Vector3(0f, 0f, -1f); float rayDistance = touch != null ? touch.CameraDistance : CameraInitialDist; PhysicsRaycastResult result = new PhysicsRaycastResult(); scene.GetComponent<PhysicsWorld>().RaycastSingle(ref result, new Ray(aimPoint, rayDir), rayDistance, 2); if (result.Body != null) rayDistance = Math.Min(rayDistance, result.Distance); rayDistance = MathHelper.Clamp(rayDistance, CameraMinDist, CameraMaxDist); CameraNode.Position = aimPoint + rayDir * rayDistance; CameraNode.Rotation = dir; } }