Example #1
0
        private static void RenderUnderLight(SceneNodeBase sceneNodeBase, ShadowVolumeUnderLightEventArgs arg)
        {
            if (sceneNodeBase != null)
            {
                var      node     = sceneNodeBase as ISupportShadowVolume;
                TwoFlags flags    = (node != null) ? node.EnableShadowVolume : TwoFlags.None;
                bool     before   = (node != null) && ((flags & TwoFlags.BeforeChildren) == TwoFlags.BeforeChildren);
                bool     children = (node == null) || ((flags & TwoFlags.Children) == TwoFlags.Children);

                if (before)
                {
                    flags  = node.EnableRenderUnderLight;
                    before = (flags & TwoFlags.BeforeChildren) == TwoFlags.BeforeChildren;
                }

                if (children)
                {
                    flags    = (node != null) ? node.EnableRenderUnderLight : TwoFlags.None;
                    children = (node == null) || ((flags & TwoFlags.Children) == TwoFlags.Children);
                }

                if (before)
                {
                    node.RenderUnderLight(arg);
                }

                if (children)
                {
                    foreach (var item in sceneNodeBase.Children)
                    {
                        RenderUnderLight(item, arg);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="param"></param>
        public override void Act(ActionParams param)
        {
            Scene scene = this.scene;
            bool  displayShadowVolume = this.DisplayShadowVolume;

            this.depthClamp.On();// for infinite back cap of shadow volumes.

            // Render depth info into depth buffer and ambient color into color buffer.
            {
                var arg = new ShadowVolumeAmbientEventArgs(param, scene.Camera, scene.AmbientColor);
                RenderAmbientColor(scene.RootNode, arg);
            }

            this.stencilTest.On(); // enable stencil test.
            foreach (var light in scene.Lights)
            {
                // Clear stencil buffer.
                {
                    GL.Instance.Clear(GL.GL_STENCIL_BUFFER_BIT);      // this seems not working.
                    // do the same thing.
                    this.depthTest.On();                              // Disable depth test to make sure this node works for every stencil point.
                    this.depthMask.On();                              // Disable writing to depth buffer.
                    this.clearStencilNode.RenderBeforeChildren(null); // this helps clear stencil buffer because `glClear(GL_STENCIL_BUFFER_BIT);` doesn't work on my laptop.
                    this.depthMask.Off();
                    this.depthTest.Off();
                }
                // Extrude shadow volume and save shadow info into stencil buffer.
                {
                    this.depthMask.On(); // Disable writing to depth buffer.
                    if (!displayShadowVolume)
                    {
                        this.colorMask.On();
                    }                                                  // Disable writing to color buffer.
                    else
                    {
                        this.polygonMode.On(); this.lineSipple.On();
                    }
                    this.cullFace.On();                             // Disable culling face.
                    GL.Instance.StencilFunc(GL.GL_ALWAYS, 0, 0xFF); // always pass stencil test.
                    // If depth test fails for back face, increase value in stencil buffer.
                    glStencilOpSeparate(GL.GL_BACK, GL.GL_KEEP, GL.GL_INCR_WRAP, GL.GL_KEEP);
                    // If depth test fails for front face, decrease value in stencil buffer.
                    glStencilOpSeparate(GL.GL_FRONT, GL.GL_KEEP, GL.GL_DECR_WRAP, GL.GL_KEEP);

                    // Extrude shadow volume. And shadow info will be saved into stencil buffer automatically according to `glStencilOp...`.
                    var arg = new ShadowVolumeExtrudeEventArgs(param, scene.Camera, light);
                    Extrude(scene.RootNode, arg);

                    this.cullFace.Off();
                    if (!displayShadowVolume)
                    {
                        this.colorMask.Off();
                    }
                    else
                    {
                        this.polygonMode.Off(); this.lineSipple.Off();
                    }
                    this.depthMask.Off();
                }
                //
                {
                    // Draw only if the corresponding stencil value is zero.
                    GL.Instance.StencilFunc(GL.GL_EQUAL, 0x0, 0xFF);
                    // prevent updating to the stencil buffer.
                    GL.Instance.StencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP);

                    this.blend.On(); // add illuminated color to ambient color.

                    // light the scene up.
                    var arg = new ShadowVolumeUnderLightEventArgs(param, scene.Camera, light);
                    RenderUnderLight(scene.RootNode, arg);

                    this.blend.Off();
                }
            }
            this.stencilTest.Off();

            this.depthClamp.Off();
        }