private void Update(Context context, ClipmapUpdate update, ClipmapLevel level, RasterDataDetails details, RasterLevel rasterLevel) { ClipmapUpdate[] updates = SplitUpdateToAvoidWrapping(update, details); foreach (ClipmapUpdate nonWrappingUpdate in updates) { RasterTileRegion[] tileRegions = rasterLevel.GetTilesInExtent(nonWrappingUpdate.West, nonWrappingUpdate.South, nonWrappingUpdate.East, nonWrappingUpdate.North); foreach (RasterTileRegion region in tileRegions) { Texture2D tileTexture; bool loaded = details.LoadedTiles.TryGetValue(region.Tile.Identifier, out tileTexture); if (loaded) { RenderTileToLevelTexture(context, level, details, region, tileTexture); } else { UpsampleTileData(context, level, details, region); } } } if (details.Type == RasterType.Terrain) { // Normals at edges are incorrect, so include a one-post buffer around the update region // when updating normals in order to update normals that were previously at the edge. ClipmapUpdate updateWithBuffer = update.AddBufferWithinLevelNextExtent(); ClipmapUpdate[] normalUpdates = SplitUpdateToAvoidWrapping(updateWithBuffer, details); foreach (ClipmapUpdate normalUpdate in normalUpdates) { UpdateNormals(context, normalUpdate); } } }
private void UpdateImagery(ClipmapLevel level, ClipmapLevel coarserLevel, Context context, SceneState sceneState) { int deltaX = level.NextImageryExtent.West - level.CurrentImageryExtent.West; int deltaY = level.NextImageryExtent.South - level.CurrentImageryExtent.South; if (deltaX == 0 && deltaY == 0) { return; } int minLongitude = deltaX > 0 ? level.CurrentImageryExtent.East + 1 : level.NextImageryExtent.West; int maxLongitude = deltaX > 0 ? level.NextImageryExtent.East : level.CurrentImageryExtent.West - 1; int minLatitude = deltaY > 0 ? level.CurrentImageryExtent.North + 1 : level.NextImageryExtent.South; int maxLatitude = deltaY > 0 ? level.NextImageryExtent.North : level.CurrentImageryExtent.South - 1; int width = maxLongitude - minLongitude + 1; int height = maxLatitude - minLatitude + 1; if (level.CurrentImageryExtent.West > level.CurrentImageryExtent.East || // initial update width >= level.ImageryWidth || height >= level.ImageryHeight) // complete update { // Initial or complete update. width = level.ImageryWidth; height = level.ImageryHeight; deltaX = level.ImageryWidth; deltaY = level.ImageryHeight; minLongitude = level.NextImageryExtent.West; maxLongitude = level.NextImageryExtent.East; minLatitude = level.NextImageryExtent.South; maxLatitude = level.NextImageryExtent.North; } if (height > 0) { ClipmapUpdate horizontalUpdate = new ClipmapUpdate( level, level.NextImageryExtent.West, minLatitude, level.NextImageryExtent.East, maxLatitude); _updater.UpdateImagery(context, horizontalUpdate); } if (width > 0) { ClipmapUpdate verticalUpdate = new ClipmapUpdate( level, minLongitude, level.NextImageryExtent.South, maxLongitude, level.NextImageryExtent.North); _updater.UpdateImagery(context, verticalUpdate); } level.CurrentImageryExtent.West = level.NextImageryExtent.West; level.CurrentImageryExtent.South = level.NextImageryExtent.South; level.CurrentImageryExtent.East = level.NextImageryExtent.East; level.CurrentImageryExtent.North = level.NextImageryExtent.North; }
public void Render(Context context, SceneState sceneState) { if (_wireframe) { _renderState.RasterizationMode = RasterizationMode.Line; } else { _renderState.RasterizationMode = RasterizationMode.Fill; } Vector3D previousTarget = sceneState.Camera.Target; Vector3D previousEye = sceneState.Camera.Eye; Vector3D previousSun = sceneState.SunPosition; _levelZeroWorldScaleFactor.Value = new Vector2F((float)_clipmapLevels[0].Terrain.PostDeltaLongitude, (float)_clipmapLevels[0].Terrain.PostDeltaLatitude); int maxLevel = _clipmapLevels.Length - 1; Vector2D center = new Vector2D(0.0, 0.0); bool rendered = false; for (int i = maxLevel; i >= 0; --i) { ClipmapLevel thisLevel = _clipmapLevels[i]; ClipmapLevel coarserLevel = _clipmapLevels[i > 0 ? i - 1 : 0]; rendered = RenderLevel(i, thisLevel, coarserLevel, !rendered, center, context, sceneState); } sceneState.Camera.Target = previousTarget; sceneState.Camera.Eye = previousEye; sceneState.SunPosition = previousSun; }
private void UpdateImageryOriginInTextures(ClipmapLevel level) { int deltaX = level.NextImageryExtent.West - level.CurrentImageryExtent.West; int deltaY = level.NextImageryExtent.South - level.CurrentImageryExtent.South; if (deltaX == 0 && deltaY == 0) { return; } if (level.CurrentImageryExtent.West > level.CurrentImageryExtent.East || // initial update Math.Abs(deltaX) >= level.ImageryWidth || Math.Abs(deltaY) >= level.ImageryHeight) // complete update { level.OriginInImagery = new Vector2I(0, 0); } else { int newOriginX = (level.OriginInImagery.X + deltaX) % level.ImageryWidth; if (newOriginX < 0) { newOriginX += level.ImageryWidth; } int newOriginY = (level.OriginInImagery.Y + deltaY) % level.ImageryHeight; if (newOriginY < 0) { newOriginY += level.ImageryHeight; } level.OriginInImagery = new Vector2I(newOriginX, newOriginY); } }
private void UpdateOriginInTextures(ClipmapLevel level) { int deltaX = level.NextExtent.West - level.CurrentExtent.West; int deltaY = level.NextExtent.South - level.CurrentExtent.South; if (deltaX == 0 && deltaY == 0) { return; } if (level.CurrentExtent.West > level.CurrentExtent.East || // initial update Math.Abs(deltaX) >= _clipmapPosts || Math.Abs(deltaY) >= _clipmapPosts) // complete update { level.OriginInTextures = new Vector2I(0, 0); } else { int newOriginX = (level.OriginInTextures.X + deltaX) % _clipmapPosts; if (newOriginX < 0) { newOriginX += _clipmapPosts; } int newOriginY = (level.OriginInTextures.Y + deltaY) % _clipmapPosts; if (newOriginY < 0) { newOriginY += _clipmapPosts; } level.OriginInTextures = new Vector2I(newOriginX, newOriginY); } }
private void UpdateNormals(Context context, ClipmapUpdate update) { ClipmapLevel level = update.Level; context.TextureUnits[0].Texture = update.Level.HeightTexture; context.TextureUnits[0].TextureSampler = Device.TextureSamplers.NearestRepeat; _framebuffer.ColorAttachments[_normalOutput] = level.NormalTexture; int clipmapSize = level.NextExtent.East - level.NextExtent.West + 1; int west = (level.OriginInTextures.X + (update.West - level.NextExtent.West)) % clipmapSize; int south = (level.OriginInTextures.Y + (update.South - level.NextExtent.South)) % clipmapSize; _computeNormalsUpdateSize.Value = new Vector2F(update.Width, update.Height); _computeNormalsOrigin.Value = new Vector2F(west, south); _computeNormalsOneOverHeightMapSize.Value = new Vector2F(1.0f / update.Level.HeightTexture.Description.Width, 1.0f / update.Level.HeightTexture.Description.Height); _postDelta.Value = (float)update.Level.Terrain.PostDeltaLongitude; // Save the current state of the context Rectangle oldViewport = context.Viewport; Framebuffer oldFramebuffer = context.Framebuffer; // Update the context and draw context.Viewport = new Rectangle(0, 0, level.NormalTexture.Description.Width, level.NormalTexture.Description.Height); context.Framebuffer = _framebuffer; context.Draw(_unitQuadPrimitiveType, _computeNormalsDrawState, _sceneState); // Restore the context to its original state context.Framebuffer = oldFramebuffer; context.Viewport = oldViewport; }
public ClipmapUpdate(ClipmapLevel level, int west, int south, int east, int north) { _level = level; _west = west; _south = south; _east = east; _north = north; }
private void ApplyIfNotLoaded(Context context, RasterDataDetails details, ClipmapLevel level, RasterTile tile) { Texture2D texture; if (!details.LoadedTiles.TryGetValue(tile.Identifier, out texture) || texture == null) { ApplyNewTile(context, details, level, tile); } }
public ClipmapUpdater(Context context, ClipmapLevel[] clipmapLevels) { ShaderVertexAttributeCollection vertexAttributes = new ShaderVertexAttributeCollection(); vertexAttributes.Add(new ShaderVertexAttribute("position", VertexLocations.Position, ShaderVertexAttributeType.FloatVector2, 1)); Mesh unitQuad = RectangleTessellator.Compute(new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(1.0, 1.0)), 1, 1); _unitQuad = context.CreateVertexArray(unitQuad, vertexAttributes, BufferHint.StaticDraw); _unitQuadPrimitiveType = unitQuad.PrimitiveType; _sceneState = new SceneState(); _framebuffer = context.CreateFramebuffer(); _updateShader = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpdateVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpdateFS.glsl")); _updateTexelOutput = _updateShader.FragmentOutputs["texelOutput"]; _updateDrawState = new DrawState(new RenderState(), _updateShader, _unitQuad); _updateDrawState.RenderState.FacetCulling.FrontFaceWindingOrder = unitQuad.FrontFaceWindingOrder; _updateDrawState.RenderState.DepthTest.Enabled = false; _updateDestinationOffset = (Uniform <Vector2F>)_updateShader.Uniforms["u_destinationOffset"]; _updateUpdateSize = (Uniform <Vector2F>)_updateShader.Uniforms["u_updateSize"]; _updateSourceOrigin = (Uniform <Vector2F>)_updateShader.Uniforms["u_sourceOrigin"]; _upsampleShader = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpsampleVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpsampleFS.glsl")); _upsampleTexelOutput = _upsampleShader.FragmentOutputs["texelOutput"]; _upsampleDrawState = new DrawState(new RenderState(), _upsampleShader, _unitQuad); _upsampleDrawState.RenderState.FacetCulling.FrontFaceWindingOrder = unitQuad.FrontFaceWindingOrder; _upsampleDrawState.RenderState.DepthTest.Enabled = false; _upsampleSourceOrigin = (Uniform <Vector2F>)_upsampleShader.Uniforms["u_sourceOrigin"]; _upsampleUpdateSize = (Uniform <Vector2F>)_upsampleShader.Uniforms["u_updateSize"]; _upsampleDestinationOffset = (Uniform <Vector2F>)_upsampleShader.Uniforms["u_destinationOffset"]; _upsampleOneOverTextureSize = (Uniform <Vector2F>)_upsampleShader.Uniforms["u_oneOverTextureSize"]; _computeNormalsShader = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapComputeNormalsVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapComputeNormalsFS.glsl")); _normalOutput = _computeNormalsShader.FragmentOutputs["normalOutput"]; _computeNormalsDrawState = new DrawState(new RenderState(), _computeNormalsShader, _unitQuad); _computeNormalsDrawState.RenderState.FacetCulling.FrontFaceWindingOrder = unitQuad.FrontFaceWindingOrder; _computeNormalsDrawState.RenderState.DepthTest.Enabled = false; _computeNormalsOrigin = (Uniform <Vector2F>)_computeNormalsShader.Uniforms["u_origin"]; _computeNormalsUpdateSize = (Uniform <Vector2F>)_computeNormalsShader.Uniforms["u_updateSize"]; _computeNormalsOneOverHeightMapSize = (Uniform <Vector2F>)_computeNormalsShader.Uniforms["u_oneOverHeightMapSize"]; _heightExaggeration = (Uniform <float>)_computeNormalsShader.Uniforms["u_heightExaggeration"]; _postDelta = (Uniform <float>)_computeNormalsShader.Uniforms["u_postDelta"]; HeightExaggeration = 1.0f; ClipmapLevel levelZero = clipmapLevels[0]; InitializeRequestThreads(context, _terrain, levelZero, levelZero.Terrain); InitializeRequestThreads(context, _imagery, levelZero, levelZero.Imagery); }
private void DrawBlock(VertexArray block, ClipmapLevel level, ClipmapLevel coarserLevel, int overallWest, int overallSouth, int blockWest, int blockSouth, Context context, SceneState sceneState) { int textureWest = blockWest - overallWest; int textureSouth = blockSouth - overallSouth; _patchOriginInClippedLevel.Value = new Vector2F(textureWest, textureSouth); DrawState drawState = new DrawState(_renderState, _shaderProgram, block); context.Draw(_primitiveType, drawState, sceneState); }
private void RequestTileResidency(Context context, ClipmapLevel level, RasterDataDetails details, RasterLevel rasterLevel, ClipmapLevel.Extent nextExtent) { RasterTileRegion[] tileRegions = rasterLevel.GetTilesInExtent(nextExtent.West, nextExtent.South, nextExtent.East, nextExtent.North); foreach (RasterTileRegion region in tileRegions) { if (!details.LoadedTiles.ContainsKey(region.Tile.Identifier)) { RequestTileLoad(details, level, region.Tile); } } }
public ClipmapUpdater(Context context, ClipmapLevel[] clipmapLevels) { ShaderVertexAttributeCollection vertexAttributes = new ShaderVertexAttributeCollection(); vertexAttributes.Add(new ShaderVertexAttribute("position", VertexLocations.Position, ShaderVertexAttributeType.FloatVector2, 1)); Mesh unitQuad = RectangleTessellator.Compute(new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(1.0, 1.0)), 1, 1); _unitQuad = context.CreateVertexArray(unitQuad, vertexAttributes, BufferHint.StaticDraw); _unitQuadPrimitiveType = unitQuad.PrimitiveType; _sceneState = new SceneState(); _framebuffer = context.CreateFramebuffer(); _updateShader = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpdateVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpdateFS.glsl")); _updateTexelOutput = _updateShader.FragmentOutputs["texelOutput"]; _updateDrawState = new DrawState(new RenderState(), _updateShader, _unitQuad); _updateDrawState.RenderState.FacetCulling.FrontFaceWindingOrder = unitQuad.FrontFaceWindingOrder; _updateDrawState.RenderState.DepthTest.Enabled = false; _updateDestinationOffset = (Uniform<Vector2F>)_updateShader.Uniforms["u_destinationOffset"]; _updateUpdateSize = (Uniform<Vector2F>)_updateShader.Uniforms["u_updateSize"]; _updateSourceOrigin = (Uniform<Vector2F>)_updateShader.Uniforms["u_sourceOrigin"]; _upsampleShader = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpsampleVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapUpsampleFS.glsl")); _upsampleTexelOutput = _upsampleShader.FragmentOutputs["texelOutput"]; _upsampleDrawState = new DrawState(new RenderState(), _upsampleShader, _unitQuad); _upsampleDrawState.RenderState.FacetCulling.FrontFaceWindingOrder = unitQuad.FrontFaceWindingOrder; _upsampleDrawState.RenderState.DepthTest.Enabled = false; _upsampleSourceOrigin = (Uniform<Vector2F>)_upsampleShader.Uniforms["u_sourceOrigin"]; _upsampleUpdateSize = (Uniform<Vector2F>)_upsampleShader.Uniforms["u_updateSize"]; _upsampleDestinationOffset = (Uniform<Vector2F>)_upsampleShader.Uniforms["u_destinationOffset"]; _upsampleOneOverTextureSize = (Uniform<Vector2F>)_upsampleShader.Uniforms["u_oneOverTextureSize"]; _computeNormalsShader = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapComputeNormalsVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.ClipmapComputeNormalsFS.glsl")); _normalOutput = _computeNormalsShader.FragmentOutputs["normalOutput"]; _computeNormalsDrawState = new DrawState(new RenderState(), _computeNormalsShader, _unitQuad); _computeNormalsDrawState.RenderState.FacetCulling.FrontFaceWindingOrder = unitQuad.FrontFaceWindingOrder; _computeNormalsDrawState.RenderState.DepthTest.Enabled = false; _computeNormalsOrigin = (Uniform<Vector2F>)_computeNormalsShader.Uniforms["u_origin"]; _computeNormalsUpdateSize = (Uniform<Vector2F>)_computeNormalsShader.Uniforms["u_updateSize"]; _computeNormalsOneOverHeightMapSize = (Uniform<Vector2F>)_computeNormalsShader.Uniforms["u_oneOverHeightMapSize"]; _heightExaggeration = (Uniform<float>)_computeNormalsShader.Uniforms["u_heightExaggeration"]; _postDelta = (Uniform<float>)_computeNormalsShader.Uniforms["u_postDelta"]; HeightExaggeration = 1.0f; ClipmapLevel levelZero = clipmapLevels[0]; InitializeRequestThreads(context, _terrain, levelZero, levelZero.Terrain); InitializeRequestThreads(context, _imagery, levelZero, levelZero.Imagery); }
private void RequestTileLoad(RasterDataDetails details, ClipmapLevel level, RasterTile tile) { LinkedListNode <TileLoadRequest> requestNode; bool exists = details.LoadingTiles.TryGetValue(tile.Identifier, out requestNode); if (!exists) { // Create a new request. TileLoadRequest request = new TileLoadRequest(); request.Level = level; request.Tile = tile; requestNode = new LinkedListNode <TileLoadRequest>(request); } lock (details.RequestList) { if (exists) { // Remove the existing request from the queue so we can re-insert it // in its new location. if (requestNode.List == null) { // Request was in the queue at one point, but it's not anymore. // That means it's been loaded, so we don't need to do anything. return; } details.RequestList.Remove(requestNode); } if (details.RequestInsertionPoint == null || details.RequestInsertionPoint.List == null) { details.RequestList.AddLast(requestNode); } else { details.RequestList.AddBefore(details.RequestInsertionPoint, requestNode); } details.RequestInsertionPoint = requestNode; // If the request list has too many entries, delete from the beginning const int MaxRequests = 500; while (details.RequestList.Count > MaxRequests) { LinkedListNode <TileLoadRequest> nodeToRemove = details.RequestList.First; details.RequestList.RemoveFirst(); details.LoadingTiles.Remove(nodeToRemove.Value.Tile.Identifier); } Monitor.Pulse(details.RequestList); } details.LoadingTiles[tile.Identifier] = requestNode; }
private void RenderTileToLevelTexture(Context context, ClipmapLevel level, RasterDataDetails details, RasterTileRegion region, Texture2D tileTexture) { Texture2D levelTexture; Vector2I originInTextures; ClipmapLevel.Extent nextExtent; if (details.Type == RasterType.Terrain) { levelTexture = level.HeightTexture; originInTextures = level.OriginInTextures; nextExtent = level.NextExtent; } else { levelTexture = level.ImageryTexture; originInTextures = level.OriginInImagery; nextExtent = level.NextImageryExtent; } context.TextureUnits[0].Texture = tileTexture; context.TextureUnits[0].TextureSampler = Device.TextureSamplers.NearestClamp; _framebuffer.ColorAttachments[_updateTexelOutput] = levelTexture; int clipmapSize = nextExtent.East - nextExtent.West + 1; int destWest = (originInTextures.X + (region.Tile.West + region.West - nextExtent.West)) % clipmapSize; int destSouth = (originInTextures.Y + (region.Tile.South + region.South - nextExtent.South)) % clipmapSize; int width = region.East - region.West + 1; int height = region.North - region.South + 1; _updateSourceOrigin.Value = new Vector2F(region.West, region.South); _updateUpdateSize.Value = new Vector2F(width, height); _updateDestinationOffset.Value = new Vector2F(destWest, destSouth); // Save the current state of the context Rectangle oldViewport = context.Viewport; Framebuffer oldFramebuffer = context.Framebuffer; // Update the context and draw context.Viewport = new Rectangle(0, 0, levelTexture.Description.Width, levelTexture.Description.Height); context.Framebuffer = _framebuffer; context.Draw(_unitQuadPrimitiveType, _updateDrawState, _sceneState); // Restore the context to its original state context.Framebuffer = oldFramebuffer; context.Viewport = oldViewport; }
private void InitializeRequestThreads(Context context, RasterDataDetails details, ClipmapLevel clipmapLevelZero, RasterLevel rasterLevelZero) { details.WorkerWindow = Device.CreateWindow(1, 1); context.MakeCurrent(); #if !SingleThreaded Thread requestThread = new Thread(RequestThreadEntryPoint); requestThread.IsBackground = true; requestThread.Start(details); #endif // Preload the entire world at level 0 RasterTileRegion[] regions = rasterLevelZero.GetTilesInExtent(0, 0, rasterLevelZero.LongitudePosts - 1, rasterLevelZero.LatitudePosts - 1); foreach (RasterTileRegion region in regions) { RequestTileLoad(details, clipmapLevelZero, region.Tile); } }
private void ApplyNewTile(Context context, RasterDataDetails details, ClipmapLevel level, RasterTile tile) { ClipmapLevel.Extent nextExtent = details.Type == RasterType.Terrain ? level.NextExtent : level.NextImageryExtent; RasterLevel rasterLevel = details.Type == RasterType.Terrain ? level.Terrain : level.Imagery; ClipmapUpdate entireLevel = new ClipmapUpdate( level, nextExtent.West, nextExtent.South, nextExtent.East, nextExtent.North); ClipmapUpdate thisTile = new ClipmapUpdate( level, tile.West - 1, tile.South - 1, tile.East + 1, tile.North + 1); ClipmapUpdate intersection = IntersectUpdates(entireLevel, thisTile); if (intersection.Width > 0 && intersection.Height > 0) { Update(context, intersection, level, details, rasterLevel); // Recurse on child tiles if they're NOT loaded. Unloaded children will use data from this tile. ClipmapLevel finer = level.FinerLevel; if (finer != null) { ApplyIfNotLoaded(context, details, finer, tile.SouthwestChild); ApplyIfNotLoaded(context, details, finer, tile.SoutheastChild); ApplyIfNotLoaded(context, details, finer, tile.NorthwestChild); ApplyIfNotLoaded(context, details, finer, tile.NortheastChild); } } }
private ClipmapUpdate[] SplitUpdateToAvoidWrapping(ClipmapUpdate update, RasterDataDetails details) { ClipmapLevel level = update.Level; Vector2I origin = details.Type == RasterType.Terrain ? level.OriginInTextures : level.OriginInImagery; ClipmapLevel.Extent extent = details.Type == RasterType.Terrain ? level.NextExtent : level.NextImageryExtent; int clipmapSizeX = extent.East - extent.West + 1; int clipmapSizeY = extent.North - extent.South + 1; int west = (origin.X + (update.West - extent.West)) % clipmapSizeX; int east = (origin.X + (update.East - extent.West)) % clipmapSizeX; int south = (origin.Y + (update.South - extent.South)) % clipmapSizeY; int north = (origin.Y + (update.North - extent.South)) % clipmapSizeY; if (east < west && north < south) { // Horizontal AND vertical wrap ClipmapUpdate bottomLeftUpdate = new ClipmapUpdate( level, update.West, update.South, extent.West + (clipmapSizeX - origin.X - 1), extent.South + (clipmapSizeY - origin.Y - 1)); ClipmapUpdate bottomRightUpdate = new ClipmapUpdate( level, extent.West + clipmapSizeX - origin.X, update.South, update.East, extent.South + (clipmapSizeY - origin.Y - 1)); ClipmapUpdate topLeftUpdate = new ClipmapUpdate( level, update.West, extent.South + clipmapSizeY - origin.Y, extent.West + (clipmapSizeX - origin.X - 1), update.North); ClipmapUpdate topRightUpdate = new ClipmapUpdate( level, extent.West + clipmapSizeX - origin.X, extent.South + clipmapSizeY - origin.Y, update.East, update.North); ClipmapUpdate[] result = new ClipmapUpdate[4]; result[0] = bottomLeftUpdate; result[1] = bottomRightUpdate; result[2] = topLeftUpdate; result[3] = topRightUpdate; return(result); } else if (east < west) { // Horizontal wrap ClipmapUpdate leftUpdate = new ClipmapUpdate( level, update.West, update.South, extent.West + (clipmapSizeX - origin.X - 1), update.North); ClipmapUpdate rightUpdate = new ClipmapUpdate( level, extent.West + clipmapSizeX - origin.X, update.South, update.East, update.North); ClipmapUpdate[] result = new ClipmapUpdate[2]; result[0] = leftUpdate; result[1] = rightUpdate; return(result); } else if (north < south) { // Vertical wrap ClipmapUpdate bottomUpdate = new ClipmapUpdate( level, update.West, update.South, update.East, extent.South + (clipmapSizeY - origin.Y - 1)); ClipmapUpdate topUpdate = new ClipmapUpdate( level, update.West, extent.South + clipmapSizeY - origin.Y, update.East, update.North); ClipmapUpdate[] result = new ClipmapUpdate[2]; result[0] = bottomUpdate; result[1] = topUpdate; return(result); } else { // No wrap ClipmapUpdate[] result = new ClipmapUpdate[1]; result[0] = update; return(result); } }
public void RequestTileResidency(Context context, ClipmapLevel level) { RequestTileResidency(context, level, _terrain, level.Terrain, level.NextExtent); RequestTileResidency(context, level, _imagery, level.Imagery, level.NextImageryExtent); }
public void UpdateImagery(Context context, ClipmapUpdate update) { ClipmapLevel level = update.Level; Update(context, update, level, _imagery, level.Imagery); }
private bool RenderLevel(int levelIndex, ClipmapLevel level, ClipmapLevel coarserLevel, bool fillRing, Vector2D center, Context context, SceneState sceneState) { context.TextureUnits[0].Texture = level.HeightTexture; context.TextureUnits[0].TextureSampler = Device.TextureSamplers.NearestRepeat; context.TextureUnits[1].Texture = coarserLevel.HeightTexture; context.TextureUnits[1].TextureSampler = Device.TextureSamplers.LinearRepeat; context.TextureUnits[2].Texture = level.NormalTexture; context.TextureUnits[2].TextureSampler = Device.TextureSamplers.LinearRepeat; context.TextureUnits[3].Texture = coarserLevel.NormalTexture; context.TextureUnits[3].TextureSampler = Device.TextureSamplers.LinearRepeat; context.TextureUnits[4].Texture = level.ImageryTexture; context.TextureUnits[4].TextureSampler = Device.TextureSamplers.LinearRepeat; if (_colorClipmapLevels) { _color.Value = _colors[levelIndex]; _blendRegionColor.Value = levelIndex == 0 ? _colors[levelIndex] : _colors[levelIndex - 1]; } else { _color.Value = new Vector3F(0.0f, 1.0f, 0.0f); _blendRegionColor.Value = new Vector3F(0.0f, 0.0f, 1.0f); } int west = level.CurrentExtent.West; int south = level.CurrentExtent.South; int east = level.CurrentExtent.East; int north = level.CurrentExtent.North; float levelScaleFactor = (float)Math.Pow(2.0, -levelIndex); _levelScaleFactor.Value = new Vector2F(levelScaleFactor, levelScaleFactor); _levelOffsetFromWorldOrigin.Value = new Vector2F((float)((double)level.CurrentExtent.West - level.Terrain.LongitudeToIndex(0.0)), (float)((double)level.CurrentExtent.South - level.Terrain.LatitudeToIndex(0.0))); int coarserWest = coarserLevel.CurrentExtent.West; int coarserSouth = coarserLevel.CurrentExtent.South; _fineLevelOriginInCoarse.Value = coarserLevel.OriginInTextures.ToVector2F() + new Vector2F(west / 2 - coarserWest + 0.5f, south / 2 - coarserSouth + 0.5f); _viewPosInClippedLevel.Value = new Vector2F((float)(level.Terrain.LongitudeToIndex(Trig.ToDegrees(_clipmapCenter.Longitude)) - level.CurrentExtent.West), (float)(level.Terrain.LatitudeToIndex(Trig.ToDegrees(_clipmapCenter.Latitude)) - level.CurrentExtent.South)); _fineTextureOrigin.Value = level.OriginInTextures.ToVector2F() + new Vector2F(0.5f, 0.5f); _useBlendRegions.Value = _blendRegionsEnabled && level != coarserLevel; _terrainToImageryResolutionRatio.Value = new Vector2F((float)(level.Terrain.PostDeltaLongitude / level.Imagery.PostDeltaLongitude), (float)(level.Terrain.PostDeltaLatitude / level.Imagery.PostDeltaLatitude)); double terrainWest = level.Terrain.IndexToLongitude(level.CurrentExtent.West); double terrainSouth = level.Terrain.IndexToLatitude(level.CurrentExtent.South); double imageryWestIndex = level.Imagery.LongitudeToIndex(terrainWest); double imagerySouthIndex = level.Imagery.LatitudeToIndex(terrainSouth); Vector2D terrainOffsetInImagery = level.OriginInImagery.ToVector2D() + new Vector2D(imageryWestIndex - level.CurrentImageryExtent.West, imagerySouthIndex - level.CurrentImageryExtent.South); _terrainOffsetInImagery.Value = terrainOffsetInImagery.ToVector2F(); _oneOverImagerySize.Value = new Vector2F((float)(1.0 / level.ImageryWidth), (float)(1.0 / level.ImageryHeight)); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - 2 * _fillPatchSegments, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, north - 2 * _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, north - 2 * _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, north - _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - 2 * _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, west, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, east - _fillPatchSegments, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_degenerateTrianglePatch, level, coarserLevel, west, south, west, south, context, sceneState); // Fill the center of the highest-detail ring if (fillRing) { DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + 2 * _fillPatchPosts, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south + 2 * _fillPatchPosts, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + 2 * _fillPatchPosts, south + 2 * _fillPatchPosts, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchPosts, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south + _fillPatchSegments, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south + 2 * _fillPatchPosts, context, sceneState); DrawBlock(_centerPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south + 2 * _fillPatchSegments, context, sceneState); } else { int offset = level.OffsetStripOnNorth ? north - _fillPatchPosts : south + _fillPatchSegments; DrawBlock(_horizontalOffsetPatch, level, coarserLevel, west, south, west + _fillPatchSegments, offset, context, sceneState); int southOffset = level.OffsetStripOnNorth ? 0 : 1; offset = level.OffsetStripOnEast ? east - _fillPatchPosts : west + _fillPatchSegments; DrawBlock(_verticalOffsetPatch, level, coarserLevel, west, south, offset, south + _fillPatchSegments + southOffset, context, sceneState); } return(true); }
private void UpdateImageryOriginInTextures(ClipmapLevel level) { int deltaX = level.NextImageryExtent.West - level.CurrentImageryExtent.West; int deltaY = level.NextImageryExtent.South - level.CurrentImageryExtent.South; if (deltaX == 0 && deltaY == 0) return; if (level.CurrentImageryExtent.West > level.CurrentImageryExtent.East || // initial update Math.Abs(deltaX) >= level.ImageryWidth || Math.Abs(deltaY) >= level.ImageryHeight) // complete update { level.OriginInImagery = new Vector2I(0, 0); } else { int newOriginX = (level.OriginInImagery.X + deltaX) % level.ImageryWidth; if (newOriginX < 0) newOriginX += level.ImageryWidth; int newOriginY = (level.OriginInImagery.Y + deltaY) % level.ImageryHeight; if (newOriginY < 0) newOriginY += level.ImageryHeight; level.OriginInImagery = new Vector2I(newOriginX, newOriginY); } }
public GlobeClipmapTerrain(Context context, RasterSource terrainSource, EsriRestImagery imagery, Ellipsoid ellipsoid, int clipmapPosts) { _terrainSource = terrainSource; _ellipsoid = ellipsoid; _clipmapPosts = clipmapPosts; _clipmapSegments = _clipmapPosts - 1; int clipmapLevels = _terrainSource.Levels.Count; _clipmapLevels = new ClipmapLevel[clipmapLevels]; for (int i = 0; i < _clipmapLevels.Length; ++i) { _clipmapLevels[i] = new ClipmapLevel(); } for (int i = 0; i < _clipmapLevels.Length; ++i) { RasterLevel terrainLevel = _terrainSource.Levels[i]; _clipmapLevels[i].Terrain = terrainLevel; _clipmapLevels[i].HeightTexture = Device.CreateTexture2D(new Texture2DDescription(_clipmapPosts, _clipmapPosts, TextureFormat.Red32f)); _clipmapLevels[i].NormalTexture = Device.CreateTexture2D(new Texture2DDescription(_clipmapPosts, _clipmapPosts, TextureFormat.RedGreenBlue32f)); _clipmapLevels[i].CoarserLevel = i == 0 ? null : _clipmapLevels[i - 1]; _clipmapLevels[i].FinerLevel = i == _clipmapLevels.Length - 1 ? null : _clipmapLevels[i + 1]; // Aim for roughly one imagery texel per geometry texel. // Find the first imagery level that meets our resolution needs. double longitudeResRequired = terrainLevel.PostDeltaLongitude; double latitudeResRequired = terrainLevel.PostDeltaLatitude; RasterLevel imageryLevel = null; for (int j = 0; j < imagery.Levels.Count; ++j) { imageryLevel = imagery.Levels[j]; if (imageryLevel.PostDeltaLongitude <= longitudeResRequired && imageryLevel.PostDeltaLatitude <= latitudeResRequired) { break; } } _clipmapLevels[i].Imagery = imageryLevel; _clipmapLevels[i].ImageryWidth = (int)Math.Ceiling(_clipmapPosts * terrainLevel.PostDeltaLongitude / imageryLevel.PostDeltaLongitude); _clipmapLevels[i].ImageryHeight = (int)Math.Ceiling(_clipmapPosts * terrainLevel.PostDeltaLatitude / imageryLevel.PostDeltaLatitude); _clipmapLevels[i].ImageryTexture = Device.CreateTexture2D(new Texture2DDescription(_clipmapLevels[i].ImageryWidth, _clipmapLevels[i].ImageryHeight, TextureFormat.RedGreenBlue8, false)); } _shaderProgram = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.GlobeClipmapVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.GlobeClipmapFS.glsl")); _fillPatchPosts = (clipmapPosts + 1) / 4; // M _fillPatchSegments = _fillPatchPosts - 1; // Create the MxM block used to fill the ring and the field. Mesh fieldBlockMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(_fillPatchSegments, _fillPatchSegments)), _fillPatchSegments, _fillPatchSegments); _fillPatch = context.CreateVertexArray(fieldBlockMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); // Create the Mx3 block used to fill the space between the MxM blocks in the ring Mesh ringFixupHorizontalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(_fillPatchSegments, 2.0)), _fillPatchSegments, 2); _horizontalFixupPatch = context.CreateVertexArray(ringFixupHorizontalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); // Create the 3xM block used to fill the space between the MxM blocks in the ring Mesh ringFixupVerticalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(2.0, _fillPatchSegments)), 2, _fillPatchSegments); _verticalFixupPatch = context.CreateVertexArray(ringFixupVerticalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh offsetStripHorizontalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(2 * _fillPatchPosts, 1.0)), 2 * _fillPatchPosts, 1); _horizontalOffsetPatch = context.CreateVertexArray(offsetStripHorizontalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh offsetStripVerticalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(1.0, 2 * _fillPatchPosts - 1)), 1, 2 * _fillPatchPosts - 1); _verticalOffsetPatch = context.CreateVertexArray(offsetStripVerticalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh centerMesh = RectangleTessellator.Compute(new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(2.0, 2.0)), 2, 2); _centerPatch = context.CreateVertexArray(centerMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh degenerateTriangleMesh = CreateDegenerateTriangleMesh(); _degenerateTrianglePatch = context.CreateVertexArray(degenerateTriangleMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); _patchOriginInClippedLevel = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_patchOriginInClippedLevel"]; _levelScaleFactor = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_levelScaleFactor"]; _levelZeroWorldScaleFactor = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_levelZeroWorldScaleFactor"]; _levelOffsetFromWorldOrigin = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_levelOffsetFromWorldOrigin"]; _heightExaggeration = (Uniform<float>)_shaderProgram.Uniforms["u_heightExaggeration"]; _viewPosInClippedLevel = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_viewPosInClippedLevel"]; _fineLevelOriginInCoarse = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_fineLevelOriginInCoarse"]; _unblendedRegionSize = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_unblendedRegionSize"]; _oneOverBlendedRegionSize = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_oneOverBlendedRegionSize"]; _fineTextureOrigin = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_fineTextureOrigin"]; _showBlendRegions = (Uniform<bool>)_shaderProgram.Uniforms["u_showBlendRegions"]; _useBlendRegions = (Uniform<bool>)_shaderProgram.Uniforms["u_useBlendRegions"]; _oneOverClipmapSize = (Uniform<float>)_shaderProgram.Uniforms["u_oneOverClipmapSize"]; _color = (Uniform<Vector3F>)_shaderProgram.Uniforms["u_color"]; _blendRegionColor = (Uniform<Vector3F>)_shaderProgram.Uniforms["u_blendRegionColor"]; _terrainToImageryResolutionRatio = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_terrainToImageryResolutionRatio"]; _terrainOffsetInImagery = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_terrainOffsetInImagery"]; _oneOverImagerySize = (Uniform<Vector2F>)_shaderProgram.Uniforms["u_oneOverImagerySize"]; _showImagery = (Uniform<bool>)_shaderProgram.Uniforms["u_showImagery"]; _lighting = (Uniform<bool>)_shaderProgram.Uniforms["u_shade"]; ((Uniform<Vector3F>)_shaderProgram.Uniforms["u_globeRadiiSquared"]).Value = ellipsoid.RadiiSquared.ToVector3F(); _renderState = new RenderState(); _renderState.FacetCulling.FrontFaceWindingOrder = fieldBlockMesh.FrontFaceWindingOrder; _primitiveType = fieldBlockMesh.PrimitiveType; float oneOverBlendedRegionSize = (float)(10.0 / _clipmapPosts); _oneOverBlendedRegionSize.Value = new Vector2F(oneOverBlendedRegionSize, oneOverBlendedRegionSize); float unblendedRegionSize = (float)(_clipmapSegments / 2 - _clipmapPosts / 10.0 - 1); _unblendedRegionSize.Value = new Vector2F(unblendedRegionSize, unblendedRegionSize); _useBlendRegions.Value = true; _showImagery.Value = true; _oneOverClipmapSize.Value = 1.0f / clipmapPosts; _updater = new ClipmapUpdater(context, _clipmapLevels); HeightExaggeration = 0.00001f; }
private void UpsampleTileData(Context context, ClipmapLevel level, RasterDataDetails details, RasterTileRegion region) { ClipmapLevel coarserLevel = level.CoarserLevel; if (coarserLevel == null) { return; } Texture2D levelTexture; Texture2D coarserLevelTexture; Vector2I originInTextures; Vector2I coarserOriginInTextures; ClipmapLevel.Extent nextExtent; ClipmapLevel.Extent coarserNextExtent; if (details.Type == RasterType.Terrain) { levelTexture = level.HeightTexture; coarserLevelTexture = coarserLevel.HeightTexture; originInTextures = level.OriginInTextures; coarserOriginInTextures = coarserLevel.OriginInTextures; nextExtent = level.NextExtent; coarserNextExtent = coarserLevel.NextExtent; } else { levelTexture = level.ImageryTexture; coarserLevelTexture = coarserLevel.ImageryTexture; originInTextures = level.OriginInImagery; coarserOriginInTextures = coarserLevel.OriginInImagery; nextExtent = level.NextImageryExtent; coarserNextExtent = coarserLevel.NextImageryExtent; } context.TextureUnits[0].Texture = coarserLevelTexture; context.TextureUnits[0].TextureSampler = Device.TextureSamplers.LinearRepeat; _framebuffer.ColorAttachments[_upsampleTexelOutput] = levelTexture; int fineClipmapSize = nextExtent.East - nextExtent.West + 1; int destWest = (originInTextures.X + (region.Tile.West + region.West - nextExtent.West)) % fineClipmapSize; int destSouth = (originInTextures.Y + (region.Tile.South + region.South - nextExtent.South)) % fineClipmapSize; int coarseClipmapSize = coarserNextExtent.East - coarserNextExtent.West + 1; double sourceWest = (coarserOriginInTextures.X + ((region.Tile.West + region.West) / 2.0 - coarserNextExtent.West)) % coarseClipmapSize; double sourceSouth = (coarserOriginInTextures.Y + ((region.Tile.South + region.South) / 2.0 - coarserNextExtent.South)) % coarseClipmapSize; int width = region.East - region.West + 1; int height = region.North - region.South + 1; _upsampleSourceOrigin.Value = new Vector2F((float)sourceWest, (float)sourceSouth); _upsampleUpdateSize.Value = new Vector2F(width, height); _upsampleDestinationOffset.Value = new Vector2F(destWest, destSouth); _upsampleOneOverTextureSize.Value = new Vector2F(1.0f / coarserLevelTexture.Description.Width, 1.0f / coarserLevelTexture.Description.Height); // Save the current state of the context Rectangle oldViewport = context.Viewport; Framebuffer oldFramebuffer = context.Framebuffer; // Update the context and draw context.Viewport = new Rectangle(0, 0, levelTexture.Description.Width, levelTexture.Description.Height); context.Framebuffer = _framebuffer; context.Draw(_unitQuadPrimitiveType, _upsampleDrawState, _sceneState); // Restore the context to its original state context.Framebuffer = oldFramebuffer; context.Viewport = oldViewport; }
public GlobeClipmapTerrain(Context context, RasterSource terrainSource, EsriRestImagery imagery, Ellipsoid ellipsoid, int clipmapPosts) { _terrainSource = terrainSource; _ellipsoid = ellipsoid; _clipmapPosts = clipmapPosts; _clipmapSegments = _clipmapPosts - 1; int clipmapLevels = _terrainSource.Levels.Count; _clipmapLevels = new ClipmapLevel[clipmapLevels]; for (int i = 0; i < _clipmapLevels.Length; ++i) { _clipmapLevels[i] = new ClipmapLevel(); } for (int i = 0; i < _clipmapLevels.Length; ++i) { RasterLevel terrainLevel = _terrainSource.Levels[i]; _clipmapLevels[i].Terrain = terrainLevel; _clipmapLevels[i].HeightTexture = Device.CreateTexture2D(new Texture2DDescription(_clipmapPosts, _clipmapPosts, TextureFormat.Red32f)); _clipmapLevels[i].NormalTexture = Device.CreateTexture2D(new Texture2DDescription(_clipmapPosts, _clipmapPosts, TextureFormat.RedGreenBlue32f)); _clipmapLevels[i].CoarserLevel = i == 0 ? null : _clipmapLevels[i - 1]; _clipmapLevels[i].FinerLevel = i == _clipmapLevels.Length - 1 ? null : _clipmapLevels[i + 1]; // Aim for roughly one imagery texel per geometry texel. // Find the first imagery level that meets our resolution needs. double longitudeResRequired = terrainLevel.PostDeltaLongitude; double latitudeResRequired = terrainLevel.PostDeltaLatitude; RasterLevel imageryLevel = null; for (int j = 0; j < imagery.Levels.Count; ++j) { imageryLevel = imagery.Levels[j]; if (imageryLevel.PostDeltaLongitude <= longitudeResRequired && imageryLevel.PostDeltaLatitude <= latitudeResRequired) { break; } } _clipmapLevels[i].Imagery = imageryLevel; _clipmapLevels[i].ImageryWidth = (int)Math.Ceiling(_clipmapPosts * terrainLevel.PostDeltaLongitude / imageryLevel.PostDeltaLongitude); _clipmapLevels[i].ImageryHeight = (int)Math.Ceiling(_clipmapPosts * terrainLevel.PostDeltaLatitude / imageryLevel.PostDeltaLatitude); _clipmapLevels[i].ImageryTexture = Device.CreateTexture2D(new Texture2DDescription(_clipmapLevels[i].ImageryWidth, _clipmapLevels[i].ImageryHeight, TextureFormat.RedGreenBlue8, false)); } _shaderProgram = Device.CreateShaderProgram( EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.GlobeClipmapVS.glsl"), EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.ClipmapTerrain.GlobeClipmapFS.glsl")); _fillPatchPosts = (clipmapPosts + 1) / 4; // M _fillPatchSegments = _fillPatchPosts - 1; // Create the MxM block used to fill the ring and the field. Mesh fieldBlockMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(_fillPatchSegments, _fillPatchSegments)), _fillPatchSegments, _fillPatchSegments); _fillPatch = context.CreateVertexArray(fieldBlockMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); // Create the Mx3 block used to fill the space between the MxM blocks in the ring Mesh ringFixupHorizontalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(_fillPatchSegments, 2.0)), _fillPatchSegments, 2); _horizontalFixupPatch = context.CreateVertexArray(ringFixupHorizontalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); // Create the 3xM block used to fill the space between the MxM blocks in the ring Mesh ringFixupVerticalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(2.0, _fillPatchSegments)), 2, _fillPatchSegments); _verticalFixupPatch = context.CreateVertexArray(ringFixupVerticalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh offsetStripHorizontalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(2 * _fillPatchPosts, 1.0)), 2 * _fillPatchPosts, 1); _horizontalOffsetPatch = context.CreateVertexArray(offsetStripHorizontalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh offsetStripVerticalMesh = RectangleTessellator.Compute( new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(1.0, 2 * _fillPatchPosts - 1)), 1, 2 * _fillPatchPosts - 1); _verticalOffsetPatch = context.CreateVertexArray(offsetStripVerticalMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh centerMesh = RectangleTessellator.Compute(new RectangleD(new Vector2D(0.0, 0.0), new Vector2D(2.0, 2.0)), 2, 2); _centerPatch = context.CreateVertexArray(centerMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); Mesh degenerateTriangleMesh = CreateDegenerateTriangleMesh(); _degenerateTrianglePatch = context.CreateVertexArray(degenerateTriangleMesh, _shaderProgram.VertexAttributes, BufferHint.StaticDraw); _patchOriginInClippedLevel = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_patchOriginInClippedLevel"]; _levelScaleFactor = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_levelScaleFactor"]; _levelZeroWorldScaleFactor = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_levelZeroWorldScaleFactor"]; _levelOffsetFromWorldOrigin = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_levelOffsetFromWorldOrigin"]; _heightExaggeration = (Uniform <float>)_shaderProgram.Uniforms["u_heightExaggeration"]; _viewPosInClippedLevel = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_viewPosInClippedLevel"]; _fineLevelOriginInCoarse = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_fineLevelOriginInCoarse"]; _unblendedRegionSize = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_unblendedRegionSize"]; _oneOverBlendedRegionSize = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_oneOverBlendedRegionSize"]; _fineTextureOrigin = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_fineTextureOrigin"]; _showBlendRegions = (Uniform <bool>)_shaderProgram.Uniforms["u_showBlendRegions"]; _useBlendRegions = (Uniform <bool>)_shaderProgram.Uniforms["u_useBlendRegions"]; _oneOverClipmapSize = (Uniform <float>)_shaderProgram.Uniforms["u_oneOverClipmapSize"]; _color = (Uniform <Vector3F>)_shaderProgram.Uniforms["u_color"]; _blendRegionColor = (Uniform <Vector3F>)_shaderProgram.Uniforms["u_blendRegionColor"]; _terrainToImageryResolutionRatio = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_terrainToImageryResolutionRatio"]; _terrainOffsetInImagery = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_terrainOffsetInImagery"]; _oneOverImagerySize = (Uniform <Vector2F>)_shaderProgram.Uniforms["u_oneOverImagerySize"]; _showImagery = (Uniform <bool>)_shaderProgram.Uniforms["u_showImagery"]; _lighting = (Uniform <bool>)_shaderProgram.Uniforms["u_shade"]; ((Uniform <Vector3F>)_shaderProgram.Uniforms["u_globeRadiiSquared"]).Value = ellipsoid.RadiiSquared.ToVector3F(); _renderState = new RenderState(); _renderState.FacetCulling.FrontFaceWindingOrder = fieldBlockMesh.FrontFaceWindingOrder; _primitiveType = fieldBlockMesh.PrimitiveType; float oneOverBlendedRegionSize = (float)(10.0 / _clipmapPosts); _oneOverBlendedRegionSize.Value = new Vector2F(oneOverBlendedRegionSize, oneOverBlendedRegionSize); float unblendedRegionSize = (float)(_clipmapSegments / 2 - _clipmapPosts / 10.0 - 1); _unblendedRegionSize.Value = new Vector2F(unblendedRegionSize, unblendedRegionSize); _useBlendRegions.Value = true; _showImagery.Value = true; _oneOverClipmapSize.Value = 1.0f / clipmapPosts; _updater = new ClipmapUpdater(context, _clipmapLevels); HeightExaggeration = 0.00001f; }
private void UpsampleTileData(Context context, ClipmapLevel level, RasterDataDetails details, RasterTileRegion region) { ClipmapLevel coarserLevel = level.CoarserLevel; if (coarserLevel == null) return; Texture2D levelTexture; Texture2D coarserLevelTexture; Vector2I originInTextures; Vector2I coarserOriginInTextures; ClipmapLevel.Extent nextExtent; ClipmapLevel.Extent coarserNextExtent; if (details.Type == RasterType.Terrain) { levelTexture = level.HeightTexture; coarserLevelTexture = coarserLevel.HeightTexture; originInTextures = level.OriginInTextures; coarserOriginInTextures = coarserLevel.OriginInTextures; nextExtent = level.NextExtent; coarserNextExtent = coarserLevel.NextExtent; } else { levelTexture = level.ImageryTexture; coarserLevelTexture = coarserLevel.ImageryTexture; originInTextures = level.OriginInImagery; coarserOriginInTextures = coarserLevel.OriginInImagery; nextExtent = level.NextImageryExtent; coarserNextExtent = coarserLevel.NextImageryExtent; } context.TextureUnits[0].Texture = coarserLevelTexture; context.TextureUnits[0].TextureSampler = Device.TextureSamplers.LinearRepeat; _framebuffer.ColorAttachments[_upsampleTexelOutput] = levelTexture; int fineClipmapSize = nextExtent.East - nextExtent.West + 1; int destWest = (originInTextures.X + (region.Tile.West + region.West - nextExtent.West)) % fineClipmapSize; int destSouth = (originInTextures.Y + (region.Tile.South + region.South - nextExtent.South)) % fineClipmapSize; int coarseClipmapSize = coarserNextExtent.East - coarserNextExtent.West + 1; double sourceWest = (coarserOriginInTextures.X + ((region.Tile.West + region.West) / 2.0 - coarserNextExtent.West)) % coarseClipmapSize; double sourceSouth = (coarserOriginInTextures.Y + ((region.Tile.South + region.South) / 2.0 - coarserNextExtent.South)) % coarseClipmapSize; int width = region.East - region.West + 1; int height = region.North - region.South + 1; _upsampleSourceOrigin.Value = new Vector2F((float)sourceWest, (float)sourceSouth); _upsampleUpdateSize.Value = new Vector2F(width, height); _upsampleDestinationOffset.Value = new Vector2F(destWest, destSouth); _upsampleOneOverTextureSize.Value = new Vector2F(1.0f / coarserLevelTexture.Description.Width, 1.0f / coarserLevelTexture.Description.Height); // Save the current state of the context Rectangle oldViewport = context.Viewport; Framebuffer oldFramebuffer = context.Framebuffer; // Update the context and draw context.Viewport = new Rectangle(0, 0, levelTexture.Description.Width, levelTexture.Description.Height); context.Framebuffer = _framebuffer; context.Draw(_unitQuadPrimitiveType, _upsampleDrawState, _sceneState); // Restore the context to its original state context.Framebuffer = oldFramebuffer; context.Viewport = oldViewport; }
private void RequestTileLoad(RasterDataDetails details, ClipmapLevel level, RasterTile tile) { LinkedListNode<TileLoadRequest> requestNode; bool exists = details.LoadingTiles.TryGetValue(tile.Identifier, out requestNode); if (!exists) { // Create a new request. TileLoadRequest request = new TileLoadRequest(); request.Level = level; request.Tile = tile; requestNode = new LinkedListNode<TileLoadRequest>(request); } lock (details.RequestList) { if (exists) { // Remove the existing request from the queue so we can re-insert it // in its new location. if (requestNode.List == null) { // Request was in the queue at one point, but it's not anymore. // That means it's been loaded, so we don't need to do anything. return; } details.RequestList.Remove(requestNode); } if (details.RequestInsertionPoint == null || details.RequestInsertionPoint.List == null) { details.RequestList.AddLast(requestNode); } else { details.RequestList.AddBefore(details.RequestInsertionPoint, requestNode); } details.RequestInsertionPoint = requestNode; // If the request list has too many entries, delete from the beginning const int MaxRequests = 500; while (details.RequestList.Count > MaxRequests) { LinkedListNode<TileLoadRequest> nodeToRemove = details.RequestList.First; details.RequestList.RemoveFirst(); details.LoadingTiles.Remove(nodeToRemove.Value.Tile.Identifier); } Monitor.Pulse(details.RequestList); } details.LoadingTiles[tile.Identifier] = requestNode; }
public void PreRender(Context context, SceneState sceneState) { if (!_lodUpdateEnabled) { return; } _clipmapCenter = _ellipsoid.ToGeodetic3D(sceneState.Camera.Eye); //Geodetic2D center = Ellipsoid.ScaledWgs84.ToGeodetic2D(sceneState.Camera.Target / Ellipsoid.Wgs84.MaximumRadius); Geodetic2D center = new Geodetic2D(_clipmapCenter.Longitude, _clipmapCenter.Latitude); double centerLongitude = Trig.ToDegrees(center.Longitude); double centerLatitude = Trig.ToDegrees(center.Latitude); ClipmapLevel level = _clipmapLevels[_clipmapLevels.Length - 1]; double longitudeIndex = level.Terrain.LongitudeToIndex(centerLongitude); double latitudeIndex = level.Terrain.LatitudeToIndex(centerLatitude); double imageryLongitudeIndex = level.Imagery.LongitudeToIndex(centerLongitude); double imageryLatitudeIndex = level.Imagery.LatitudeToIndex(centerLatitude); int west = (int)(longitudeIndex - _clipmapPosts / 2); if ((west % 2) != 0) { ++west; } int south = (int)(latitudeIndex - _clipmapPosts / 2); if ((south % 2) != 0) { ++south; } int imageryWest = (int)(imageryLongitudeIndex - level.ImageryWidth / 2); int imagerySouth = (int)(imageryLatitudeIndex - level.ImageryHeight / 2); level.NextExtent.West = west; level.NextExtent.East = west + _clipmapSegments; level.NextExtent.South = south; level.NextExtent.North = south + _clipmapSegments; level.NextImageryExtent.West = imageryWest; level.NextImageryExtent.East = imageryWest + level.ImageryWidth; level.NextImageryExtent.South = imagerySouth; level.NextImageryExtent.North = imagerySouth + level.ImageryHeight; UpdateOriginInTextures(level); UpdateImageryOriginInTextures(level); for (int i = _clipmapLevels.Length - 2; i >= 0; --i) { level = _clipmapLevels[i]; ClipmapLevel finerLevel = _clipmapLevels[i + 1]; // Terrain level.NextExtent.West = finerLevel.NextExtent.West / 2 - _fillPatchSegments; level.OffsetStripOnEast = (level.NextExtent.West % 2) == 0; if (!level.OffsetStripOnEast) { --level.NextExtent.West; } level.NextExtent.East = level.NextExtent.West + _clipmapSegments; level.NextExtent.South = finerLevel.NextExtent.South / 2 - _fillPatchSegments; level.OffsetStripOnNorth = (level.NextExtent.South % 2) == 0; if (!level.OffsetStripOnNorth) { --level.NextExtent.South; } level.NextExtent.North = level.NextExtent.South + _clipmapSegments; // Imagery imageryWest = (int)level.Imagery.LongitudeToIndex(level.Terrain.IndexToLongitude(level.NextExtent.West)); imagerySouth = (int)level.Imagery.LatitudeToIndex(level.Terrain.IndexToLatitude(level.NextExtent.South)); level.NextImageryExtent.West = imageryWest; level.NextImageryExtent.East = imageryWest + level.ImageryWidth - 1; level.NextImageryExtent.South = imagerySouth; level.NextImageryExtent.North = imagerySouth + level.ImageryHeight - 1; UpdateOriginInTextures(level); UpdateImageryOriginInTextures(level); } _updater.ApplyNewData(context); for (int i = 0; i < _clipmapLevels.Length; ++i) { ClipmapLevel thisLevel = _clipmapLevels[i]; ClipmapLevel coarserLevel = _clipmapLevels[i > 0 ? i - 1 : 0]; _updater.RequestTileResidency(context, thisLevel); UpdateTerrain(thisLevel, coarserLevel, context, sceneState); UpdateImagery(thisLevel, coarserLevel, context, sceneState); } }
private bool RenderLevel(int levelIndex, ClipmapLevel level, ClipmapLevel coarserLevel, bool fillRing, Vector2D center, Context context, SceneState sceneState) { context.TextureUnits[0].Texture = level.HeightTexture; context.TextureUnits[0].TextureSampler = Device.TextureSamplers.NearestRepeat; context.TextureUnits[1].Texture = coarserLevel.HeightTexture; context.TextureUnits[1].TextureSampler = Device.TextureSamplers.LinearRepeat; context.TextureUnits[2].Texture = level.NormalTexture; context.TextureUnits[2].TextureSampler = Device.TextureSamplers.LinearRepeat; context.TextureUnits[3].Texture = coarserLevel.NormalTexture; context.TextureUnits[3].TextureSampler = Device.TextureSamplers.LinearRepeat; context.TextureUnits[4].Texture = level.ImageryTexture; context.TextureUnits[4].TextureSampler = Device.TextureSamplers.LinearRepeat; if (_colorClipmapLevels) { _color.Value = _colors[levelIndex]; _blendRegionColor.Value = levelIndex == 0 ? _colors[levelIndex] : _colors[levelIndex - 1]; } else { _color.Value = new Vector3F(0.0f, 1.0f, 0.0f); _blendRegionColor.Value = new Vector3F(0.0f, 0.0f, 1.0f); } int west = level.CurrentExtent.West; int south = level.CurrentExtent.South; int east = level.CurrentExtent.East; int north = level.CurrentExtent.North; float levelScaleFactor = (float)Math.Pow(2.0, -levelIndex); _levelScaleFactor.Value = new Vector2F(levelScaleFactor, levelScaleFactor); _levelOffsetFromWorldOrigin.Value = new Vector2F((float)((double)level.CurrentExtent.West - level.Terrain.LongitudeToIndex(0.0)), (float)((double)level.CurrentExtent.South - level.Terrain.LatitudeToIndex(0.0))); int coarserWest = coarserLevel.CurrentExtent.West; int coarserSouth = coarserLevel.CurrentExtent.South; _fineLevelOriginInCoarse.Value = coarserLevel.OriginInTextures.ToVector2F() + new Vector2F(west / 2 - coarserWest + 0.5f, south / 2 - coarserSouth + 0.5f); _viewPosInClippedLevel.Value = new Vector2F((float)(level.Terrain.LongitudeToIndex(Trig.ToDegrees(_clipmapCenter.Longitude)) - level.CurrentExtent.West), (float)(level.Terrain.LatitudeToIndex(Trig.ToDegrees(_clipmapCenter.Latitude)) - level.CurrentExtent.South)); _fineTextureOrigin.Value = level.OriginInTextures.ToVector2F() + new Vector2F(0.5f, 0.5f); _useBlendRegions.Value = _blendRegionsEnabled && level != coarserLevel; _terrainToImageryResolutionRatio.Value = new Vector2F((float)(level.Terrain.PostDeltaLongitude / level.Imagery.PostDeltaLongitude), (float)(level.Terrain.PostDeltaLatitude / level.Imagery.PostDeltaLatitude)); double terrainWest = level.Terrain.IndexToLongitude(level.CurrentExtent.West); double terrainSouth = level.Terrain.IndexToLatitude(level.CurrentExtent.South); double imageryWestIndex = level.Imagery.LongitudeToIndex(terrainWest); double imagerySouthIndex = level.Imagery.LatitudeToIndex(terrainSouth); Vector2D terrainOffsetInImagery = level.OriginInImagery.ToVector2D() + new Vector2D(imageryWestIndex - level.CurrentImageryExtent.West, imagerySouthIndex - level.CurrentImageryExtent.South); _terrainOffsetInImagery.Value = terrainOffsetInImagery.ToVector2F(); _oneOverImagerySize.Value = new Vector2F((float)(1.0 / level.ImageryWidth), (float)(1.0 / level.ImageryHeight)); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - 2 * _fillPatchSegments, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, south, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, north - 2 * _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, north - 2 * _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west, north - _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - 2 * _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, east - _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, west, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, east - _fillPatchSegments, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, north - _fillPatchSegments, context, sceneState); DrawBlock(_degenerateTrianglePatch, level, coarserLevel, west, south, west, south, context, sceneState); // Fill the center of the highest-detail ring if (fillRing) { DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + 2 * _fillPatchPosts, south + _fillPatchSegments, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south + 2 * _fillPatchPosts, context, sceneState); DrawBlock(_fillPatch, level, coarserLevel, west, south, west + 2 * _fillPatchPosts, south + 2 * _fillPatchPosts, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, west + _fillPatchSegments, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_horizontalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchPosts, south + 2 * _fillPatchSegments, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south + _fillPatchSegments, context, sceneState); DrawBlock(_verticalFixupPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south + 2 * _fillPatchPosts, context, sceneState); DrawBlock(_centerPatch, level, coarserLevel, west, south, west + 2 * _fillPatchSegments, south + 2 * _fillPatchSegments, context, sceneState); } else { int offset = level.OffsetStripOnNorth ? north - _fillPatchPosts : south + _fillPatchSegments; DrawBlock(_horizontalOffsetPatch, level, coarserLevel, west, south, west + _fillPatchSegments, offset, context, sceneState); int southOffset = level.OffsetStripOnNorth ? 0 : 1; offset = level.OffsetStripOnEast ? east - _fillPatchPosts : west + _fillPatchSegments; DrawBlock(_verticalOffsetPatch, level, coarserLevel, west, south, offset, south + _fillPatchSegments + southOffset, context, sceneState); } return true; }
private void UpdateOriginInTextures(ClipmapLevel level) { int deltaX = level.NextExtent.West - level.CurrentExtent.West; int deltaY = level.NextExtent.South - level.CurrentExtent.South; if (deltaX == 0 && deltaY == 0) return; if (level.CurrentExtent.West > level.CurrentExtent.East || // initial update Math.Abs(deltaX) >= _clipmapPosts || Math.Abs(deltaY) >= _clipmapPosts) // complete update { level.OriginInTextures = new Vector2I(0, 0); } else { int newOriginX = (level.OriginInTextures.X + deltaX) % _clipmapPosts; if (newOriginX < 0) newOriginX += _clipmapPosts; int newOriginY = (level.OriginInTextures.Y + deltaY) % _clipmapPosts; if (newOriginY < 0) newOriginY += _clipmapPosts; level.OriginInTextures = new Vector2I(newOriginX, newOriginY); } }
private void UpdateImagery(ClipmapLevel level, ClipmapLevel coarserLevel, Context context, SceneState sceneState) { int deltaX = level.NextImageryExtent.West - level.CurrentImageryExtent.West; int deltaY = level.NextImageryExtent.South - level.CurrentImageryExtent.South; if (deltaX == 0 && deltaY == 0) return; int minLongitude = deltaX > 0 ? level.CurrentImageryExtent.East + 1 : level.NextImageryExtent.West; int maxLongitude = deltaX > 0 ? level.NextImageryExtent.East : level.CurrentImageryExtent.West - 1; int minLatitude = deltaY > 0 ? level.CurrentImageryExtent.North + 1 : level.NextImageryExtent.South; int maxLatitude = deltaY > 0 ? level.NextImageryExtent.North : level.CurrentImageryExtent.South - 1; int width = maxLongitude - minLongitude + 1; int height = maxLatitude - minLatitude + 1; if (level.CurrentImageryExtent.West > level.CurrentImageryExtent.East || // initial update width >= level.ImageryWidth || height >= level.ImageryHeight) // complete update { // Initial or complete update. width = level.ImageryWidth; height = level.ImageryHeight; deltaX = level.ImageryWidth; deltaY = level.ImageryHeight; minLongitude = level.NextImageryExtent.West; maxLongitude = level.NextImageryExtent.East; minLatitude = level.NextImageryExtent.South; maxLatitude = level.NextImageryExtent.North; } if (height > 0) { ClipmapUpdate horizontalUpdate = new ClipmapUpdate( level, level.NextImageryExtent.West, minLatitude, level.NextImageryExtent.East, maxLatitude); _updater.UpdateImagery(context, horizontalUpdate); } if (width > 0) { ClipmapUpdate verticalUpdate = new ClipmapUpdate( level, minLongitude, level.NextImageryExtent.South, maxLongitude, level.NextImageryExtent.North); _updater.UpdateImagery(context, verticalUpdate); } level.CurrentImageryExtent.West = level.NextImageryExtent.West; level.CurrentImageryExtent.South = level.NextImageryExtent.South; level.CurrentImageryExtent.East = level.NextImageryExtent.East; level.CurrentImageryExtent.North = level.NextImageryExtent.North; }
public void UpdateTerrain(Context context, ClipmapUpdate update) { ClipmapLevel level = update.Level; Update(context, update, level, _terrain, level.Terrain); }