//-------------------------------------------------------------- #region Methods //-------------------------------------------------------------- protected override void OnLoad() { // Get common services and game objects. _graphicsService = _services.GetInstance<IGraphicsService>(); var content = _services.GetInstance<ContentManager>(); var scene = _services.GetInstance<IScene>(); _simulation = _services.GetInstance<Simulation>(); var gameObjectService = _services.GetInstance<IGameObjectService>(); _cameraObject = gameObjectService.Objects.OfType<CameraObject>().First(); _previousCameraFar = _cameraObject.CameraNode.Camera.Projection.Far; // Create a new terrain. var terrain = new Terrain(); _terrainTile = new TerrainTile(_graphicsService) { CellSize = 2, }; terrain.Tiles.Add(_terrainTile); var shadowMapEffect = content.Load<Effect>("DigitalRune/Terrain/TerrainShadowMap"); var gBufferEffect = content.Load<Effect>("DigitalRune/Terrain/TerrainGBuffer"); var materialEffect = content.Load<Effect>("DigitalRune/Terrain/TerrainMaterial"); var material = new Material { { "ShadowMap", new EffectBinding(_graphicsService, shadowMapEffect, null, EffectParameterHint.Material) }, { "GBuffer", new EffectBinding(_graphicsService, gBufferEffect, null, EffectParameterHint.Material) }, { "Material", new EffectBinding(_graphicsService, materialEffect, null, EffectParameterHint.Material) } }; TerrainNode = new TerrainNode(terrain, material) { BaseClipmap = { CellsPerLevel = 128, NumberOfLevels = 6, }, DetailClipmap = { CellsPerLevel = 1364, NumberOfLevels = 9, }, }; scene.Children.Add(TerrainNode); // Create a rigid body with a height field for collision detection. var heightField = new HeightField { Depth = 1, UseFastCollisionApproximation = false, }; _rigidBody = new RigidBody(heightField, new MassFrame(), null) { MotionType = MotionType.Static, UserData = _terrainTile, }; _simulation.RigidBodies.Add(_rigidBody); InitializeHeightsAndNormals(); InitializeClipmapCellSizes(); InitializeTerrainLayers(content); // Enable mipmaps when using anisotropic filtering on AMD graphics cards: //TerrainNode.DetailClipmap.EnableMipMap = true; CreateGuiControls(); }
protected override void OnUnload() { _cameraObject = null; // Remove terrain from scene. TerrainNode.Parent.Children.Remove(TerrainNode); TerrainNode.Dispose(false); TerrainNode = null; // We have to dispose the textures which were not loaded via the content manager. _terrainTile.HeightTexture.SafeDispose(); _terrainTile.HeightTexture = null; _terrainTile.NormalTexture.SafeDispose(); _terrainTile.NormalTexture = null; _rigidBody.Simulation.RigidBodies.Remove(_rigidBody); _terrainTile = null; _rigidBody = null; }
//-------------------------------------------------------------- #region Methods //-------------------------------------------------------------- protected override void OnLoad() { // Get common services and game objects. _graphicsService = _services.GetInstance<IGraphicsService>(); _graphicsScreen = _graphicsService.Screens.OfType<DeferredGraphicsScreen>().First(); var content = _services.GetInstance<ContentManager>(); var scene = _services.GetInstance<IScene>(); _simulation = _services.GetInstance<Simulation>(); var gameObjectService = _services.GetInstance<IGameObjectService>(); _cameraObject = gameObjectService.Objects.OfType<CameraObject>().First(); _previousCameraFar = _cameraObject.CameraNode.Camera.Projection.Far; // Create a new terrain. var terrain = new Terrain(); // The terrain is made up of terrain tiles which can be loaded independently. // Each terrain tile consists of height and normal textures which define the terrain // geometry and terrain layers which define the material (detail textures). // In this sample we create 2x2 tiles. _tiles = new Tile[2, 2]; for (int row = 0; row < 2; row++) { for (int column = 0; column < 2; column++) { // Create a tile and add it to the terrain. // (The tile content is loaded later.) var terrainTile = new TerrainTile(_graphicsService) { CellSize = 1, // The terrain has a resolution of 1 height sample per world space unit. }; terrain.Tiles.Add(terrainTile); // Create a rigid body with a height field for collision detection and add // it to the simulation. (The height data is loaded later.) var heightField = new HeightField { Depth = 1, UseFastCollisionApproximation = false, }; var rigidBody = new RigidBody(heightField, new MassFrame(), null) { MotionType = MotionType.Static, UserData = terrainTile, }; _simulation.RigidBodies.Add(rigidBody); // Store the tile for use later in this sample. _tiles[row, column] = new Tile { TerrainTile = terrainTile, RigidBody = rigidBody, }; } } // Create a terrain node which represents the terrain in the scene graph. // The terrain node is rendered by the TerrainRenderer (see DeferredGraphicsScreen). // The material used to render the terrain is customizable. The material must specify // the effects for the different render passes which we use in the DeferredGraphicsScreen // ("ShadowMap", "GBuffer", "Material"). // The prebuilt DigitalRune content contains standard terrain effects. However, you could // change the effects to change how the material is rendered. // We can create the material by loading a .drmat file. Or we can create the material in // code like this: var shadowMapEffect = content.Load<Effect>("DigitalRune/Terrain/TerrainShadowMap"); var gBufferEffect = content.Load<Effect>("DigitalRune/Terrain/TerrainGBuffer"); var materialEffect = content.Load<Effect>("DigitalRune/Terrain/TerrainMaterial"); var material = new Material { { "ShadowMap", new EffectBinding(_graphicsService, shadowMapEffect, null, EffectParameterHint.Material) }, { "GBuffer", new EffectBinding(_graphicsService, gBufferEffect, null, EffectParameterHint.Material) }, { "Material", new EffectBinding(_graphicsService, materialEffect, null, EffectParameterHint.Material) } }; TerrainNode = new TerrainNode(terrain, material) { // The terrain rendering uses clipmaps. // The clipmaps are updated by the TerrainClipmapRenderer (see DeferredGraphicsScreen) // when the camera moves. // The base clipmap contains the basic geometry info (height, normals, hole info). // It also determines the terrain mesh resolution. BaseClipmap = { CellsPerLevel = 128, NumberOfLevels = 6 }, // The detail clipmap contains the splatted detail textures (e.g. grass, rock, ...). // (The max texture size in XNA is 4096x4096. That means we can fit 9 clipmap levels // into a single texture.) DetailClipmap = { CellsPerLevel = 1365, NumberOfLevels = 9, }, }; scene.Children.Add(TerrainNode); // Load the height and normal maps which define the terrain geometry. InitializeHeightsAndNormals(); // Set the clipmap cell sizes. InitializeClipmapCellSizes(); // Create the terrain layers which define the detail textures (e.g. grass, rock, ...) InitializeTerrainLayers(content); // Special note for AMD GPUs: // If we want anisotropic filtering for the terrain, then we need to enable mipmaps for // AMD GPUs. NVIDIA and Intel can do anisotropic filtering without mipmaps. //TerrainNode.DetailClipmap.EnableMipMap = true; CreateGuiControls(); }
/// <summary> /// Invalidates the specified terrain layer in the data cached by the renderer. /// </summary> /// <param name="tile">The terrain tile owning the terrain layer.</param> /// <param name="layer">The terrain layer which should be invalidated.</param> /// <inheritdoc cref="Invalidate()"/> /// <exception cref="ArgumentNullException"> /// <paramref name="tile"/> or <paramref name="layer"/> is <see langword="null"/>. /// </exception> public void Invalidate(TerrainTile tile, TerrainLayer layer) { if (tile == null) throw new ArgumentNullException("tile"); if (layer == null) throw new ArgumentNullException("layer"); UpdateAabb(); Aabb aabb = layer.Aabb ?? tile.Aabb; if (layer.Material.Contains(TerrainClipmapRenderer.RenderPassBase) && !RegionsContain(InvalidBaseRegions, aabb)) { InvalidBaseRegions.Add(aabb); // If there are 2 or more AABBs, then they need clipping. AreInvalidBaseRegionsClipped = (InvalidBaseRegions.Count == 1); } if (layer.Material.Contains(TerrainClipmapRenderer.RenderPassDetail) && !RegionsContain(InvalidDetailRegions, aabb)) { InvalidDetailRegions.Add(aabb); // If there are 2 or more AABBs, then they need clipping. AreInvalidDetailRegionsClipped = (InvalidDetailRegions.Count == 1); } }
/// <summary> /// Invalidates the specified terrain tile in the data cached by the renderer. /// </summary> /// <param name="tile">The terrain tile which should be invalidated.</param> /// <inheritdoc cref="Invalidate()"/> /// <exception cref="ArgumentNullException"> /// <paramref name="tile"/> is <see langword="null"/>. /// </exception> public void Invalidate(TerrainTile tile) { if (tile == null) throw new ArgumentNullException("tile"); UpdateAabb(); Invalidate(tile.Aabb); }
public TerrainTextureSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; _graphicsScreen = new DeferredGraphicsScreen(Services); _graphicsScreen.DrawReticle = true; GraphicsService.Screens.Insert(0, _graphicsScreen); GameObjectService.Objects.Add(new DeferredGraphicsOptionsObject(Services)); Services.Register(typeof(DebugRenderer), null, _graphicsScreen.DebugRenderer); var scene = _graphicsScreen.Scene; Services.Register(typeof(IScene), null, scene); // Add gravity and damping to the physics simulation. Simulation.ForceEffects.Add(new Gravity()); Simulation.ForceEffects.Add(new Damping()); // Add a custom game object which controls the camera. var cameraGameObject = new CameraObject(Services, 60); cameraGameObject.ResetPose(new Vector3F(0, 1.8f, 0), 0, 0); GameObjectService.Objects.Add(cameraGameObject); _graphicsScreen.ActiveCameraNode = cameraGameObject.CameraNode; for (int i = 0; i < 10; i++) GameObjectService.Objects.Add(new DynamicObject(Services, 1)); GameObjectService.Objects.Add(new DynamicSkyObject(Services, true, false, true)); // Create a simple flat terrain. var terrain = new Terrain(); _terrainTile = new TerrainTile(GraphicsService) { OriginX = -100, OriginZ = -100, CellSize = 1, }; terrain.Tiles.Add(_terrainTile); // Create a flat dummy height texture. float[] heights = new float[200 * 200]; Texture2D heightTexture = null; TerrainHelper.CreateHeightTexture( GraphicsService.GraphicsDevice, heights, 200, 200, false, ref heightTexture); _terrainTile.HeightTexture = heightTexture; var shadowMapEffect = ContentManager.Load<Effect>("DigitalRune/Terrain/TerrainShadowMap"); var gBufferEffect = ContentManager.Load<Effect>("DigitalRune/Terrain/TerrainGBuffer"); var materialEffect = ContentManager.Load<Effect>("DigitalRune/Terrain/TerrainMaterial"); var material = new Material { { "ShadowMap", new EffectBinding(GraphicsService, shadowMapEffect, null, EffectParameterHint.Material) }, { "GBuffer", new EffectBinding(GraphicsService, gBufferEffect, null, EffectParameterHint.Material) }, { "Material", new EffectBinding(GraphicsService, materialEffect, null, EffectParameterHint.Material) } }; var terrainNode = new TerrainNode(terrain, material) { DetailClipmap = { CellsPerLevel = 1364, NumberOfLevels = 9, EnableMipMap = true, }, }; scene.Children.Add(terrainNode); // Add 3 detail textures layers: gravel, rock, snow. float detailCellSize = terrainNode.DetailClipmap.CellSizes[0]; var materialGravel = new TerrainMaterialLayer(GraphicsService) { DiffuseTexture = ContentManager.Load<Texture2D>("Terrain/Gravel-Diffuse"), NormalTexture = ContentManager.Load<Texture2D>("Terrain/Gravel-Normal"), SpecularTexture = ContentManager.Load<Texture2D>("Terrain/Gravel-Specular"), TileSize = detailCellSize * 512, BlendRange = 0.1f, }; _terrainTile.Layers.Add(materialGravel); var noiseTexture = NoiseHelper.GetNoiseTexture(GraphicsService, 128, 60); var materialRock = new TerrainMaterialLayer(GraphicsService) { DiffuseTexture = ContentManager.Load<Texture2D>("Terrain/Rock-02-Diffuse"), NormalTexture = ContentManager.Load<Texture2D>("Terrain/Rock-02-Normal"), SpecularTexture = ContentManager.Load<Texture2D>("Terrain/Rock-02-Specular"), HeightTexture = ContentManager.Load<Texture2D>("Terrain/Rock-02-Height"), TileSize = detailCellSize * 1024, DiffuseColor = new Vector3F(1 / 0.702f), BlendTexture = noiseTexture, BlendTextureChannel = 0, BlendRange = 0.1f, TerrainHeightBlendRange = 0.1f, }; _terrainTile.Layers.Add(materialRock); var materialSnow = new TerrainMaterialLayer(GraphicsService) { DiffuseTexture = ContentManager.Load<Texture2D>("Terrain/Snow-Diffuse"), NormalTexture = ContentManager.Load<Texture2D>("Terrain/Snow-Normal"), SpecularTexture = ContentManager.Load<Texture2D>("Terrain/Snow-Specular"), TileSize = detailCellSize * 512, BlendTexture = noiseTexture, BlendTextureChannel = 1, BlendRange = 0.1f, }; _terrainTile.Layers.Add(materialSnow); // Create a flat plane for collision detection. var rigidBody = new RigidBody(new PlaneShape(), new MassFrame(), null) { MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(rigidBody); CreateGuiControls(); }