Example #1
0
        ///<summary>
        ///    Collect rendering passes. Here, passes are converted into render target operations
        ///    and queued with queueRenderSystemOp.
        ///</summary>
        protected void CollectPasses(CompositorTargetOperation finalState, CompositionTargetPass target)
        {
            /// Here, passes are converted into render target operations
            Pass      targetpass;
            Technique srctech;
            Material  srcmat;

            foreach (CompositionPass pass in target.Passes)
            {
                switch (pass.Type)
                {
                case CompositorPassType.Clear:
                    QueueRenderSystemOp(finalState, new RSClearOperation(
                                            pass.ClearBuffers,
                                            pass.ClearColor,
                                            pass.ClearDepth,
                                            pass.ClearStencil));
                    break;

                case CompositorPassType.Stencil:
                    QueueRenderSystemOp(finalState, new RSStencilOperation(
                                            pass.StencilCheck, pass.StencilFunc, pass.StencilRefValue,
                                            pass.StencilMask, pass.StencilFailOp, pass.StencilDepthFailOp,
                                            pass.StencilPassOp, pass.StencilTwoSidedOperation
                                            ));
                    break;

                case CompositorPassType.RenderScene:
                    if ((int)pass.FirstRenderQueue < (int)finalState.CurrentQueueGroupID)
                    {
                        /// Mismatch -- warn user
                        /// XXX We could support repeating the last queue, with some effort
                        LogManager.Instance.Write("Warning in compilation of Compositor "
                                                  + compositor.Name + ": Attempt to render queue " +
                                                  pass.FirstRenderQueue + " before " +
                                                  finalState.CurrentQueueGroupID);
                    }
                    /// Add render queues
                    for (RenderQueueGroupID x = pass.FirstRenderQueue; x <= pass.LastRenderQueue; ++x)
                    {
                        Debug.Assert(x >= 0);
                        finalState.RenderQueues[(int)x] = true;
                    }
                    finalState.CurrentQueueGroupID = (RenderQueueGroupID)((int)pass.LastRenderQueue + 1);
                    finalState.FindVisibleObjects  = true;
                    finalState.MaterialScheme      = target.MaterialScheme;

                    break;

                case CompositorPassType.RenderQuad:
                    srcmat = pass.Material;
                    if (srcmat == null)
                    {
                        /// No material -- warn user
                        LogManager.Instance.Write("Warning in compilation of Compositor "
                                                  + compositor.Name + ": No material defined for composition pass");
                        break;
                    }
                    srcmat.Load();
                    if (srcmat.SupportedTechniques.Count == 0)
                    {
                        /// No supported techniques -- warn user
                        LogManager.Instance.Write("Warning in compilation of Compositor "
                                                  + compositor.Name + ": material " + srcmat.Name + " has no supported techniques");
                        break;
                    }
                    srctech = srcmat.GetBestTechnique(0);
                    /// Create local material
                    Material localMat = CreateLocalMaterial();
                    /// Copy and adapt passes from source material
                    for (int i = 0; i < srctech.NumPasses; i++)
                    {
                        Pass srcpass = srctech.GetPass(i);
                        /// Create new target pass
                        targetpass = localMat.GetTechnique(0).CreatePass();
                        srcpass.CopyTo(targetpass);
                        /// Set up inputs
                        int numInputs = pass.GetNumInputs();
                        for (int x = 0; x < numInputs; x++)
                        {
                            string inp = pass.Inputs[x];
                            if (inp != string.Empty)
                            {
                                if (x < targetpass.NumTextureUnitStages)
                                {
                                    targetpass.GetTextureUnitState(x).SetTextureName(GetSourceForTex(inp));
                                }
                                else
                                {
                                    /// Texture unit not there
                                    LogManager.Instance.Write("Warning in compilation of Compositor "
                                                              + compositor.Name + ": material " + srcmat.Name + " texture unit "
                                                              + x + " out of bounds");
                                }
                            }
                        }
                    }
                    QueueRenderSystemOp(finalState, new RSQuadOperation(this, pass.Identifier, localMat));
                    break;
                }
            }
        }
        /// <summary>
        ///		Internal method for splitting the passes into illumination passes.
        /// </summary>
        public void CompileIlluminationPasses()
        {
            ClearIlluminationPasses();

            // don't need to split transparent passes since they are rendered seperately
            if (this.IsTransparent)
            {
                return;
            }

            // start off with ambient passes
            IlluminationStage stage = IlluminationStage.Ambient;

            bool hasAmbient = false;

            for (int i = 0; i < passes.Count; /* increment in logic */)
            {
                Pass             pass = (Pass)passes[i];
                IlluminationPass iPass;

                switch (stage)
                {
                case IlluminationStage.Ambient:
                    // keep looking for ambient only
                    if (pass.IsAmbientOnly)
                    {
                        iPass = new IlluminationPass();
                        iPass.OriginalPass = pass;
                        iPass.Pass         = pass;
                        iPass.Stage        = stage;
                        illuminationPasses.Add(iPass);
                        hasAmbient = true;

                        // progress to the next pass
                        i++;
                    }
                    else
                    {
                        // split off any ambient part
                        if (pass.Ambient.CompareTo(ColorEx.Black) != 0 ||
                            pass.Emissive.CompareTo(ColorEx.Black) != 0 ||
                            pass.AlphaRejectFunction != CompareFunction.AlwaysPass)
                        {
                            Pass newPass = new Pass(this, pass.Index);
                            pass.CopyTo(newPass);
                            if (newPass.AlphaRejectFunction != CompareFunction.AlwaysPass)
                            {
                                // Alpha rejection passes must retain their transparency, so
                                // we allow the texture units, but override the colour functions
                                for (int tindex = 0; tindex < newPass.NumTextureUnitStages; tindex++)
                                {
                                    TextureUnitState tus = newPass.GetTextureUnitState(tindex);
                                    tus.SetColorOperationEx(LayerBlendOperationEx.Source1, LayerBlendSource.Current, LayerBlendSource.Current);
                                }
                            }
                            else
                            {
                                // remove any texture units
                                newPass.RemoveAllTextureUnitStates();
                            }

                            // also remove any fragment program
                            if (newPass.HasFragmentProgram)
                            {
                                newPass.SetFragmentProgram("");
                            }

                            // We have to leave vertex program alone (if any) and
                            // just trust that the author is using light bindings, which
                            // we will ensure there are none in the ambient pass
                            newPass.Diffuse  = new ColorEx(newPass.Diffuse.a, 0f, 0f, 0f);                                    // Preserving alpha
                            newPass.Specular = ColorEx.Black;

                            // Calculate hash value for new pass, because we are compiling
                            // illumination passes on demand, which will loss hash calculate
                            // before it add to render queue first time.
                            newPass.RecalculateHash();

                            iPass = new IlluminationPass();
                            iPass.DestroyOnShutdown = true;
                            iPass.OriginalPass      = pass;
                            iPass.Pass  = newPass;
                            iPass.Stage = stage;

                            illuminationPasses.Add(iPass);
                            hasAmbient = true;
                        }

                        if (!hasAmbient)
                        {
                            // make up a new basic pass
                            Pass newPass = new Pass(this, pass.Index);
                            pass.CopyTo(newPass);

                            newPass.Ambient = ColorEx.Black;
                            newPass.Diffuse = ColorEx.Black;

                            // Calculate hash value for new pass, because we are compiling
                            // illumination passes on demand, which will loss hash calculate
                            // before it add to render queue first time.
                            newPass.RecalculateHash();

                            iPass = new IlluminationPass();
                            iPass.DestroyOnShutdown = true;
                            iPass.OriginalPass      = pass;
                            iPass.Pass  = newPass;
                            iPass.Stage = stage;
                            illuminationPasses.Add(iPass);
                            hasAmbient = true;
                        }

                        // this means we are done with ambients, progress to per-light
                        stage = IlluminationStage.PerLight;
                    }

                    break;

                case IlluminationStage.PerLight:
                    if (pass.RunOncePerLight)
                    {
                        // if this is per-light already, use it directly
                        iPass = new IlluminationPass();
                        iPass.DestroyOnShutdown = false;
                        iPass.OriginalPass      = pass;
                        iPass.Pass  = pass;
                        iPass.Stage = stage;
                        illuminationPasses.Add(iPass);

                        // progress to the next pass
                        i++;
                    }
                    else
                    {
                        // split off per-light details (can only be done for one)
                        if (pass.LightingEnabled &&
                            (pass.Diffuse.CompareTo(ColorEx.Black) != 0 ||
                             pass.Specular.CompareTo(ColorEx.Black) != 0))
                        {
                            // copy existing pass
                            Pass newPass = new Pass(this, pass.Index);
                            pass.CopyTo(newPass);

                            if (newPass.AlphaRejectFunction != CompareFunction.AlwaysPass)
                            {
                                // Alpha rejection passes must retain their transparency, so
                                // we allow the texture units, but override the colour functions
                                for (int tindex = 0; tindex < newPass.NumTextureUnitStages; tindex++)
                                {
                                    TextureUnitState tus = newPass.GetTextureUnitState(tindex);
                                    tus.SetColorOperationEx(LayerBlendOperationEx.Source1, LayerBlendSource.Current, LayerBlendSource.Current);
                                }
                            }
                            else
                            {
                                // remove any texture units
                                newPass.RemoveAllTextureUnitStates();
                            }

                            // also remove any fragment program
                            if (newPass.HasFragmentProgram)
                            {
                                newPass.SetFragmentProgram("");
                            }

                            // Cannot remove vertex program, have to assume that
                            // it will process diffuse lights, ambient will be turned off
                            newPass.Ambient  = ColorEx.Black;
                            newPass.Emissive = ColorEx.Black;

                            // must be additive
                            newPass.SetSceneBlending(SceneBlendFactor.One, SceneBlendFactor.One);

                            iPass = new IlluminationPass();
                            iPass.DestroyOnShutdown = true;
                            iPass.OriginalPass      = pass;
                            iPass.Pass  = newPass;
                            iPass.Stage = stage;

                            illuminationPasses.Add(iPass);
                        }

                        // This means the end of per-light passes
                        stage = IlluminationStage.Decal;
                    }

                    break;

                case IlluminationStage.Decal:
                    // We just want a 'lighting off' pass to finish off
                    // and only if there are texture units
                    if (pass.NumTextureUnitStages > 0)
                    {
                        if (!pass.LightingEnabled)
                        {
                            // we assume this pass already combines as required with the scene
                            iPass = new IlluminationPass();
                            iPass.DestroyOnShutdown = false;
                            iPass.OriginalPass      = pass;
                            iPass.Pass  = pass;
                            iPass.Stage = stage;
                            illuminationPasses.Add(iPass);
                        }
                        else
                        {
                            // Copy the pass and tweak away the lighting parts
                            Pass newPass = new Pass(this, pass.Index);
                            pass.CopyTo(newPass);
                            newPass.Ambient         = ColorEx.Black;
                            newPass.Diffuse         = new ColorEx(newPass.Diffuse.a, 0f, 0f, 0f);                             // Preserving alpha
                            newPass.Specular        = ColorEx.Black;
                            newPass.Emissive        = ColorEx.Black;
                            newPass.LightingEnabled = false;
                            // modulate
                            newPass.SetSceneBlending(SceneBlendFactor.DestColor, SceneBlendFactor.Zero);

                            // Calculate hash value for new pass, because we are compiling
                            // illumination passes on demand, which will loss hash calculate
                            // before it add to render queue first time.
                            newPass.RecalculateHash();

                            // there is nothing we can do about vertex & fragment
                            // programs here, so people will just have to make their
                            // programs friendly-like if they want to use this technique
                            iPass = new IlluminationPass();
                            iPass.DestroyOnShutdown = true;
                            iPass.OriginalPass      = pass;
                            iPass.Pass  = newPass;
                            iPass.Stage = stage;
                            illuminationPasses.Add(iPass);
                        }
                    }

                    // always increment on decal, since nothing more to do with this pass
                    i++;

                    break;
                }
            }
        }