/// <summary> /// Function to generate our 3D models for the scene. /// </summary> /// <remarks> /// <para> /// In this example we will be mixing 2D and 3D scene elements. So, of course, in 3D, we'll need something to render. Since this is a space scene, we'll be rendering sphere(s). I've chosen to /// generate these models instead of loading them from disk because it's a pain to write a loader for those things, and I don't focus on 3D much in Gorgon. So, for now we'll use stock primitives. /// </para> /// </remarks> private void Generate3DModels() { // The 3D model for the earth. It has a diffuse/albedo map, a normal map and a specular map. var earthSphere = new IcoSphere(_graphics, 3.0f, new DX.RectangleF(0, 0, 1, 1), DX.Vector3.Zero, 3) { Rotation = new DX.Vector3(0, 45.0f, 0), // Start off with a 45 degree rotation on the Y axis so we can see our textures a little better on startup. Position = DX.Vector3.Zero, // Set our translation to nothing for now, our "planet" type will handle positioning. Material = { SpecularPower = 0.0f, Albedo = GorgonColor.Gray20, PixelShader = "PlanetPS", // The 3D model materials are quite simple. They just reference their resources by name. We do live in the age of super duper VertexShader = "PlanetVS", // fast computers, so doing a few lookups is not going to kill our performance. This allows us to weakly reference the resources Textures = // which in turn keeps things nicely decoupled. { [0] = "earthmap1k", [1] = "earthbump1k_NRM", [2] = "earthspec1k" } } }; // This will serve as the cloud layer, it'll just sit on top of the other sphere to give the appearance of cloud cover moving over the land. // This will be additively blended with the land sphere above and use another pixel shader that has a slight emissive effect. var earthCloudSphere = new IcoSphere(_graphics, 3.01f, new DX.RectangleF(0, 0, 1, 1), DX.Vector3.Zero, 3) { Position = new DX.Vector3(0, 0, -0.2f), // Offset the clouds. If we render at the same place in Ortho camera mode, then it'll just overwrite, offsetting like this Material = // ensures that the clouds appear on top. { SpecularPower = 0, Albedo = GorgonColor.Gray20, PixelShader = "PlanetCloudPS", VertexShader = "PlanetVS", BlendState = GorgonBlendState.Additive, Textures = { [0] = "earthcloudmap" } } }; // Validate our references here so we don't have to wait too long to find out if I messed up. // Local functions are one of the best things added to C#. Delphi's had this for centuries. void Validate(Mesh mesh) { if (!_vertexShaders.ContainsKey(mesh.Material.VertexShader)) { throw new GorgonException(GorgonResult.CannotCreate, $"The vertex shader '{mesh.Material.VertexShader}' is missing."); } if (!_pixelShaders.ContainsKey(mesh.Material.PixelShader)) { throw new GorgonException(GorgonResult.CannotCreate, $"The pixel shader '{mesh.Material.PixelShader}' is missing."); } for (int i = 0; i < mesh.Material.Textures.Length; ++i) { if (string.IsNullOrWhiteSpace(mesh.Material.Textures[i])) { continue; } if (!_textures.ContainsKey(mesh.Material.Textures[i])) { throw new GorgonException(GorgonResult.CannotCreate, $"The texture '{mesh.Material.Textures[i]}' is missing."); } } } Validate(earthSphere); Validate(earthCloudSphere); _meshes[nameof(earthSphere)] = earthSphere; _meshes[nameof(earthCloudSphere)] = earthCloudSphere; }
/// <summary> /// Function to build the meshes. /// </summary> private static void BuildMeshes() { var fnU = new DX.Vector3(0.5f, 1.0f, 0); var fnV = new DX.Vector3(1.0f, 1.0f, 0); DX.Vector3.Cross(ref fnU, ref fnV, out DX.Vector3 faceNormal); faceNormal.Normalize(); _triangle = new Triangle(_graphics, new Vertex3D { Position = new DX.Vector4(-12.5f, -1.5f, 12.5f, 1), Normal = faceNormal, UV = new DX.Vector2(0, 1.0f) }, new Vertex3D { Position = new DX.Vector4(0, 24.5f, 12.5f, 1), Normal = faceNormal, UV = new DX.Vector2(0.5f, 0.0f) }, new Vertex3D { Position = new DX.Vector4(12.5f, -1.5f, 12.5f, 1), Normal = faceNormal, UV = new DX.Vector2(1.0f, 1.0f) }) { Material = { PixelShader = "WaterShader", VertexShader = "VertexShader", Textures = { [0] = "UV", [1] = "Water_Normal", [2] = "Water_Specular" } }, Position = new DX.Vector3(0, 0, 1.0f) }; _renderer.Meshes.Add(_triangle); _plane = new Plane(_graphics, new DX.Vector2(25.0f, 25.0f), new RectangleF(0, 0, 1.0f, 1.0f), new DX.Vector3(90, 0, 0), 32, 32) { Position = new DX.Vector3(0, -1.5f, 1.0f), Material = { PixelShader = "WaterShader", VertexShader = "VertexShader", Textures = { [0] = "UV", [1] = "Water_Normal", [2] = "Water_Specular" } } }; _renderer.Meshes.Add(_plane); _cube = new Cube(_graphics, new DX.Vector3(1, 1, 1), new RectangleF(0, 0, 1.0f, 1.0f), new DX.Vector3(45.0f, 0, 0)) { Position = new DX.Vector3(0, 0, 1.5f), Material = { SpecularPower = 0, PixelShader = "BumpMapShader", VertexShader = "VertexShader", Textures = { [0] = "UV", [1] = "GorgonNormalMap" } } }; _renderer.Meshes.Add(_cube); _sphere = new Sphere(_graphics, 1.0f, new RectangleF(0.0f, 0.0f, 1.0f, 1.0f), DX.Vector3.Zero, 64, 64) { Position = new DX.Vector3(-2.0f, 1.0f, 0.75f), Material = { PixelShader = "PixelShader", VertexShader = "VertexShader", SpecularPower = 0.75f, Textures = { [0] = "Earth" } } }; _renderer.Meshes.Add(_sphere); _icoSphere = new IcoSphere(_graphics, 5.0f, new DX.RectangleF(0, 0, 1, 1), DX.Vector3.Zero, 3) { Rotation = new DX.Vector3(0, -45.0f, 0), Position = new DX.Vector3(10, 2, 9.5f), Material = { PixelShader = "BumpMapShader", VertexShader = "VertexShader", Textures = { [0] = "Earth", [1] = "Earth_Normal", [2] = "Earth_Specular" } } }; _renderer.Meshes.Add(_icoSphere); _clouds = new Sphere(_graphics, 5.125f, new RectangleF(0.0f, 0.0f, 1.0f, 1.0f), DX.Vector3.Zero, 16) { Position = new DX.Vector3(10, 2, 9.5f), Material = { PixelShader = "PixelShader", VertexShader = "VertexShader", BlendState = GorgonBlendState.Additive, Textures = { [0] = "Clouds" } } }; _renderer.Meshes.Add(_clouds); }