internal Rayd CastFromCamera(GraphicsDevice graphicsDevice, Vector2 mouseVector) { Matrixd worldd = Matrixd.CreateRotationZ(-cameraRotX) * Matrixd.CreateRotationX(cameraRotY); double distance = 9 * Math.Pow(0.5, cameraZoom); Matrixd viewd = CameraMatrixManager.GetWorldViewd(distance); Matrixd projectiond = CameraMatrixManager.GetWorldProjectiond(distance, graphicsDevice.Viewport.AspectRatio); return(Rayd.CastFromCamera(graphicsDevice, mouseVector.X, mouseVector.Y, projectiond, viewd, worldd)); }
// yup, it returns lat/long only in the range you'd expect internal Vector3d GetLatLongOfCoord(GraphicsDevice graphicsDevice, double x, double y) { Matrixd worldd = Matrixd.CreateRotationZ(-cameraRotX) * Matrixd.CreateRotationX(cameraRotY); double distance = 9 * Math.Pow(0.5, cameraZoom); Matrixd viewd = CameraMatrixManager.GetWorldViewd(distance); Matrixd projectiond = CameraMatrixManager.GetWorldProjectiond(distance, graphicsDevice.Viewport.AspectRatio); Rayd ray = Rayd.CastFromCamera(graphicsDevice, x, y, projectiond, viewd, worldd); Vector3d intersection = ray.IntersectionSphere(new Vector3d(0, 0, 0), 1); // angle 0 if (intersection == null) { return(null); } return(ToLatLong(intersection)); }
private Matrixd CreateShipWVP(RenderContext renderContext, double rotation) { double fakeScale = Math.Max(Math.Pow(2, 21 - camera.cameraZoom), 1); // make the ship bigger to account for depth buffer limitations Vector3d shipPos = position; // earth radius 6371 km double shipScale = fakeScale / 6371000; double distanceFromCamera = 30; // in meters Matrixd world = Matrixd.CreateRotationZ(-camera.cameraRotX) * Matrixd.CreateRotationX(camera.cameraRotY); // eh.... think hard on this later double distance = 9 * Math.Pow(0.5, camera.cameraZoom); shipPos += position.WalkNorth(-Math.PI / 4) * (distance * 2 - distanceFromCamera * shipScale); // why distance * 2?? Matrixd view = CameraMatrixManager.GetWorldViewd(distance); Matrixd projection = CameraMatrixManager.GetWorldProjectiond(distance, renderContext.graphicsDevice.Viewport.AspectRatio); Matrixd worldWVP = world * view * projection; Matrixd shipRot = Matrixd.CreateRotationZ(rotation + Math.PI) * Matrixd.CreateRotationX(Math.PI / 2 - camera.cameraRotY) * Matrixd.CreateRotationZ(camera.cameraRotX); return(shipRot * Matrixd.CreateScale(shipScale) * Matrixd.CreateTranslation(shipPos) * worldWVP); }
private void Draw3D(GraphicsDevice graphicsDevice, SectorBounds bounds, ISector rootSector, RenderContext.LayerPass layerPass) { double relativeCameraZoom = camera.cameraZoom - Math.Log(ZCoords.GetSectorManager().GetTopmostOSMSectors().Count, 4) + (Game1.RECORDING ? 1 : 0); int zoomLevel = Math.Min(Math.Max((int)(relativeCameraZoom - 3), 0), ZCoords.GetSectorManager().GetHighestOSMZoom()); List <ISector> containedSectors = rootSector.GetSectorsInRange(bounds.minX, bounds.maxX, bounds.minY, bounds.maxY, zoomLevel); List <ISector> sorted = containedSectors.Where(x => x.GetRoot().Equals(rootSector)).ToList(); sorted.Sort((x, y) => x.Zoom.CompareTo(y.Zoom)); foreach (var sector in sorted) { IGraphicsBuffer buffer = loadedMaps[sector]; if (buffer is ImageTileBuffer) { continue; } SectorBounds b = new SectorBounds(bounds.minX * (1 << sector.Zoom) - sector.X, bounds.maxX * (1 << sector.Zoom) - sector.X, bounds.minY * (1 << sector.Zoom) - sector.Y, bounds.maxY * (1 << sector.Zoom) - sector.Y); SectorBounds limitedB = new SectorBounds(Math.Max(0, Math.Min(1, b.minX)), Math.Max(0, Math.Min(1, b.maxX)), Math.Max(0, Math.Min(1, b.minY)), Math.Max(0, Math.Min(1, b.maxY))); BasicEffect basicEffect = new BasicEffect(graphicsDevice); camera.ApplyMatrices(basicEffect); // going to make it easy and assume the shape is perfectly parallel (it's not) // the sector plane is constructed by flattening the visible portion of the sphere, basically Vector3d v1 = sector.ProjectToSphereCoordinates(new Vector2d(limitedB.minX, limitedB.minY)); Vector3d v2 = sector.ProjectToSphereCoordinates(new Vector2d(limitedB.maxX, limitedB.minY)); Vector3d v3 = sector.ProjectToSphereCoordinates(new Vector2d(limitedB.minX, limitedB.maxY)); Vector3d xAxis = (v2 - v1) / (limitedB.maxX - limitedB.minX); Vector3d yAxis = (v3 - v1) / (limitedB.maxY - limitedB.minY); Vector3d start = v1 - xAxis * limitedB.minX - yAxis * limitedB.minY; Vector3d zAxis = start * (xAxis.Length() + yAxis.Length()) / start.Length() / 2; // make this roughly the same length // matrixes copied over Matrixd world = Matrixd.CreateRotationZ(-camera.cameraRotX) * Matrixd.CreateRotationX(camera.cameraRotY); // eh.... think hard on this later double distance = 9 * Math.Pow(0.5, camera.cameraZoom); Matrixd view = CameraMatrixManager.GetWorldViewd(distance); Matrixd projection = CameraMatrixManager.GetWorldProjectiond(distance, graphicsDevice.Viewport.AspectRatio); Matrixd transformMatrix = new Matrixd(xAxis.X, xAxis.Y, xAxis.Z, 0, yAxis.X, yAxis.Y, yAxis.Z, 0, zAxis.X, zAxis.Y, zAxis.Z, 0, start.X, start.Y, start.Z, 1); // turns our local coordinates into 3d spherical coordinates, based on the sector Matrixd WVP = Normalize(transformMatrix * world * view * projection); // combine them all to allow for higher precision RenderContext context = new RenderContext(graphicsDevice, WVP, b.minX, b.maxX, b.minY, b.maxY, camera.cameraZoom, layerPass); buffer.Draw(context); } }