private void RenderCapsule(IGraphicsService graphicsService, PrimitiveJob job) { float radius = job.Size.Radius; float height = job.Size.Height; if (DrawWireFrame) { if (_hemisphereLinePrimitive == null) { _hemisphereLinePrimitive = MeshHelper.GetHemisphereLines(graphicsService); } Effect.World = Matrix.CreateScale(radius) * Matrix.CreateTranslation(0, height / 2 - radius, 0) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); _hemisphereLinePrimitive.Draw(); Effect.World = Matrix.CreateScale(-radius, -radius, radius) * Matrix.CreateTranslation(0, -height / 2 + radius, 0) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); _hemisphereLinePrimitive.Draw(); // 4 lines Vector3F dx = radius * job.Pose.ToWorldDirection(new Vector3F(1, 0, 0)); Vector3F dy = (height / 2 - radius) * job.Pose.ToWorldDirection(new Vector3F(0, 1, 0)); Vector3F dz = radius * job.Pose.ToWorldDirection(new Vector3F(0, 0, 1)); Vector3F center = job.Pose.Position; _lineBatch.Add(center + dy + dx, center - dy + dx, job.Color); _lineBatch.Add(center + dy - dx, center - dy - dx, job.Color); _lineBatch.Add(center + dy + dz, center - dy + dz, job.Color); _lineBatch.Add(center + dy - dz, center - dy - dz, job.Color); } else { if (_hemispherePrimitive == null) { _hemispherePrimitive = MeshHelper.GetHemisphere(graphicsService); } Effect.World = Matrix.CreateScale(radius) * Matrix.CreateTranslation(0, height / 2 - radius, 0) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); _hemispherePrimitive.Draw(); Effect.World = Matrix.CreateScale(-radius, -radius, radius) * Matrix.CreateTranslation(0, -height / 2 + radius, 0) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); _hemispherePrimitive.Draw(); if (_uncappedCylinderPrimitive == null) { _uncappedCylinderPrimitive = MeshHelper.GetUncappedCylinder(graphicsService); } Effect.World = Matrix.CreateScale(radius, height / 2 - radius, radius) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); _uncappedCylinderPrimitive.Draw(); } }
private void RenderHiDef(TextureCube texture, Matrix orientation, float exposure, RenderContext context) { var graphicsDevice = context.GraphicsService.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.BlendState = BlendState.Opaque; var cameraNode = context.CameraNode; Matrix view = cameraNode.View; Matrix projection = cameraNode.Camera.Projection; // Cube maps are left handed --> Sample with inverted z. (Otherwise, the // cube map and objects or texts in it are mirrored.) var mirrorZ = Matrix.CreateScale(1, 1, -1); _parameterWorldViewProjection.SetValue( (Matrix)(projection * view * new Matrix(orientation, Vector3.Zero) * mirrorZ)); _parameterExposure.SetValue(new Vector4(exposure, exposure, exposure, 1)); _textureParameter.SetValue(texture); if (context.IsHdrEnabled()) { _passLinear.Apply(); } else { _passGamma.Apply(); } _submesh.Draw(); savedRenderState.Restore(); }
private void RenderCylinder(IGraphicsService graphicsService, PrimitiveJob job) { float radius = job.Size.Radius; float height = job.Size.Height; Effect.World = Matrix.CreateScale(radius, height / 2, radius) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); if (DrawWireFrame) { if (_cylinderLinePrimitive == null) { _cylinderLinePrimitive = MeshHelper.GetCylinderLines(graphicsService); } _cylinderLinePrimitive.Draw(); } else { if (_cylinderPrimitive == null) { _cylinderPrimitive = MeshHelper.GetCylinder(graphicsService); } _cylinderPrimitive.Draw(); } }
public override void Paint() { TopoModel model = ActiveModel; if (Visible) { if (false) //**Main.main.objectPlacement.checkCutFaces.Checked) { // int cutpos = Main.main.objectPlacement.cutPositionSlider.Value; if (ForceRefresh || ctrl.updateCuts || lastRendered != 1 || activeModel != activeSubmesh || lastShowEdges != SettingsProvider.Instance.ThreeDSettings.ShowEdges || lastSelected != Selected) { RHVector3 normpoint = ctrl.cutPos.Add(ctrl.cutDirection); RHVector3 point = new RHVector3(0, 0, 0); ReverseTransformPoint(ctrl.cutPos, point); ReverseTransformPoint(normpoint, normpoint); RHVector3 normal = normpoint.Subtract(point); submesh.Clear(); model.CutMesh(submesh, normal, point, outside ? Submesh.MESHCOLOR_OUTSIDE : Submesh.MESHCOLOR_FRONTBACK); submesh.selected = Selected; submesh.Compress(); lastShowEdges = SettingsProvider.Instance.ThreeDSettings.ShowEdges; lastSelected = Selected; activeSubmesh = activeModel; lastRendered = 1; } } else { if (ForceRefresh || ctrl.updateCuts || lastRendered != 0 || activeModel != activeSubmesh || lastShowEdges != SettingsProvider.Instance.ThreeDSettings.ShowEdges) { submesh.Clear(); submesh.defaultColor = ProjectManager.Instance.CurrentProject.projectSettings.PrinterSettings.Extruders[ExtruderNumber].ExtruderColor; model.FillMesh(submesh, outside ? Submesh.MESHCOLOR_OUTSIDE : Submesh.MESHCOLOR_FRONTBACK); submesh.selected = Selected; submesh.Compress(); lastShowEdges = SettingsProvider.Instance.ThreeDSettings.ShowEdges; lastSelected = Selected; activeSubmesh = activeModel; lastRendered = 0; } } // submesh.Draw(SettingsProvider.Instance.ThreeDSettings.drawMethod,ctrl.cam.EdgeTranslation()); submesh.Draw(2, ctrl.cam.EdgeTranslation()); } ForceRefresh = false; }
private void RenderSphere(IGraphicsService graphicsService, PrimitiveJob job, RenderContext context) { if (DrawWireFrame) { Pose cameraPose = context.CameraNode.PoseWorld; Matrix44F cameraProjection = context.CameraNode.Camera.Projection; if (Numeric.AreEqual(1.0f, cameraProjection.M33)) { // Orthographic projection Vector3F position = job.Pose.Position; Vector3F right = cameraPose.Orientation.GetColumn(0); Vector3F up = cameraPose.Orientation.GetColumn(1); Vector3F forward = cameraPose.Orientation.GetColumn(2); Matrix pose = new Matrix(right.X, right.Y, right.Z, 0, up.X, up.Y, up.Z, 0, forward.X, forward.Y, forward.Z, 0, position.X, position.Y, position.Z, 1); Effect.World = Matrix.CreateScale(job.Size.Radius) * pose; Effect.CurrentTechnique.Passes[0].Apply(); if (_circleLinePrimitive == null) { _circleLinePrimitive = MeshHelper.GetCircleLines(graphicsService); } _circleLinePrimitive.Draw(); } else { // Perspective projection Vector3F right = cameraPose.Orientation * Vector3F.Right; RenderSphereOutline(job.Size.Radius, ref job.Pose.Position, ref cameraPose, ref right, ref job.Color); } } else { Effect.World = Matrix.CreateScale(job.Size.Radius) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); if (_icospherePrimitive == null) { _icospherePrimitive = MeshHelper.GetIcosphere(graphicsService); } _icospherePrimitive.Draw(); } }
private void Render(RenderContext context) { var graphicsDevice = context.GraphicsService.GraphicsDevice; graphicsDevice.Clear(Color.CornflowerBlue); graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; // Use the view and projection info from the camera node controlled by the // Player game component. _effect.View = (Matrix)_cameraObject.CameraNode.View; _effect.Projection = _cameraObject.CameraNode.Camera.Projection; _effect.World = Matrix.CreateTranslation(-1, 1, 0); _effect.DiffuseColor = new Vector3(1, 0, 0); _effect.LightingEnabled = true; _effect.CurrentTechnique.Passes[0].Apply(); // Render the submesh using the currently active shader. _torus.Draw(); _effect.World = Matrix.CreateTranslation(1, 1, 0); _effect.DiffuseColor = new Vector3(0, 1, 0); _effect.CurrentTechnique.Passes[0].Apply(); _teapot.Draw(); _effect.World = Matrix.CreateScale(0.5f, 1, 0.5f) * Matrix.CreateTranslation(-2, 1, -2); _effect.DiffuseColor = new Vector3(0, 0, 1); _effect.CurrentTechnique.Passes[0].Apply(); _sphere.Draw(); _effect.World = Matrix.CreateTranslation(0, 1, -2); _effect.DiffuseColor = new Vector3(1, 1, 0); _effect.CurrentTechnique.Passes[0].Apply(); _box.Draw(); _effect.World = Matrix.CreateTranslation(2, 1, -2); _effect.DiffuseColor = new Vector3(1, 0, 1); _effect.LightingEnabled = false; _effect.CurrentTechnique.Passes[0].Apply(); _cone.Draw(); }
public override void Paint() { TopoModel model = ActiveModel; if (Main.main.objectPlacement.checkCutFaces.Checked) { int cutpos = Main.main.objectPlacement.cutPositionSlider.Value; if (ForceRefresh || Main.main.threedview.updateCuts || lastRendered != 1 || activeModel != activeSubmesh || lastShowEdges != Main.threeDSettings.ShowEdges || lastSelected != Selected) { RHVector3 normpoint = Main.main.threedview.cutPos.Add(Main.main.threedview.cutDirection); RHVector3 point = new RHVector3(0, 0, 0); ReverseTransformPoint(Main.main.threedview.cutPos, point); ReverseTransformPoint(normpoint, normpoint); RHVector3 normal = normpoint.Subtract(point); submesh.Clear(); model.CutMesh(submesh, normal, point, outside ? Submesh.MESHCOLOR_OUTSIDE : Submesh.MESHCOLOR_FRONTBACK); submesh.selected = Selected; submesh.Compress(); lastShowEdges = Main.threeDSettings.ShowEdges; lastSelected = Selected; activeSubmesh = activeModel; lastRendered = 1; } } else { if (ForceRefresh || Main.main.threedview.updateCuts || lastRendered != 0 || activeModel != activeSubmesh || lastShowEdges != Main.threeDSettings.ShowEdges) { submesh.Clear(); model.FillMesh(submesh, outside ? Submesh.MESHCOLOR_OUTSIDE : Submesh.MESHCOLOR_FRONTBACK); submesh.selected = Selected; submesh.Compress(); lastShowEdges = Main.threeDSettings.ShowEdges; lastSelected = Selected; activeSubmesh = activeModel; lastRendered = 0; } } submesh.Draw(Main.threeDSettings.drawMethod, Main.main.threedview.cam.EdgeTranslation()); ForceRefresh = false; }
private void RenderBox(IGraphicsService graphicsService, PrimitiveJob job) { Effect.World = Matrix.CreateScale((Vector3)job.Size.Extent) * job.Pose; Effect.CurrentTechnique.Passes[0].Apply(); if (DrawWireFrame) { if (_boxLinePrimitive == null) _boxLinePrimitive = MeshHelper.GetBoxLines(graphicsService); _boxLinePrimitive.Draw(); } else { if (_boxPrimitive == null) _boxPrimitive = MeshHelper.GetBox(graphicsService); _boxPrimitive.Draw(); } }
/// <inheritdoc/> public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { ThrowIfDisposed(); if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (nodes.Count == 0) { return; } context.Validate(_effect); context.ThrowIfCameraMissing(); var graphicsDevice = context.GraphicsService.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); graphicsDevice.BlendState = BlendState.AlphaBlend; graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; // Camera properties var cameraNode = context.CameraNode; Matrix view = (Matrix) new Matrix(cameraNode.PoseWorld.Orientation.Transposed, new Vector3()); _parameterView.SetValue(view); Matrix projection = cameraNode.Camera.Projection; _parameterProjection.SetValue(projection); // Update SceneNode.LastFrame for all visible nodes. int frame = context.Frame; cameraNode.LastFrame = frame; for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i] as ScatteringSkyNode; if (node == null) { continue; } // ScatteringSkyNode is visible in current frame. node.LastFrame = frame; _parameterSunDirection.SetValue((Vector3)node.SunDirection); _parameterSunIntensity.SetValue((Vector3)(node.SunIntensity * node.SunColor)); _parameterRadii.SetValue(new Vector4( node.AtmosphereHeight + node.PlanetRadius, // Atmosphere radius node.PlanetRadius, // Ground radius node.ObserverAltitude + node.PlanetRadius, // Observer radius node.ScaleHeight)); // Absolute Scale height _parameterNumberOfSamples.SetValue(node.NumberOfSamples); _parameterBetaRayleigh.SetValue((Vector3)node.BetaRayleigh); _parameterBetaMie.SetValue((Vector3)node.BetaMie); _parameterGMie.SetValue(node.GMie); _parameterTransmittance.SetValue(node.Transmittance); if (node.BaseHorizonColor.IsNumericallyZero && node.BaseZenithColor.IsNumericallyZero) { // No base color. if (context.IsHdrEnabled()) { _passLinear.Apply(); } else { _passGamma.Apply(); } } else { // Add base color. _parameterBaseHorizonColor.SetValue((Vector4) new Vector4(node.BaseHorizonColor, node.BaseColorShift)); _parameterBaseZenithColor.SetValue((Vector3)node.BaseZenithColor); if (context.IsHdrEnabled()) { _passLinearWithBaseColor.Apply(); } else { _passGammaWithBaseColor.Apply(); } } _submesh.Draw(); } savedRenderState.Restore(); }
private void RenderHiDef(SkyboxNode node, RenderContext context) { var graphicsDevice = context.GraphicsService.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.BlendState = node.EnableAlphaBlending ? BlendState.AlphaBlend : BlendState.Opaque; bool sourceIsFloatingPoint = TextureHelper.IsFloatingPointFormat(node.Texture.Format); // Set sampler state. (Floating-point textures cannot use linear filtering. (XNA would throw an exception.)) if (sourceIsFloatingPoint) { graphicsDevice.SamplerStates[0] = SamplerState.PointClamp; } else { graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp; } var cameraNode = context.CameraNode; Matrix view = cameraNode.View; Matrix projection = cameraNode.Camera.Projection; // Cube maps are left handed --> Sample with inverted z. (Otherwise, the // cube map and objects or texts in it are mirrored.) var mirrorZ = Matrix.CreateScale(1, 1, -1); Matrix orientation = node.PoseWorld.Orientation; _parameterWorldViewProjection.SetValue((Matrix)(projection * view * new Matrix(orientation, Vector3.Zero) * mirrorZ)); Vector4 color = node.EnableAlphaBlending ? new Vector4((Vector3)node.Color * node.Alpha, node.Alpha) // Premultiplied : new Vector4((Vector3)node.Color, 1); // Opaque _parameterColor.SetValue(color); _textureParameter.SetValue(node.Texture); if (node.Encoding is RgbEncoding) { _parameterTextureSize.SetValue(node.Texture.Size); if (context.IsHdrEnabled()) { _passRgbToRgb.Apply(); } else { _passRgbToSRgb.Apply(); } } else if (node.Encoding is SRgbEncoding) { if (!sourceIsFloatingPoint) { if (context.IsHdrEnabled()) { _passSRgbToRgb.Apply(); } else { _passSRgbToSRgb.Apply(); } } else { throw new GraphicsException("sRGB encoded skybox cube maps must not use a floating point format."); } } else if (node.Encoding is RgbmEncoding) { float max = GraphicsHelper.ToGamma(((RgbmEncoding)node.Encoding).Max); _parameterRgbmMaxValue.SetValue(max); if (context.IsHdrEnabled()) { _passRgbmToRgb.Apply(); } else { _passRgbmToSRgb.Apply(); } } else { throw new NotSupportedException("The SkyBoxRenderer supports only RgbEncoding, SRgbEncoding and RgbmEncoding."); } _submesh.Draw(); savedRenderState.Restore(); }
public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { ThrowIfDisposed(); if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (nodes.Count == 0) { return; } context.Validate(_effect); context.ThrowIfCameraMissing(); var graphicsDevice = context.GraphicsService.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); graphicsDevice.BlendState = BlendState.AlphaBlend; graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; // Camera properties var cameraNode = context.CameraNode; Matrix view = (Matrix) new Matrix(cameraNode.PoseWorld.Orientation.Transposed, new Vector3()); _parameterView.SetValue(view); Matrix projection = cameraNode.Camera.Projection; _parameterProjection.SetValue(projection); // Update SceneNode.LastFrame for all visible nodes. int frame = context.Frame; cameraNode.LastFrame = frame; for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i] as GradientSkyNode; if (node == null) { continue; } // GradientSkyNode is visible in current frame. node.LastFrame = frame; _parameterSunDirection.SetValue((Vector3)node.SunDirection); _parameterFrontColor.SetValue((Vector4)node.FrontColor); _parameterZenithColor.SetValue((Vector4)node.ZenithColor); _parameterBackColor.SetValue((Vector4)node.BackColor); _parameterGroundColor.SetValue((Vector4)node.GroundColor); _parameterShift.SetValue(new Vector4(node.FrontZenithShift, node.BackZenithShift, node.FrontGroundShift, node.BackGroundShift)); if (node.CieSkyStrength < Numeric.EpsilonF) { if (context.IsHdrEnabled()) { _passLinear.Apply(); } else { _passGamma.Apply(); } } else { var p = node.CieSkyParameters; _parameterAbcd.SetValue(new Vector4(p.A, p.B, p.C, p.D)); _parameterEAndStrength.SetValue(new Vector2(p.E, node.CieSkyStrength)); if (context.IsHdrEnabled()) { _passCieLinear.Apply(); } else { _passCieGamma.Apply(); } } _submesh.Draw(); } savedRenderState.Restore(); }
public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { ThrowIfDisposed(); if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (numberOfNodes == 0) { return; } context.Validate(_effect); context.ThrowIfCameraMissing(); var graphicsDevice = context.GraphicsService.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); // Camera properties int viewportHeight = graphicsDevice.Viewport.Height; var cameraNode = context.CameraNode; var projection = cameraNode.Camera.Projection; _parameterProjection.SetValue(projection); // Update SceneNode.LastFrame for all visible nodes. int frame = context.Frame; cameraNode.LastFrame = frame; for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i] as CloudLayerNode; if (node == null) { continue; } // CloudLayerNode is visible in current frame. node.LastFrame = frame; if (node.CloudMap.Texture == null) { continue; } var sunDirection = node.SunDirection; _parameterSunDirection.SetValue((Vector3)sunDirection); _parameterSkyCurvature.SetValue(node.SkyCurvature); _parameterTextureMatrix.SetValue((Matrix) new Matrix44F(node.TextureMatrix, Vector3F.Zero)); // The sample at the pixel counts as one, the rest are for the blur. // Note: We must not set -1 because a for loop like // for (int i = 0; i < -1, i++) // crashes the AMD DX9 WP8.1 graphics driver. LOL _parameterNumberOfSamples.SetValue(Math.Max(0, node.NumberOfSamples - 1)); _parameterSampleDistance.SetValue(node.SampleDistance); _parameterScatterParameters.SetValue(new Vector3(node.ForwardScatterExponent, node.ForwardScatterScale, node.ForwardScatterOffset)); _parameterHorizonFade.SetValue(new Vector2(node.HorizonFade, node.HorizonBias)); _parameterSunLight.SetValue((Vector3)node.SunLight); _parameterAmbientLight.SetValue(new Vector4((Vector3)node.AmbientLight, node.Alpha)); _parameterTexture.SetValue(node.CloudMap.Texture); // Occlusion query. if (graphicsDevice.GraphicsProfile != GraphicsProfile.Reach && node.SunQuerySize >= Numeric.EpsilonF) { bool skipQuery = false; if (node.OcclusionQuery != null) { if (node.OcclusionQuery.IsComplete) { node.TryUpdateSunOcclusion(); } else { // The previous query is still not finished. Do not start a new query, this would // create a SharpDX warning. skipQuery = true; } } else { node.OcclusionQuery = new OcclusionQuery(graphicsDevice); } if (!skipQuery) { node.IsQueryPending = true; float totalPixels = viewportHeight * node.SunQuerySize; totalPixels *= totalPixels; node.QuerySize = totalPixels; // Use a camera which looks at the sun. // Get an relative up vector which is not parallel to the forward direction. var lookAtUp = Vector3F.UnitY; if (Vector3F.AreNumericallyEqual(sunDirection, lookAtUp)) { lookAtUp = Vector3F.UnitZ; } Vector3F zAxis = -sunDirection; Vector3F xAxis = Vector3F.Cross(lookAtUp, zAxis).Normalized; Vector3F yAxis = Vector3F.Cross(zAxis, xAxis); var lookAtSunView = new Matrix(xAxis.X, yAxis.X, zAxis.X, 0, xAxis.Y, yAxis.Y, zAxis.Y, 0, xAxis.Z, yAxis.Z, zAxis.Z, 0, 0, 0, 0, 1); _parameterView.SetValue(lookAtSunView); graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite; graphicsDevice.DepthStencilState = DepthStencilState.None; graphicsDevice.RasterizerState = RasterizerState.CullNone; // Create small quad shortly behind the near plane. // Note: We use an "untranslated" view matrix, so we can ignore the camera position. float width = (projection.Top - projection.Bottom) * node.SunQuerySize; Vector3F right = sunDirection.Orthonormal1 * (width / 2); Vector3F up = sunDirection.Orthonormal2 * (width / 2); Vector3F center = sunDirection * (projection.Near * 1.0001f); _queryGeometry[0] = center - up - right; _queryGeometry[1] = center + up - right; _queryGeometry[2] = center - up + right; _queryGeometry[3] = center + up + right; if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8) { _passOcclusionAlpha.Apply(); } else { _passOcclusionRgb.Apply(); } node.OcclusionQuery.Begin(); graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2, VertexPosition.VertexDeclaration); node.OcclusionQuery.End(); } } else { node.IsQueryPending = false; node.SunOcclusion = 0; } Matrix viewUntranslated = (Matrix) new Matrix44F(cameraNode.PoseWorld.Orientation.Transposed, new Vector3F(0)); _parameterView.SetValue(viewUntranslated); // Render clouds. graphicsDevice.BlendState = BlendState.AlphaBlend; graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; if (context.IsHdrEnabled()) { if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8) { _passCloudAlphaLinear.Apply(); } else { _passCloudRgbLinear.Apply(); } } else { if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8) { _passCloudAlphaGamma.Apply(); } else { _passCloudRgbGamma.Apply(); } } _submesh.Draw(); } savedRenderState.Restore(); }
/// <inheritdoc/> public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (numberOfNodes == 0) { return; } var cameraNode = context.CameraNode; var projection = cameraNode.Camera.Projection; Pose view = cameraNode.PoseWorld.Inverse; int frame = context.Frame; cameraNode.LastFrame = frame; var graphicsDevice = context.GraphicsService.GraphicsDevice; // Save render state. var originalRasterizerState = graphicsDevice.RasterizerState; var originalDepthStencilState = graphicsDevice.DepthStencilState; var originalBlendState = graphicsDevice.BlendState; // We render only backsides with no depth test. // OPTIMIZE: When camera is outside a sphere, we can render front sides with depth-read. graphicsDevice.RasterizerState = RasterizerState.CullClockwise; graphicsDevice.DepthStencilState = DepthStencilState.None; graphicsDevice.BlendState = BlendState.AlphaBlend; // Set global effect parameters. var viewport = graphicsDevice.Viewport; _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height)); _parameterView.SetValue(view); _parameterProjection.SetValue(projection); _parameterCameraPosition.SetValue((Vector3)cameraNode.PoseWorld.Position); _parameterCameraFar.SetValue(projection.Far); _parameterGBuffer0.SetValue(context.GBuffer0); for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i] as FogSphereNode; if (node == null) { continue; } // FogSphereNode is visible in current frame. node.LastFrame = frame; Matrix world = Matrix.CreateScale((Vector3)node.ScaleWorld) * node.PoseWorld; _parameterWorld.SetValue(world); _parameterWorldInverse.SetValue(Matrix.Invert(world)); _parameterColor.SetValue((Vector3)node.Color); _parameterBlendMode.SetValue(node.BlendMode); _parameterDensity.SetValue(node.Density); _parameterFalloff.SetValue(node.Falloff); _parameterIntersectionSoftness.SetValue(node.IntersectionSoftness); _effect.CurrentTechnique.Passes[0].Apply(); _submesh.Draw(); } // Restore render states. graphicsDevice.RasterizerState = originalRasterizerState; graphicsDevice.DepthStencilState = originalDepthStencilState; graphicsDevice.BlendState = originalBlendState; }
public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (numberOfNodes == 0) { return; } context.Validate(_effect); context.ThrowIfCameraMissing(); var graphicsDevice = _effect.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); graphicsDevice.DepthStencilState = DepthStencilState.None; graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd; var viewport = graphicsDevice.Viewport; _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height)); _parameterGBuffer0.SetValue(context.GBuffer0); _parameterGBuffer1.SetValue(context.GBuffer1); var cameraNode = context.CameraNode; Pose cameraPose = cameraNode.PoseWorld; Matrix viewProjection = (Matrix)cameraNode.View * cameraNode.Camera.Projection; // Update SceneNode.LastFrame for all visible nodes. int frame = context.Frame; context.CameraNode.LastFrame = frame; bool isHdrEnabled = context.IsHdrEnabled(); // Copy nodes to list and sort them by persistent IDs. This is necessary to avoid popping when // light probes overlap. _jobs.Clear(); for (int i = 0; i < numberOfNodes; i++) { var lightNode = nodes[i] as LightNode; if (lightNode == null) { continue; } var light = lightNode.Light as ImageBasedLight; if (light == null || light.Texture == null) { continue; } // Build sort-ID - high values for lights which should be rendered last. ulong sortId = 0; // Render infinite lights first and others later. if (!(light.Shape is InfiniteShape)) { sortId += ((ulong)1 << 32); // Set high value above 32-bit range. } // Sort by priority. Lights with higher priority should be rendered last // (= over the other lights). // Shift priority (signed int) to positive range and add it. sortId += (ulong)((long)lightNode.Priority + int.MaxValue + 1); // Shift sortId and add light.Id in least significant bits. sortId = (sortId << 16) | (ushort)light.Id; // Add to list for sorting. _jobs.Add(new Job { SortId = sortId, LightNode = lightNode, }); } // Sort by ascending sort-ID value. _jobs.Sort(Comparer.Instance); numberOfNodes = _jobs.Count; for (int i = 0; i < numberOfNodes; i++) { var lightNode = _jobs[i].LightNode; var light = (ImageBasedLight)lightNode.Light; // LightNode is visible in current frame. lightNode.LastFrame = frame; // ReSharper disable CompareOfFloatsByEqualityOperator bool enableDiffuse = !(Numeric.IsNaN(light.DiffuseIntensity) || (light.DiffuseIntensity == 0.0f && light.BlendMode == 0.0f)); // ReSharper restore CompareOfFloatsByEqualityOperator bool enableSpecular = !Numeric.IsNaN(light.SpecularIntensity); if (!enableDiffuse && !enableSpecular) { continue; } float hdrScale = isHdrEnabled ? light.HdrScale : 1; // We use 1x1 mipmap level for diffuse. // (2x2 is still okay, 4x4 already looks a bit like a specular reflection.) float diffuseIntensity = enableDiffuse ? light.DiffuseIntensity : 0.0f; _parameterParameters0.SetValue(new Vector4( (Vector3)light.Color * diffuseIntensity * hdrScale, // DiffuseColor Math.Max(0, light.Texture.LevelCount - 1))); // Diffuse mip level. // Shader supports only RGBM. float rgbmMax; if (light.Encoding is RgbmEncoding) { rgbmMax = GraphicsHelper.ToGamma(((RgbmEncoding)light.Encoding).Max); } else if (light.Encoding is SRgbEncoding) { // Decoding RGBM with MaxValue 1 is equal to encoding sRGB, i.e. only // gamma-to-linear is performed (assuming that the cube map alpha channel is 1). rgbmMax = 1; } else { throw new NotSupportedException( "ImageBasedLight must use sRGB or RGBM encoding. Other encodings are not yet supported."); } _parameterParameters1.SetValue(new Vector4( (Vector3)light.Color * light.SpecularIntensity * hdrScale, // SpecularColor rgbmMax)); // Bounding box can be a box shape or an infinite shape. var boundingBoxShape = lightNode.Shape as BoxShape; // Get extent of bounding box. For infinite shapes we simply set a large value. var boundingBoxExtent = boundingBoxShape != null ? boundingBoxShape.Extent * lightNode.ScaleWorld : new Vector3F(1e20f); // Falloff can only be used for box shapes but not for infinite shapes. float falloffRange = (boundingBoxShape != null) ? light.FalloffRange : 0; // AABB for localization in local space. // Use invalid min and max (min > max) to disable localization. Aabb projectionAabb = new Aabb(new Vector3F(1), new Vector3F(-1)); if (light.EnableLocalizedReflection) { if (light.LocalizedReflectionBox.HasValue) { // User defined AABB. projectionAabb = light.LocalizedReflectionBox.Value; projectionAabb.Minimum *= lightNode.ScaleWorld; projectionAabb.Maximum *= lightNode.ScaleWorld; } else if (boundingBoxShape != null) { // AABB is equal to the bounding box. projectionAabb = new Aabb(-boundingBoxExtent / 2, boundingBoxExtent / 2); } } _parameterParameters2.SetValue(new Vector4( boundingBoxExtent.X / 2, boundingBoxExtent.Y / 2, boundingBoxExtent.Z / 2, falloffRange)); _parameterParameters3.SetValue(new Vector4( projectionAabb.Minimum.X, projectionAabb.Minimum.Y, projectionAabb.Minimum.Z, light.Texture.Size)); _parameterParameters4.SetValue(new Vector4( projectionAabb.Maximum.X, projectionAabb.Maximum.Y, projectionAabb.Maximum.Z, light.BlendMode)); // Precomputed value for specular reflection lookup. const float sqrt3 = 1.7320508075688772935274463415059f; _parameterPrecomputedTerm.SetValue((float)Math.Log(light.Texture.Size * sqrt3, 2.0)); _parameterEnvironmentMap.SetValue(light.Texture); // Compute screen space rectangle and FrustumFarCorners. var rectangle = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode); var texCoordTopLeft = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height); var texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height); GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners); // Convert frustum far corners from view space to world space. for (int j = 0; j < _frustumFarCorners.Length; j++) { _frustumFarCorners[j] = (Vector3)cameraPose.ToWorldDirection((Vector3F)_frustumFarCorners[j]); } _parameterFrustumCorners.SetValue(_frustumFarCorners); EffectPass passLight = null; if (enableDiffuse && enableSpecular) { passLight = _passDiffuseAndSpecularLight; } else if (enableDiffuse) { // TODO: Can we disable writes to LightBuffer1? passLight = _passDiffuseLight; } else { // TODO: Can we disable writes to LightBuffer0? passLight = _passSpecularLight; } // Simply render fullscreen quad if we do not have a clip shape or a bounding box. if (lightNode.Clip == null && boundingBoxShape == null) { graphicsDevice.BlendState = BlendState.AlphaBlend; // Transform matrix transforms from world space with camera as origin to // local space. The lightNode.Scale is already in the other parameters and not // used in Transform. var pose = lightNode.PoseWorld; pose.Position -= cameraPose.Position; _parameterTransform.SetValue(pose.Inverse); passLight.Apply(); graphicsDevice.DrawFullScreenQuad(); continue; } // ----- Render clip mesh. graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateOnePassStencilFail; graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite; if (lightNode.Clip != null) { // Using user-defined clip shape. var data = lightNode.RenderData as LightRenderData; if (data == null) { data = new LightRenderData(); lightNode.RenderData = data; } data.UpdateClipSubmesh(context.GraphicsService, lightNode); _parameterTransform.SetValue((Matrix)data.ClipMatrix * viewProjection); _passClip.Apply(); data.ClipSubmesh.Draw(); graphicsDevice.DepthStencilState = lightNode.InvertClip ? GraphicsHelper.DepthStencilStateStencilEqual0 : GraphicsHelper.DepthStencilStateStencilNotEqual0; } else { Debug.Assert(boundingBoxShape != null); // Use box submesh. if (_boxSubmesh == null) { _boxSubmesh = MeshHelper.GetBox(context.GraphicsService); } Matrix44F world = lightNode.PoseWorld * Matrix44F.CreateScale(lightNode.ScaleLocal * boundingBoxShape.Extent); _parameterTransform.SetValue((Matrix)world * viewProjection); _passClip.Apply(); _boxSubmesh.Draw(); graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateStencilNotEqual0; } graphicsDevice.BlendState = BlendState.AlphaBlend; { // Transform matrix transforms from world space with camera as origin to // local space. The lightNode.Scale is already in the other parameters and not // used in Transform. var pose = lightNode.PoseWorld; pose.Position -= cameraPose.Position; _parameterTransform.SetValue(pose.Inverse); } // ----- Render full screen quad. passLight.Apply(); graphicsDevice.DrawQuad(rectangle); } savedRenderState.Restore(); _jobs.Clear(); }