/// <summary> /// Copy the details of this pass to the target pass. /// </summary> /// <param name="target">Destination pass to copy this pass's attributes to.</param> public void CopyTo(Pass target) { target.name = name; target.hashCode = hashCode; // surface target.ambient = ambient.Clone(); target.diffuse = diffuse.Clone(); target.specular = specular.Clone(); target.emissive = emissive.Clone(); target.shininess = shininess; target.tracking = tracking; // fog target.fogOverride = fogOverride; target.fogMode = fogMode; target.fogColor = fogColor.Clone(); target.fogStart = fogStart; target.fogEnd = fogEnd; target.fogDensity = fogDensity; // default blending target.sourceBlendFactor = sourceBlendFactor; target.destBlendFactor = destBlendFactor; target.depthCheck = depthCheck; target.depthWrite = depthWrite; target.alphaRejectFunction = alphaRejectFunction; target.alphaRejectValue = alphaRejectValue; target.colorWrite = colorWrite; target.depthFunc = depthFunc; target.depthBiasConstant = depthBiasConstant; target.depthBiasSlopeScale = depthBiasSlopeScale; target.cullMode = cullMode; target.manualCullMode = manualCullMode; target.lightingEnabled = lightingEnabled; target.maxLights = maxLights; target.startLight = startLight; target.runOncePerLight = runOncePerLight; target.lightsPerIteration = lightsPerIteration; target.runOnlyForOneLightType = runOnlyForOneLightType; target.onlyLightType = onlyLightType; target.shadeOptions = shadeOptions; target.sceneDetail = sceneDetail; target.passIterationCount = passIterationCount; target.pointSize = pointSize; target.pointMinSize = pointMinSize; target.pointMaxSize = pointMaxSize; target.pointSpritesEnabled = pointSpritesEnabled; target.pointAttenuationEnabled = pointAttenuationEnabled; target.pointAttenuationConstant = pointAttenuationConstant; target.pointAttenuationLinear = pointAttenuationLinear; target.pointAttenuationQuadratic = pointAttenuationQuadratic; target.contentTypeLookupBuilt = contentTypeLookupBuilt; // vertex program if(vertexProgramUsage != null) { target.vertexProgramUsage = vertexProgramUsage.Clone(); } else { target.vertexProgramUsage = null; } // shadow caster vertex program if (shadowCasterVertexProgramUsage != null) { target.shadowCasterVertexProgramUsage = shadowCasterVertexProgramUsage.Clone(); } else { target.shadowCasterVertexProgramUsage = null; } // shadow receiver vertex program if (shadowReceiverVertexProgramUsage != null) { target.shadowReceiverVertexProgramUsage = shadowReceiverVertexProgramUsage.Clone(); } else { target.shadowReceiverVertexProgramUsage = null; } // fragment program if(fragmentProgramUsage != null) { target.fragmentProgramUsage = fragmentProgramUsage.Clone(); } else { target.fragmentProgramUsage = null; } // shadow caster fragment program if (shadowCasterFragmentProgramUsage != null) { target.shadowCasterFragmentProgramUsage = shadowCasterFragmentProgramUsage.Clone(); } else { target.shadowCasterFragmentProgramUsage = null; } // shadow receiver fragment program if(shadowReceiverFragmentProgramUsage != null) { target.shadowReceiverFragmentProgramUsage = shadowReceiverFragmentProgramUsage.Clone(); } else { target.shadowReceiverFragmentProgramUsage = null; } // texture units target.RemoveAllTextureUnitStates(); for(int i = 0; i < textureUnitStates.Count; i++) { TextureUnitState newState = new TextureUnitState(target); TextureUnitState src = (TextureUnitState)textureUnitStates[i]; src.CopyTo(newState); target.textureUnitStates.Add(newState); } target.DirtyHash(); }
/// <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 newPass = new Pass( this, pass.Index ); pass.CopyTo( newPass ); // 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 = ColorEx.Black; newPass.Specular = ColorEx.Black; // if ambient and emissive are zero, then color write isn't needed if ( newPass.Ambient.CompareTo( ColorEx.Black ) == 0 && newPass.Emissive.CompareTo( ColorEx.Black ) == 0 ) { newPass.ColorWriteEnabled = false; } 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; 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.IteratePerLight ) { // 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 ); 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.TextureUnitStageCount > 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 = ColorEx.Black; newPass.Specular = ColorEx.Black; newPass.Emissive = ColorEx.Black; newPass.LightingEnabled = false; // modulate newPass.SetSceneBlending( SceneBlendFactor.DestColor, SceneBlendFactor.Zero ); // 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; } } _compiledIlluminationPasses = true; }
/// <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; } } }