// Build a shader for all supported feature levels and save its // bytecode to the shader library. private static void saveToLibrary(PlanetShaderKey k) { var planetShader = new PlanetShader11(k); foreach (var level in ShaderLibrary.ShaderLevels) { planetShader.BuildShader(level.vertexProfile, level.pixelProfile); } }
public static void CompileAndSaveShaders() { PlanetShaderKey k = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0); saveToLibrary(k); k.textures = PlanetShaderKey.SurfaceProperty.Diffuse; saveToLibrary(k); for (int lightCount = 0; lightCount < 2; ++lightCount) { int maxShadows = Math.Min(lightCount, 1); for (int shadowCount = 0; shadowCount < maxShadows; ++shadowCount) { for (int tex = 0; tex < 2; ++tex) { k.eclipseShadowCount = shadowCount; k.lightCount = lightCount; k.textures = tex == 0 ? PlanetShaderKey.SurfaceProperty.None : PlanetShaderKey.SurfaceProperty.Diffuse; k.style = PlanetSurfaceStyle.Diffuse; saveToLibrary(k); k.style = PlanetSurfaceStyle.Sky; saveToLibrary(k); k.style = PlanetSurfaceStyle.Specular; saveToLibrary(k); k.style = PlanetSurfaceStyle.SpecularPass; saveToLibrary(k); k.style = PlanetSurfaceStyle.PlanetaryRings; saveToLibrary(k); k.style = PlanetSurfaceStyle.DiffuseAndNight; saveToLibrary(k); } } } }
/// <summary> /// Get the planet shader for the specified shader key. The shader is created /// if it's not already in the shader library. /// </summary> /// <param name="device">Direct3D device</param> /// <param name="key">Planet surface shader key</param> /// <returns>A Direct3D shader to produce the requested effect.</returns> public static PlanetShader11 GetPlanetShader(Device device, PlanetShaderKey key) { PlanetShader11 shader; if (shaderLibrary == null || regenerateShaders) { shaderLibraryComparer = new PlanetShaderKeyComparer(); shaderLibrary = new Dictionary<PlanetShaderKey, PlanetShader11>(shaderLibraryComparer); regenerateShaders = false; } // Retrieve the shader from the library of compiled shaders; // if the shader isn't in the shader library, create it and // add it. if (!shaderLibrary.TryGetValue(key, out shader)) { if (shader == null) { // Shader was not retrieved from the cache of precompiled shaders shader = new PlanetShader11(key); shader.BuildShader(RenderContext11.VertexProfile, RenderContext11.PixelProfile); shader.Realize(device); shaderLibrary[key] = shader; } } return shader; }
public void Render(RenderContext11 renderContext, float opacity) { if (dirty && !(ISSLayer)) { Reload(); } Matrix3d oldWorld = renderContext.World; Vector3 offset = mesh.BoundingSphere.Center; float unitScale = 1.0f; if (mesh.BoundingSphere.Radius > 0.0f) { unitScale = 1.0f / mesh.BoundingSphere.Radius; } renderContext.World = Matrix3d.Translation(-offset.X, -offset.Y, -offset.Z) * Matrix3d.Scaling(unitScale, unitScale, unitScale) * oldWorld; Matrix3d worldView = renderContext.World * renderContext.View; Vector3d v = worldView.Transform(Vector3d.Empty); double scaleFactor = Math.Sqrt(worldView.M11 * worldView.M11 + worldView.M22 * worldView.M22 + worldView.M33 * worldView.M33) / unitScale; double dist = v.Length(); double radius = scaleFactor; // Calculate pixelsPerUnit which is the number of pixels covered // by an object 1 AU at the distance of the planet center from // the camera. This calculation works regardless of the projection // type. int viewportHeight = (int)renderContext.ViewPort.Height; double p11 = renderContext.Projection.M11; double p34 = renderContext.Projection.M34; double p44 = renderContext.Projection.M44; double w = Math.Abs(p34) * dist + p44; float pixelsPerUnit = (float)(p11 / w) * viewportHeight; float radiusInPixels = (float)(radius * pixelsPerUnit); if (radiusInPixels < 0.5f) { // Too small to be visible; skip rendering return; } // These colors can be modified by shadows, distance from planet, etc. Restore // the original values after rendering. var savedSunlightColor = renderContext.SunlightColor; var savedReflectedColor = renderContext.ReflectedLightColor; var savedHemiColor = renderContext.HemisphereLightColor; if (Properties.Settings.Default.SolarSystemLighting) { SetupLighting(renderContext); renderContext.AmbientLightColor = System.Drawing.Color.FromArgb(11, 11, 11); } else { // No lighting: set ambient light to white and turn off all other light sources renderContext.SunlightColor = System.Drawing.Color.Black; renderContext.ReflectedLightColor = System.Drawing.Color.Black; renderContext.HemisphereLightColor = System.Drawing.Color.Black; renderContext.AmbientLightColor = System.Drawing.Color.White; } SharpDX.Direct3D11.Device device = renderContext.Device; if (mesh == null) { return; } //Object3dLayer.sketch.DrawLines(renderContext, 1.0f, System.Drawing.Color.Red); renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite; renderContext.BlendMode = BlendMode.Alpha; int count = meshMaterials.Count; mesh.beginDrawing(renderContext); if (count > 0) { for (int i = 0; i < meshMaterials.Count; i++) { if (meshMaterials[i].Default) { Material mat = meshMaterials[i]; mat.Diffuse = Color; mat.Ambient = Color; meshMaterials[i] = mat; } // Set the material and texture for this subset renderContext.SetMaterial(meshMaterials[i], meshTextures[i], meshSpecularTextures[i], meshNormalMaps[i], opacity); renderContext.PreDraw(); renderContext.setSamplerState(0, renderContext.WrapSampler); mesh.drawSubset(renderContext, i); } } else { renderContext.PreDraw(); for (int i = 0; i < meshTextures.Count; i++) { var key = new PlanetShaderKey(PlanetSurfaceStyle.Diffuse, false, 0); renderContext.SetupPlanetSurfaceEffect(key, 1.0f); if (meshTextures[i] != null) { renderContext.MainTexture = meshTextures[i]; } renderContext.PreDraw(); mesh.drawSubset(renderContext, i); } } renderContext.setSamplerState(0, renderContext.ClampSampler); renderContext.setRasterizerState(TriangleCullMode.CullClockwise); renderContext.World = oldWorld; renderContext.SunlightColor = savedSunlightColor; renderContext.ReflectedLightColor = savedReflectedColor; renderContext.HemisphereLightColor = savedHemiColor; renderContext.AmbientLightColor = System.Drawing.Color.Black; }
private PlanetShader11(PlanetShaderKey k) { key = k; constants = new PlanetShaderConstants(); }
// Returns a shader used to draw the planet surface (or null if no shader was used) public PlanetShader11 SetupPlanetSurfaceEffect(PlanetShaderKey key, float opacity) { return SetupPlanetSurfaceEffectShader(key, opacity); }
private PlanetShader11 SetupPlanetSurfaceEffectShader(PlanetShaderKey key, float opacity) { PlanetShader11 shader = PlanetShader11.GetPlanetShader(Device, key); // If we've got a shader, make it active on the device and set the // shader constants. if (shader != null) { shader.use(Device.ImmediateContext); // Set the combined world/view/projection matrix in the shader Matrix3d worldMatrix = World; Matrix3d viewMatrix = View; Matrix wvp = (worldMatrix * viewMatrix * Projection).Matrix; shader.WVPMatrix = wvp; shader.DiffuseColor = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); Matrix3d invWorld = worldMatrix; invWorld.Invert(); // For view-dependent lighting (e.g. specular), we need the position of the camera // in the planet-fixed coordinate system. Matrix3d worldViewMatrix = worldMatrix * viewMatrix; Matrix3d invWorldView = worldViewMatrix; invWorldView.Invert(); shader.WorldViewMatrix = worldViewMatrix.Matrix; Vector3d cameraPositionObj = Vector3d.TransformCoordinate(new Vector3d(0.0, 0.0, 0.0), invWorldView); shader.CameraPosition = cameraPositionObj.Vector3; } Shader = shader; return shader; }
// Set up a shader for the specified material properties and the // current lighting environment. public void SetMaterial(Material material, Texture11 diffuseTex, Texture11 specularTex, Texture11 normalMap, float opacity) { PlanetSurfaceStyle surfaceStyle = PlanetSurfaceStyle.Diffuse; if (material.Specular != System.Drawing.Color.Black) { surfaceStyle = PlanetSurfaceStyle.Specular; } // Force the emissive style when lighting is disabled if (!lightingEnabled) { surfaceStyle = PlanetSurfaceStyle.Emissive; } PlanetShaderKey key = new PlanetShaderKey(surfaceStyle, false, 0); if (reflectedLightColor != System.Drawing.Color.Black) { key.lightCount = 2; } key.textures = 0; if (diffuseTex != null) { key.textures |= PlanetShaderKey.SurfaceProperty.Diffuse; } if (specularTex != null) { key.textures |= PlanetShaderKey.SurfaceProperty.Specular; } if (normalMap != null) { key.textures |= PlanetShaderKey.SurfaceProperty.Normal; } key.TwoSidedLighting = twoSidedLighting; SetupPlanetSurfaceEffect(key, material.Opacity * opacity); shader.DiffuseColor = new Vector4(material.Diffuse.R / 255.0f, material.Diffuse.G / 255.0f, material.Diffuse.B / 255.0f, material.Opacity*opacity); if (surfaceStyle == PlanetSurfaceStyle.Specular || surfaceStyle == PlanetSurfaceStyle.SpecularPass) { shader.SpecularColor = new Vector4(material.Specular.R / 255.0f, material.Specular.G / 255.0f, material.Specular.B / 255.0f, 0.0f); shader.SpecularPower = material.SpecularSharpness; } if (diffuseTex != null) { shader.MainTexture = diffuseTex.ResourceView; } if (specularTex != null) { shader.SpecularTexture = specularTex.ResourceView; } if (normalMap != null) { shader.NormalTexture = normalMap.ResourceView; } }
public void SetupBasicEffect(BasicEffect e, float opacity, System.Drawing.Color color) { Vector4 correctedColor; if (sRGB) { // sRGB correction for alpha. Even though alpha should be linear, we apply a // gamma correction because it's multiplied with color values. The right thing // to do is probably to use pre-multiplied alpha throughout WWT and not gamma // correct alpha. opacity = (float)Math.Pow(opacity, 2.2); correctedColor = new Vector4((float)Math.Pow(color.R / 255.0f, 2.2), (float)Math.Pow(color.G / 255.0f, 2.2), (float)Math.Pow(color.B / 255.0f, 2.2), opacity); } else { correctedColor = new Vector4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, opacity); } switch (e) { case BasicEffect.TextureOnly: { PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0); SetupPlanetSurfaceEffect(key, opacity); Shader.DiffuseColor = new Vector4(1.0f, 1.0f, 1.0f, opacity); } break; case BasicEffect.ColorOnly: { PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0); key.textures = 0; SetupPlanetSurfaceEffect(key, opacity); Shader.DiffuseColor = correctedColor; } break; case BasicEffect.TextureColorOpacity: { PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0); SetupPlanetSurfaceEffect(key, opacity); Shader.DiffuseColor = correctedColor; } break; case BasicEffect.ColoredText: { PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0); key.AlphaTexture = true; SetupPlanetSurfaceEffect(key, opacity); Shader.DiffuseColor = correctedColor; } break; default: Shader = null; break; } }
private static PlanetShader11 SetupPlanetSurfaceEffectShader(RenderContext11 renderContext, PlanetShaderKey key, float opacity) { var shader = PlanetShader11.GetPlanetShader(renderContext.Device, key); // If we've got a shader, make it active on the device and set the // shader constants. if (shader != null) { shader.use(renderContext.devContext); // Set the combined world/view/projection matrix in the shader var worldMatrix = renderContext.World; var viewMatrix = renderContext.View; var wvp = (worldMatrix * viewMatrix * renderContext.Projection).Matrix11; shader.WVPMatrix = wvp; shader.DiffuseColor = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); var invWorld = worldMatrix; invWorld.Invert(); // For view-dependent lighting (e.g. specular), we need the position of the camera // in the planet-fixed coordinate system. var worldViewMatrix = worldMatrix * viewMatrix; var invWorldView = worldViewMatrix; invWorldView.Invert(); var cameraPositionObj = Vector3d.TransformCoordinate(new Vector3d(0.0, 0.0, 0.0), invWorldView); shader.CameraPosition = cameraPositionObj.Vector311; } renderContext.Shader = shader; return shader; }
static void DrawSphere(RenderContext11 renderContext, Texture11 texture, int planetID, int sphereIndex, bool noMultires, bool drawLayers, PlanetShaderKey shaderKey) { var useMultires = Settings.Active.SolarSystemMultiRes && !noMultires; // Let an override layer take the place of the standard layer IImageSet defaultLayer = null; var defaultLayerColor = Color.White; if (drawLayers) { var referenceFrameName = Enum.GetName(typeof(SolarSystemObjects), (SolarSystemObjects)planetID); foreach (var layer in LayerManager.AllMaps[referenceFrameName].Layers) { if (layer.Enabled && layer is ImageSetLayer) { if (((ImageSetLayer)layer).OverrideDefaultLayer) { defaultLayer = ((ImageSetLayer)layer).ImageSet; defaultLayerColor = layer.Color; useMultires = true; break; } } } } if (useMultires) { renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite; if (sphereIndex < 4) { IImageSet planet = null; if (defaultLayer != null) { planet = defaultLayer; } else { var planetName = GetNameFrom3dId(planetID); var imageSetName = planetName == "Mars" ? "Visible Imagery" : planetName; planet = Earth3d.MainWindow.GetImagesetByName(imageSetName); } if (planet != null) { var normColor = new Vector4(defaultLayerColor.R, defaultLayerColor.G, defaultLayerColor.B, defaultLayerColor.A) * (1.0f / 255.0f); if (RenderContext11.sRGB) { normColor.X = (float) Math.Pow(normColor.X, 2.2); normColor.Y = (float)Math.Pow(normColor.Y, 2.2); normColor.Z = (float)Math.Pow(normColor.Z, 2.2); } renderContext.Shader.DiffuseColor = normColor; renderContext.setRasterizerState(TriangleCullMode.CullClockwise); Earth3d.MainWindow.DrawTiledSphere(planet, 100, Color.White); if (planetID == (int)SolarSystemObjects.Earth && Settings.Active.ShowClouds) { if (CloudTexture != null) { var cloudShaderKey = new PlanetShaderKey(PlanetSurfaceStyle.Diffuse, Settings.Active.ShowEarthSky, 0); cloudShaderKey.eclipseShadowCount = shaderKey.eclipseShadowCount; cloudShaderKey.HasAtmosphere = shaderKey.HasAtmosphere; if (!Settings.Active.SolarSystemLighting) { cloudShaderKey.style = PlanetSurfaceStyle.Emissive; } SetupPlanetSurfaceEffect(renderContext, cloudShaderKey, 1.0f); SetAtmosphereConstants(renderContext, planetID, 1.0f, CalcSkyGeometryHeight(planetID)); renderContext.MainTexture = CloudTexture; var savedWorld = renderContext.World; var cloudScale = 1.0 + (EarthCloudHeightMeters) / 6378100.0; renderContext.World = Matrix3d.Scaling(cloudScale, cloudScale, cloudScale) * renderContext.World; renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise); renderContext.DepthStencilMode = DepthStencilMode.Off; renderContext.BlendMode = BlendMode.Alpha; DrawFixedResolutionSphere(renderContext, sphereIndex); renderContext.World = savedWorld; renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite; renderContext.BlendMode = BlendMode.None; } } return; } } } renderContext.MainTexture = texture; renderContext.Device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; renderContext.Device.ImmediateContext.InputAssembler.InputLayout = renderContext.Shader.inputLayout(PlanetShader11.StandardVertexLayout.PositionNormalTex2); renderContext.PreDraw(); renderContext.SetVertexBuffer(sphereVertexBuffers[sphereIndex]); renderContext.SetIndexBuffer(sphereIndexBuffers[sphereIndex]); renderContext.devContext.DrawIndexed(sphereIndexBuffers[sphereIndex].Count, 0, 0); }
// Various input layouts used in 3D solar system mode // TODO Replace with an input layout cache static void DrawRings(RenderContext11 renderContext) { renderContext.setRasterizerState(TriangleCullMode.Off); var ringsKey = new PlanetShaderKey(PlanetSurfaceStyle.PlanetaryRings, false, 0); SetupPlanetSurfaceEffect(renderContext, ringsKey, 1.0f); renderContext.Shader.MainTexture = RingsMap.ResourceView; renderContext.devContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip; renderContext.Device.ImmediateContext.InputAssembler.InputLayout = renderContext.Shader.inputLayout(PlanetShader11.StandardVertexLayout.PositionNormalTex); renderContext.PreDraw(); renderContext.SetVertexBuffer(ringsVertexBuffer); renderContext.devContext.Draw((triangleCountRings+2), 0); renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise); }
private static void DrawPlanet3d(RenderContext11 renderContext, int planetID, Vector3d centerPoint, float opacity) { // Assume that KML is only used for Earth KmlLabels kmlMarkers = null; if (planetID == (int)SolarSystemObjects.Earth) { kmlMarkers = Earth3d.MainWindow.KmlMarkers; if (kmlMarkers != null) { kmlMarkers.ClearGroundOverlays(); } } var matOld = renderContext.World; var matOldBase = renderContext.WorldBase; var matOldNonRotating = renderContext.WorldBaseNonRotating; var radius = GetAdjustedPlanetRadius(planetID); SetupPlanetMatrix(renderContext, planetID, centerPoint, true); LayerManager.PreDraw(renderContext, 1.0f, false, Enum.GetName(typeof(SolarSystemObjects), (SolarSystemObjects)planetID), true); float planetWidth = 1; if (planetID == (int)SolarSystemObjects.Saturn) { planetWidth = 3; } if (IsPlanetInFrustum(renderContext, planetWidth)) { // Save all matrices modified by SetupMatrix... var matOld2 = renderContext.World; var matOldBase2 = renderContext.WorldBase; var matOldNonRotating2 = renderContext.WorldBaseNonRotating; renderContext.World = matOld; renderContext.WorldBase = matOldBase; renderContext.WorldBaseNonRotating = matOldNonRotating; SetupMatrixForPlanetGeometry(renderContext, planetID, centerPoint, true); var loc = planet3dLocations[planetID] - centerPoint; loc.Subtract(renderContext.CameraPosition); var dist = loc.Length(); var sizeIndexParam = (2 * Math.Atan(.5 * (radius / dist))) / Math.PI * 180; // Calculate pixelsPerUnit which is the number of pixels covered // by an object 1 AU at the distance of the planet center from // the camera. This calculation works regardless of the projection // type. var viewportHeight = renderContext.ViewPort.Height; var p11 = renderContext.Projection.M11; var p34 = renderContext.Projection.M34; var p44 = renderContext.Projection.M44; var w = Math.Abs(p34) * dist + p44; var pixelsPerUnit = (float)(p11 / w) * viewportHeight; var planetRadiusInPixels = (float)(radius * pixelsPerUnit); var sizeIndex = 0; if (sizeIndexParam > 10.5) { sizeIndex = 0; } else if (sizeIndexParam > 3.9) { sizeIndex = 1; } else if (sizeIndexParam > .72) { sizeIndex = 2; } else if (sizeIndexParam > 0.057) { sizeIndex = 3; } else { sizeIndex = 4; } var eclipseShadowCount = 0; var hasRingShadowsOnPlanet = false; // No shadows should be drawn if Solar System Lighting is OFF if (Settings.Active.SolarSystemLighting) { // Eclipse shadow setup for Earth if (planetID == (int)SolarSystemObjects.Earth) { if (sizeIndex < 2) { var width = Settings.Active.SolarSystemScale * .00001f; SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Moon, 0); eclipseShadowCount = 1; } } // Eclipse shadow setup for Jupiter // Shadow widths based only on moon diameter in relation to Moon diameter if (planetID == (int)SolarSystemObjects.Jupiter && sizeIndex < 3) { var p = 0; float width; if (planetLocations[(int)SolarSystemObjects.Callisto].Shadow) { width = Settings.Active.SolarSystemScale * .0000139f; SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Callisto, p++); } if (planetLocations[(int)SolarSystemObjects.Ganymede].Shadow) { width = Settings.Active.SolarSystemScale * .0000152f; SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Ganymede, p++); } if (planetLocations[(int)SolarSystemObjects.Io].Shadow) { width = Settings.Active.SolarSystemScale * .0000105f; SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Io, p++); } if (planetLocations[(int)SolarSystemObjects.Europa].Shadow) { width = Settings.Active.SolarSystemScale * .000009f; SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Europa, p++); } eclipseShadowCount = p; } // Ring shadows on Saturn if (planetID == (int)SolarSystemObjects.Saturn && Settings.Active.SolarSystemLighting) { hasRingShadowsOnPlanet = true; } //ShadowStuff end } // Get the position of the Sun relative to the planet center; the position is // in the world coordinate frame. var sunPosition = (planet3dLocations[0] - planet3dLocations[planetID]); renderContext.SunPosition = sunPosition; if (sizeIndex < 4) { var atmosphereOn = (planetID == 19 || planetID == 3) && Settings.Active.ShowEarthSky; if (planetID == 0 && sizeIndex > 1) { //todo11 //device.RenderState.Clipping = false; DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)Math.Min(1.6, sizeIndexParam) * 2, planetColors[planetID], true, opacity); //todo11 //device.RenderState.Clipping = true; } var surfaceStyle = PlanetSurfaceStyle.Diffuse; if (planetID == (int)SolarSystemObjects.Sun || !Settings.Active.SolarSystemLighting) { surfaceStyle = PlanetSurfaceStyle.Emissive; } else if (planetID == (int)SolarSystemObjects.Moon || planetID == (int)SolarSystemObjects.Mercury) { // Use Lommel-Seeliger photometric model for regolith covered bodies // surfaceStyle = PlanetSurfaceStyle.LommelSeeliger; } var skyGeometryHeight = CalcSkyGeometryHeight(planetID); var shaderKey = new PlanetShaderKey(surfaceStyle, atmosphereOn, eclipseShadowCount); shaderKey.HasRingShadows = hasRingShadowsOnPlanet; if (kmlMarkers != null) { shaderKey.overlayTextureCount = Math.Min(kmlMarkers.GroundOverlayCount, PlanetShader11.MaxOverlayTextures); } SetupPlanetSurfaceEffect(renderContext, shaderKey, opacity); renderContext.LocalCenter = Vector3d.Empty; // Set up any overlay textures if (shaderKey.overlayTextureCount > 0) { if (renderContext.ShadersEnabled) { kmlMarkers.SetupGroundOverlays(renderContext); } } if (shaderKey.eclipseShadowCount > 0) { renderContext.Shader.EclipseTexture = PlanetShadow.ResourceView; } if (shaderKey.HasRingShadows) { renderContext.Shader.RingTexture = RingsMap.ResourceView; } if (atmosphereOn) { SetAtmosphereConstants(renderContext, planetID, 1.0f, skyGeometryHeight); } // Disable overlays after we're done rendering the planet surface (i.e. we don't want // them on any rings, sky shell, or cloud layer.) shaderKey.overlayTextureCount = 0; renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise); if (planetID == 19 && !Settings.Active.SolarSystemMultiRes && Settings.Active.SolarSystemLighting) { shaderKey.style = PlanetSurfaceStyle.DiffuseAndNight; SetupPlanetSurfaceEffect(renderContext, shaderKey, opacity); if (atmosphereOn) { SetAtmosphereConstants(renderContext, planetID, 1.0f, skyGeometryHeight); } // Set eclipse constants var eclipseShadowWidth = Settings.Active.SolarSystemScale * .00001f; if (shaderKey.eclipseShadowCount > 0) { SetupShadow(renderContext, centerPoint, eclipseShadowWidth, SolarSystemObjects.Moon, 0); renderContext.Shader.EclipseTexture = PlanetShadow.ResourceView; } renderContext.Shader.NightTexture = planetTexturesMaps[20].ResourceView; renderContext.BlendMode = BlendMode.None; DrawSphere(renderContext, planetTexturesMaps[planetID], planetID, sizeIndex, false, false, shaderKey); // Set up for rendering specular pass shaderKey.style = PlanetSurfaceStyle.SpecularPass; SetupPlanetSurfaceEffect(renderContext, shaderKey, opacity); if (shaderKey.eclipseShadowCount > 0) { SetupShadow(renderContext, centerPoint, eclipseShadowWidth, SolarSystemObjects.Moon, 0); renderContext.Shader.EclipseTexture = PlanetShadow.ResourceView; } if (atmosphereOn) { SetAtmosphereConstants(renderContext, planetID, 1.0f, skyGeometryHeight); } // Set up specular properties; this should eventually be abstracted by RenderContext renderContext.Shader.SpecularPower = 50.0f; renderContext.Shader.SpecularColor = new Vector4(0.5f, 0.5f, 0.5f, 0.0f); renderContext.BlendMode = BlendMode.Additive; DrawSphere(renderContext, planetTexturesMaps[21], planetID, sizeIndex, false, true, shaderKey); renderContext.BlendMode = BlendMode.None; } else { renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite; renderContext.PreDraw(); DrawSphere(renderContext, planetTexturesMaps[planetID], planetID, sizeIndex, false, true, shaderKey); } // Render the sky geometry. This is a sphere slightly larger than the planet where the // only light is from atmospheric scattering. We'll render inside of the sphere only. if (atmosphereOn) { // The sky geometry needs to be slightly larger than the planet itself, so adjust the // world matrix by a scale factor a bit greater than 1.0 var savedWorld = renderContext.World; var world = renderContext.World; var skyRadius = skyGeometryHeight + 1.0f; world.ScalePrepend(new Vector3d(skyRadius, skyRadius, skyRadius)); renderContext.World = world; shaderKey.style = PlanetSurfaceStyle.Sky; var atmosphereShader = SetupPlanetSurfaceEffect(renderContext, shaderKey, 1.0f); renderContext.Shader = atmosphereShader; // Set the shadow texture if there's an eclipse if (shaderKey.eclipseShadowCount > 0) { atmosphereShader.EclipseTexture = PlanetShadow.ResourceView; } // Atmosphere height is relative to the size of the sphere being rendered. Since we're // actually rendering the shell geometry here, we just use a value of 0 for the height // and a lower value for the zero height. SetAtmosphereConstants(renderContext, planetID, 1.0f + skyGeometryHeight, 0.0f); // We're rendering just the atmosphere; there's no contribution from a surface, so set the // diffuse color to black. atmosphereShader.DiffuseColor = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); atmosphereShader.Opacity = 0.0f; //renderContext.BlendMode = BlendMode.Alpha; // Fade out the sky geometry as its screen size gets thin; this prevents terrible // aliasing that occurs. var skyShellPixels = (float)(skyGeometryHeight * radius * pixelsPerUnit); var blendFactor = Math.Min(3.0f, skyShellPixels) / 3.0f; renderContext.BlendMode = BlendMode.BlendFactorInverseAlpha; renderContext.BlendFactor = new Color4(blendFactor, blendFactor, blendFactor, 1.0f); renderContext.DepthStencilMode = DepthStencilMode.ZReadOnly; //Render the _inside_ of the sphere. No need for multires or layers when drawing the sky renderContext.setRasterizerState(TriangleCullMode.CullClockwise); DrawSphere(renderContext, planetTexturesMaps[planetID], planetID, 0/*sizeIndex*/, true, false, shaderKey); // Reset device state renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise); renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite; renderContext.BlendMode = BlendMode.None; // Restore the world matrix renderContext.World = savedWorld; } RestoreDefaultMaterialState(renderContext); if (planetID == 5) { var ringsKey = new PlanetShaderKey(PlanetSurfaceStyle.PlanetaryRings, false, 0); SetupPlanetSurfaceEffect(renderContext, ringsKey, 1.0f); DrawRings(renderContext); RestoreDefaultMaterialState(renderContext); } } else { if (planetID == 0) { DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)(10 * planetDiameters[planetID]), planetColors[planetID], true, opacity); } else if (planetID < (int)SolarSystemObjects.Moon || planetID == (int)SolarSystemObjects.Earth) { var size = (float)(800 * planetDiameters[planetID]); DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)Math.Max(.05, Math.Min(.1f, size)), planetColors[planetID], true, opacity); } else if (sizeIndexParam > .002) { var size = (float)(800 * planetDiameters[planetID]); DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)Math.Max(.05, Math.Min(.1f, size)), planetColors[planetID], true, opacity); } } // Restore all matrices modified by SetupMatrix... renderContext.World = matOld2; renderContext.WorldBase = matOldBase2; renderContext.WorldBaseNonRotating = matOldNonRotating2; } { var sunPosition = (planet3dLocations[0] - centerPoint); var planetPosition = planet3dLocations[planetID] - centerPoint; renderContext.SunPosition = sunPosition; renderContext.ReflectedLightPosition = planetPosition; if (planetID == (int)SolarSystemObjects.Earth) { renderContext.ReflectedLightColor = Color.FromArgb(50, 70, 90); renderContext.HemisphereLightColor = Color.FromArgb(100, 100, 100); } else { renderContext.ReflectedLightColor = Color.Black; renderContext.HemisphereLightColor = Color.Black; } renderContext.OccludingPlanetPosition = planetPosition; renderContext.OccludingPlanetRadius = planetDiameters[planetID] / 2.0; } LayerManager.Draw(renderContext, 1.0f, false, Enum.GetName(typeof(SolarSystemObjects), (SolarSystemObjects)planetID), true, false); // Reset render context state renderContext.ReflectedLightColor = Color.Black; renderContext.HemisphereLightColor = Color.Black; renderContext.World = matOld; Earth3d.MainWindow.MakeFrustum(); RestoreDefaultMaterialState(renderContext); renderContext.setRasterizerState(TriangleCullMode.CullClockwise); }
// Returns a shader used to draw the planet surface (or null if no shader was used) public static PlanetShader11 SetupPlanetSurfaceEffect(RenderContext11 renderContext, PlanetShaderKey key, float opacity) { return SetupPlanetSurfaceEffectShader(renderContext, key, opacity); }