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; } } }