/// <summary> /// This renders the refraction map; /// </summary> private void DrawRefractionMap(GraphicsDevice device, Camera camera, RenderSceneDelegate RenderScene) { // Clipping computations will be done after vertices have passed through the vertex shader and are in screen space. We must therefore represent the clipping planes // screen space as well, which is achieved by multiplying the plane coefficients by the view and projection matrices. Vector4 refractionPlaneCoefficients = new Vector4(0.0f, 1.0f, 0.0f, -waterHeight); refractionPlaneCoefficients = Vector4.Transform(refractionPlaneCoefficients, Matrix.Transpose(Matrix.Invert(camera.ViewMatrix * camera.ProjMatrix))); refractionClippingPlane = new Plane(refractionPlaneCoefficients); // Prepare the device for rendering to the desired render target device.ClipPlanes[0].Plane = refractionClippingPlane; device.ClipPlanes[0].IsEnabled = true; device.SetRenderTarget(0, refractionRenderTarget); device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0); // Render the scene with clipping RenderScene(); // Now disable the clipping plane and save the result to a texture device.ClipPlanes[0].IsEnabled = false; device.SetRenderTarget(0, null); refractionMap = refractionRenderTarget.GetTexture(); }
/// <summary> /// This draws the scene with reflective and refractive water. It takes a delegate function to perform the actual scene rendering needed to construct the refraction /// and reflection maps. /// </summary> /// <param name="camera"></param> public void Draw(Camera camera, RenderSceneDelegate RenderScene) { GraphicsDevice graphicsDevice = game.GraphicsDevice; // Render the refraction and reflection maps DrawRefractionMap(graphicsDevice, camera, RenderScene); }
/// <summary> /// Loads graphics resources needed for the game. /// </summary> public override void LoadGraphicsContent(bool loadAllContent) { // Initialize the camera camera = new FirstPersonCamera(GameOptions.CameraAccelerationMagnitude, GameOptions.CameraRotationSpeed, GameOptions.CameraVelocityDecayRate); camera.AspectRatio = (float)ScreenManager.GraphicsDevice.Viewport.Width / (float)ScreenManager.GraphicsDevice.Viewport.Height; camera.Position = new Vector3(0, GameOptions.TerrainMaxHeight, 0); camera.Angles = new Vector3(-MathHelper.PiOver2, 0.0f, 0.0f); if (loadAllContent) { // Load the sky box skyBox = new SkyBox(ScreenManager.Game, ScreenManager.Content, camera); // Set up the terrain parameters TerrainQuadTreeParameters parameters = new TerrainQuadTreeParameters(); parameters.HeightMapName = "Content\\Textures\\Heightmap"; parameters.LayerMap0Name = "Content\\Textures\\grass01"; parameters.LayerMap1Name = "Content\\Textures\\rock01"; parameters.LayerMap2Name = "Content\\Textures\\snow01"; parameters.GrassTextureName = "Content\\Textures\\grass"; parameters.MaxHeight = GameOptions.TerrainMaxHeight; parameters.TerrainScale = GameOptions.TerrainScale; parameters.MaxScreenSpaceError = 0.075f; parameters.ScreenHeight = ScreenManager.Game.GraphicsDevice.Viewport.Height; parameters.FieldOfView = camera.FieldOfView; parameters.GrassChunkDimension = 30; parameters.GrassChunkStarSeparation = 266.6f; parameters.GrassStartFadingInDistance = 4000.0f; parameters.GrassStopFadingInDistance = 3900.0f; parameters.WindStrength = 100.0f; parameters.WindDirection = new Vector4(-1.0f, 0.0f, 0.0f, 0.0f); parameters.DoPreprocessing = true; parameters.ComputePerspectiveScalingFactor(); terrain = new TerrainQuadTree(ScreenManager.Game, ScreenManager.Content, parameters); // Iniialize the water manager waterManager = new WaterManager(ScreenManager.Game, GameOptions.WaterHeight); } }
/// <summary> /// This loads the model and texture data needed to render the skybox. /// </summary> public SkyBox(Game game, ContentManager content, Camera camera) { this.game = game; this.camera = camera; GraphicsDevice graphicsDevice = game.GraphicsDevice; model = content.Load<Model>("Content\\Models\\Skybox"); textures = new Texture2D[model.Meshes.Count]; // Initialize the effect. effect = content.Load<Effect>("Content\\Shaders\\Skybox"); // Save the textures in the mesh to the textures array. int textureCount = 0; foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect meshEffect in mesh.Effects) { textures[textureCount] = meshEffect.Texture; ++textureCount; } } // We need to pass our effect down to the child mesh parts. foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { part.Effect = effect.Clone(graphicsDevice); } } }
/// <summary> /// This renders the grass chunk. /// </summary> public void Draw(Vector3 center, Camera camera) { IGraphicsDeviceService igs = (IGraphicsDeviceService)game.Services.GetService(typeof(IGraphicsDeviceService)); graphicsDevice = igs.GraphicsDevice; // Prepare the effect Matrix worldTransform = Matrix.CreateTranslation(center); quadTree.GrassShader.Parameters["world"].SetValue(worldTransform); quadTree.GrassShader.Parameters["view"].SetValue(camera.ViewMatrix); quadTree.GrassShader.Parameters["proj"].SetValue(camera.ProjMatrix); quadTree.GrassShader.Parameters["maxHeight"].SetValue(quadTree.Parameters.MaxHeight); quadTree.GrassShader.Parameters["textureSize"].SetValue(quadTree.HeightMap.Width); quadTree.GrassShader.Parameters["heightMap"].SetValue(quadTree.HeightMap); quadTree.GrassShader.Parameters["normalMap"].SetValue(quadTree.NormalMap); quadTree.GrassShader.Parameters["grassMap"].SetValue(quadTree.GrassTexture); quadTree.GrassShader.Parameters["terrainScale"].SetValue(quadTree.Parameters.TerrainScale); quadTree.GrassShader.Parameters["cameraPosition"].SetValue(camera.Position); quadTree.GrassShader.Parameters["timer"].SetValue(timer); quadTree.GrassShader.Parameters["startFadingInDistance"].SetValue(quadTree.Parameters.GrassStartFadingInDistance); quadTree.GrassShader.Parameters["stopFadingInDistance"].SetValue(quadTree.Parameters.GrassStopFadingInDistance); quadTree.GrassShader.Parameters["windStrength"].SetValue(quadTree.Parameters.WindStrength); quadTree.GrassShader.Parameters["windDirection"].SetValue(quadTree.Parameters.WindDirection); // Render it! int numVertices = dimension * dimension * 12; int numTriangles = dimension * dimension * 6; quadTree.GrassShader.CurrentTechnique = quadTree.GrassShader.Techniques["GrassDraw"]; quadTree.GrassShader.Begin(); graphicsDevice.VertexDeclaration = vertexDecl; graphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes); graphicsDevice.Indices = indexBuffer; foreach (EffectPass pass in quadTree.GrassShader.CurrentTechnique.Passes) { pass.Begin(); graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, numVertices, 0, numTriangles); pass.End(); } quadTree.GrassShader.End(); }
/// <summary> /// This updates the chunk and its children if needed. /// </summary> public void Update(Camera camera) { float distance = (camera.Position - centerWorldPosition).Length(); float screenSpaceError = geometricError / distance * quadTree.Parameters.PerspectiveScalingFactor; if (screenSpaceError > quadTree.Parameters.MaxScreenSpaceError && children.Count > 0) { splitIntoChildren = true; foreach (TerrainChunk child in children) { child.Update(camera); } } else { splitIntoChildren = false; } }
public void Render(Camera camera) { // If this node should be split, then render the four children instead if (splitIntoChildren) { foreach (TerrainChunk child in children) { child.Render(camera); } } else { IGraphicsDeviceService igs = (IGraphicsDeviceService)quadTree.Game.Services.GetService(typeof(IGraphicsDeviceService)); GraphicsDevice graphicsDevice = igs.GraphicsDevice; // Do frustum culling BoundingFrustum frustum = new BoundingFrustum(camera.ViewMatrix * camera.ProjMatrix); ContainmentType containment; frustum.Contains(ref boundingBox, out containment); if (containment == ContainmentType.Disjoint) return; // Prepare the effect quadTree.TerrainShader.Parameters["world"].SetValue(worldTransform); quadTree.TerrainShader.Parameters["view"].SetValue(camera.ViewMatrix); quadTree.TerrainShader.Parameters["proj"].SetValue(camera.ProjMatrix); quadTree.TerrainShader.Parameters["maxHeight"].SetValue(quadTree.Parameters.MaxHeight); quadTree.TerrainShader.Parameters["textureSize"].SetValue(quadTree.HeightMap.Width); quadTree.TerrainShader.Parameters["heightMap"].SetValue(quadTree.HeightMap); quadTree.TerrainShader.Parameters["grassMap"].SetValue(quadTree.LayerMap0); quadTree.TerrainShader.Parameters["rockMap"].SetValue(quadTree.LayerMap1); quadTree.TerrainShader.Parameters["snowMap"].SetValue(quadTree.LayerMap2); quadTree.TerrainShader.Parameters["normalMap"].SetValue(quadTree.NormalMap); quadTree.TerrainShader.Parameters["uStart"].SetValue(textureCoordinates.UStart); quadTree.TerrainShader.Parameters["uEnd"].SetValue(textureCoordinates.UEnd); quadTree.TerrainShader.Parameters["vStart"].SetValue(textureCoordinates.VStart); quadTree.TerrainShader.Parameters["vEnd"].SetValue(textureCoordinates.VEnd); // Render it! quadTree.TerrainShader.CurrentTechnique = quadTree.TerrainShader.Techniques["TerrainDraw"]; quadTree.TerrainShader.Begin(); foreach (EffectPass pass in quadTree.TerrainShader.CurrentTechnique.Passes) { pass.Begin(); quadTree.CommonGrid.Draw(); pass.End(); } quadTree.TerrainShader.End(); } }
/// <summary> /// Renders the grass chunks distributed across the terrain. /// </summary> /// <param name="camera"></param> private void RenderGrass(Camera camera) { BoundingFrustum frustum = new BoundingFrustum(camera.ViewMatrix * camera.ProjMatrix); float grassChunkSize = grassChunk.Dimension * grassChunk.StarSeparation; foreach (Vector3 position in grassChunkPositions) { // Do frustum culling. Vector2 cameraPosVec2 = new Vector2(camera.Position.X, camera.Position.Z); Vector2 grassPosVec2 = new Vector2(position.X, position.Z); if ((cameraPosVec2 - grassPosVec2).Length() > parameters.GrassStartFadingInDistance + grassChunkSize / 2.0f) continue; BoundingBox boundingBox = new BoundingBox(new Vector3(position.X - grassChunkSize / 2.0f, 0.0f, position.Z - grassChunkSize / 2.0f), new Vector3(position.X + grassChunkSize / 2.0f, parameters.MaxHeight + grassChunk.QuadHeight, position.Z + grassChunkSize / 2.0f)); ContainmentType containment; frustum.Contains(ref boundingBox, out containment); if (containment == ContainmentType.Disjoint) continue; grassChunk.Draw(position, camera); } }
/// <summary> /// This draws the terrain using the GPU for height map displacement and texture blending. /// </summary> public void Draw(Camera camera) { GraphicsDevice graphicsDevice = game.GraphicsDevice; graphicsDevice.RenderState.CullMode = CullMode.None; //graphicsDevice.RenderState.FillMode = FillMode.WireFrame; rootNode.Update(camera); rootNode.Render(camera); RenderGrass(camera); graphicsDevice.RenderState.AlphaBlendEnable = false; graphicsDevice.RenderState.AlphaTestEnable = false; graphicsDevice.RenderState.DepthBufferWriteEnable = true; }