Example #1
0
        protected override void CreateScene()
        {
            // set ambient light
            scene.AmbientLight = new ColorEx(0.2f, 0.2f, 0.2f);

            scene.SetSkyBox(true, "Skybox/Morning", 5000);

            // create a default point light
            Light light = scene.CreateLight("MainLight");

            light.Type = LightType.Directional;
            Vector3 dir = new Vector3(0.5f, -1, 0);

            dir.Normalize();
            light.Direction = dir;
            light.Diffuse   = new ColorEx(1.0f, 1.0f, 0.8f);
            light.Specular  = ColorEx.White;

            // create a plane
            plane        = new MovablePlane("ReflectPlane");
            plane.D      = 0;
            plane.Normal = Vector3.UnitY;

            // create another plane to create the mesh.  Ogre's MovablePlane uses multiple inheritance, bah!
            Plane tmpPlane = new Plane();

            tmpPlane.D      = 0;
            tmpPlane.Normal = Vector3.UnitY;

            MeshManager.Instance.CreatePlane("ReflectionPlane", tmpPlane, 2000, 2000, 1, 1, true, 1, 1, 1, Vector3.UnitZ);
            planeEntity = scene.CreateEntity("Plane", "ReflectionPlane");

            // create an entity from a model
            Entity knot = scene.CreateEntity("Knot", "knot.mesh");

            knot.MaterialName = "TextureFX/Knot";

            // create an entity from a model
            Entity head = scene.CreateEntity("Head", "ogrehead.mesh");

            // attach the render to texture entity to the root of the scene
            SceneNode rootNode = scene.RootSceneNode;

            planeNode = rootNode.CreateChildSceneNode();

            planeNode.AttachObject(planeEntity);
            planeNode.AttachObject(plane);
            planeNode.Translate(new Vector3(0, -10, 0));

            // tilt it a little to make it interesting
            planeNode.Roll(5);

            rootNode.CreateChildSceneNode("Head").AttachObject(head);

            // create a render texture
            RenderTexture rttTex = Root.Instance.RenderSystem.CreateRenderTexture("RttTex", 512, 512);

            reflectCam             = scene.CreateCamera("ReflectCam");
            reflectCam.Near        = camera.Near;
            reflectCam.Far         = camera.Far;
            reflectCam.AspectRatio = (float)window.GetViewport(0).ActualWidth / (float)window.GetViewport(0).ActualHeight;

            Viewport viewport = rttTex.AddViewport(reflectCam);

            viewport.ClearEveryFrame = true;
            viewport.OverlaysEnabled = false;
            viewport.BackgroundColor = ColorEx.Black;

            Material         mat = scene.CreateMaterial("RttMat");
            TextureUnitState t   = mat.GetTechnique(0).GetPass(0).CreateTextureUnitState("RustedMetal.jpg");

            t = mat.GetTechnique(0).GetPass(0).CreateTextureUnitState("RttTex");

            // blend with base texture
            t.SetColorOperationEx(LayerBlendOperationEx.BlendManual, LayerBlendSource.Texture, LayerBlendSource.Current,
                                  ColorEx.White, ColorEx.White, 0.25f);

            t.SetProjectiveTexturing(true, reflectCam);

            // register events for viewport before/after update
            rttTex.AfterUpdate  += new RenderTargetUpdateEventHandler(rttTex_AfterUpdate);
            rttTex.BeforeUpdate += new RenderTargetUpdateEventHandler(rttTex_BeforeUpdate);

            // set up linked reflection
            reflectCam.EnableReflection(plane);

            // also clip
            reflectCam.EnableCustomNearClipPlane(plane);

            planeEntity.MaterialName = "RttMat";

            Entity clone = null;

            for (int i = 0; i < 10; i++)
            {
                // create a new node under the root
                SceneNode node = scene.CreateSceneNode();

                // calculate a random position
                Vector3 nodePosition = new Vector3();
                nodePosition.x = MathUtil.SymmetricRandom() * 750.0f;
                nodePosition.y = MathUtil.SymmetricRandom() * 100.0f + 25;
                nodePosition.z = MathUtil.SymmetricRandom() * 750.0f;

                // set the new position
                node.Position = nodePosition;

                // attach this node to the root node
                rootNode.AddChild(node);

                // clone the knot
                string cloneName = string.Format("Knot{0}", i);
                clone = knot.Clone(cloneName);

                // add the cloned knot to the scene
                node.AttachObject(clone);
            }

            camera.Position = new Vector3(-50, 100, 500);
            camera.LookAt(new Vector3(0, 0, 0));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="meshName"></param>
        private void PrepareEntity(string meshName)
        {
            if (objectEntity != null)
            {
                ClearEntity();
            }

            // load mesh if necessary
            originalMesh = (Mesh)MeshManager.Instance.GetByName(meshName);

            // load mesh with shadow buffer so we can do fast reads
            if (originalMesh == null)
            {
                originalMesh = (Mesh)MeshManager.Instance.Load(
                    meshName,
                    BufferUsage.StaticWriteOnly,
                    BufferUsage.StaticWriteOnly,
                    true, true, 1);

                if (originalMesh == null)
                {
                    throw new Exception(string.Format("Can't find mesh named '{0}'.", meshName));
                }
            }

            PrepareClonedMesh();

            // create a new entity based on the cloned mesh
            objectEntity = scene.CreateEntity(ENTITY_NAME, MESH_NAME);

            // setting the material here propogates it down to cloned sub entites, no need to clone them
            objectEntity.MaterialName = material.Name;

            Pass pass = material.GetTechnique(0).GetPass(0);

            // add original sub mesh texture layers after the new cube map recently added
            for (int i = 0; i < clonedMesh.SubMeshCount; i++)
            {
                SubMesh   subMesh   = clonedMesh.GetSubMesh(i);
                SubEntity subEntity = objectEntity.GetSubEntity(i);

                // does this mesh have its own material set?
                if (subMesh.IsMaterialInitialized)
                {
                    string   matName = subMesh.MaterialName;
                    Material subMat  = MaterialManager.Instance.GetByName(matName);

                    if (subMat != null)
                    {
                        subMat.Load();

                        // Clone the sub entities material
                        Material cloned     = subMat.Clone(string.Format("CubeMapTempMaterial#{0}", i));
                        Pass     clonedPass = cloned.GetTechnique(0).GetPass(0);

                        // add global texture layers to the existing material of the entity
                        for (int j = 0; j < pass.NumTextureUnitStages; j++)
                        {
                            TextureUnitState orgLayer = pass.GetTextureUnitState(j);
                            TextureUnitState newLayer = clonedPass.CreateTextureUnitState(orgLayer.TextureName);
                            orgLayer.CopyTo(newLayer);
                            newLayer.SetColorOperationEx(currentLbx);
                        }

                        // set the new material for the subentity and cache it
                        subEntity.MaterialName = cloned.Name;
                        clonedMaterials.Add(cloned);
                    }
                }
            }

            // attach the entity to the scene
            objectNode.AttachObject(objectEntity);

            // update noise if currently set to on
            if (noiseOn)
            {
                UpdateNoise();
            }
        }
        /// <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;
                }
            }
        }