public GetTextureUnitState ( int index ) : |
||
index | int | Index of the state to retreive. |
return |
public override bool PreAddToRenderState( TargetRenderState targetRenderState, Pass srcPass, Pass dstPass ) { //count the number of texture units we need to process int validTexUnits = 0; for ( int i = 0; i < srcPass.TextureUnitStatesCount; i++ ) { if ( IsProcessingNeeded( srcPass.GetTextureUnitState( i ) ) ) { validTexUnits++; } } SetTextureUnitCount( validTexUnits ); //Build texture stage sub states for ( int i = 0; i < srcPass.TextureUnitStatesCount; i++ ) { TextureUnitState texUnitState = srcPass.GetTextureUnitState( i ); if ( IsProcessingNeeded( texUnitState ) ) { SetTextureUnit( i, texUnitState ); } } return true; }
/// <summary> /// Internal utility method for rendering a single object. /// </summary> /// <param name="renderable">The renderable to issue to the pipeline.</param> /// <param name="pass">The pass which is being used.</param> /// <param name="doLightIteration">If true, this method will issue the renderable to /// the pipeline possibly multiple times, if the pass indicates it should be /// done once per light.</param> /// <param name="manualLightList">Only applicable if 'doLightIteration' is false, this /// method allows you to pass in a previously determined set of lights /// which will be used for a single render of this object.</param> protected virtual void RenderSingleObject( IRenderable renderable, Pass pass, bool doLightIteration, LightList manualLightList ) { ushort numMatrices = 0; // grab the current scene detail level PolygonMode camPolyMode = this.cameraInProgress.PolygonMode; // get the world matrices and the count renderable.GetWorldTransforms( this.xform ); numMatrices = renderable.NumWorldTransforms; // set the world matrices in the render system if ( numMatrices > 1 ) { this.targetRenderSystem.SetWorldMatrices( this.xform, numMatrices ); } else { this.targetRenderSystem.WorldMatrix = this.xform[ 0 ]; } // issue view/projection changes (if any) this.UseRenderableViewProjection( renderable ); if ( !this.suppressRenderStateChanges ) { bool passSurfaceAndLightParams = true; if ( pass.IsProgrammable ) { // Tell auto params object about the renderable change this.autoParamDataSource.Renderable = renderable; pass.UpdateAutoParamsNoLights( this.autoParamDataSource ); if ( pass.HasVertexProgram ) { passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates; } } // issue texture units that depend on updated view matrix // reflective env mapping is one case for ( int i = 0; i < pass.TextureUnitStageCount; i++ ) { TextureUnitState texUnit = pass.GetTextureUnitState( i ); if ( texUnit.HasViewRelativeTexCoordGen ) { targetRenderSystem.SetTextureUnitSettings( i, texUnit ); //this.targetRenderSystem.SetTextureUnit( i, texUnit, !pass.HasFragmentProgram ); } } // Normalize normals bool thisNormalize = renderable.NormalizeNormals; if ( thisNormalize != normalizeNormals ) { this.targetRenderSystem.NormalizeNormals = thisNormalize; normalizeNormals = thisNormalize; } // Set up the solid / wireframe override PolygonMode requestedMode = pass.PolygonMode; if ( renderable.PolygonModeOverrideable == true ) { // check camera detial only when render detail is overridable if ( requestedMode > camPolyMode ) { // only downgrade detail; if cam says wireframe we don't go up to solid requestedMode = camPolyMode; } } if ( requestedMode != this.lastPolyMode ) { this.targetRenderSystem.PolygonMode = requestedMode; this.lastPolyMode = requestedMode; } // TODO: Add ClipPlanes to RenderSystem.cs // This is removed in OGRE 1.6.0... no need to port - J. Price //targetRenderSystem.ClipPlanes = renderable.ClipPlanes; // get the renderables render operation op = renderable.RenderOperation; // TODO: Add srcRenderable to RenderOperation.cs //op.srcRenderable = renderable; if ( doLightIteration ) { // Here's where we issue the rendering operation to the render system // Note that we may do this once per light, therefore it's in a loop // and the light parameters are updated once per traversal through the // loop LightList rendLightList = renderable.Lights; bool iteratePerLight = pass.IteratePerLight; int numIterations = iteratePerLight ? rendLightList.Count : 1; LightList lightListToUse = null; for ( int i = 0; i < numIterations; i++ ) { // determine light list to use if ( iteratePerLight ) { localLightList.Clear(); // check whether we need to filter this one out if ( pass.RunOnlyOncePerLightType && pass.OnlyLightType != rendLightList[ i ].Type ) { // skip this one continue; } localLightList.Add( rendLightList[ i ] ); lightListToUse = localLightList; } else { // use complete light list lightListToUse = rendLightList; } if ( pass.IsProgrammable ) { // Update any automatic gpu params for lights // Other bits of information will have to be looked up this.autoParamDataSource.SetCurrentLightList( lightListToUse ); pass.UpdateAutoParamsLightsOnly( this.autoParamDataSource ); UpdateGpuProgramParameters( pass ); } // Do we need to update light states? // Only do this if fixed-function vertex lighting applies if ( pass.LightingEnabled && passSurfaceAndLightParams ) { this.targetRenderSystem.UseLights( lightListToUse, pass.MaxSimultaneousLights ); } this.targetRenderSystem.CurrentPassIterationCount = pass.IterationCount; // issue the render op this.targetRenderSystem.Render( op ); } // iterate per light } else { // do we need to update GPU program parameters? if ( pass.IsProgrammable ) { // do we have a manual light list if ( manualLightList != null ) { // Update any automatic gpu params for lights // Other bits of information will have to be looked up this.autoParamDataSource.SetCurrentLightList( manualLightList ); pass.UpdateAutoParamsLightsOnly( this.autoParamDataSource ); } UpdateGpuProgramParameters( pass ); } // Use manual lights if present, and not using vertex programs if ( manualLightList != null && pass.LightingEnabled && passSurfaceAndLightParams ) { this.targetRenderSystem.UseLights( manualLightList, pass.MaxSimultaneousLights ); } this.targetRenderSystem.CurrentPassIterationCount = pass.IterationCount; // issue the render op this.targetRenderSystem.Render( op ); } } else { // suppressRenderStateChanges // Just render this.targetRenderSystem.CurrentPassIterationCount = 1; this.targetRenderSystem.Render( op ); } // Reset view / projection changes if any this.ResetViewProjectionMode(); }
/// <summary>Internal method for setting up the renderstate for a rendering pass.</summary> /// <param name="pass">The Pass details to set.</param> /// <param name="evenIfSuppressed"> /// Sets the pass details even if render state /// changes are suppressed; if you are using this to manually set state /// when render state changes are suppressed, you should set this to true. /// </param> /// <param name="shadowDerivation"> /// If false, disables the derivation of shadow passes from original passes /// </param> /// <returns> /// A Pass object that was used instead of the one passed in, can /// happen when rendering shadow passes /// </returns> public virtual Pass SetPass( Pass pass, bool evenIfSuppressed, bool shadowDerivation ) { if ( !this.suppressRenderStateChanges || evenIfSuppressed ) { if ( this.illuminationStage == IlluminationRenderStage.RenderToTexture && shadowDerivation ) { // Derive a special shadow caster pass from this one pass = this.DeriveShadowCasterPass( pass ); } else if ( this.illuminationStage == IlluminationRenderStage.RenderReceiverPass ) { pass = this.DeriveShadowReceiverPass( pass ); } //TODO :autoParamDataSource.SetPass( pass ); bool passSurfaceAndLightParams = true; if ( pass.HasVertexProgram ) { this.targetRenderSystem.BindGpuProgram( pass.VertexProgram.BindingDelegate ); // bind parameters later since they can be per-object // does the vertex program want surface and light params passed to rendersystem? passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates; } else { // Unbind program? if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Vertex ) ) { this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex ); } // Set fixed-function vertex parameters } if ( passSurfaceAndLightParams ) { // Set surface reflectance properties, only valid if lighting is enabled if ( pass.LightingEnabled ) { this.targetRenderSystem.SetSurfaceParams( pass.Ambient, pass.Diffuse, pass.Specular, pass.Emissive, pass.Shininess, pass.VertexColorTracking ); } // #if NOT_IN_OGRE else { // even with lighting off, we need ambient set to white this.targetRenderSystem.SetSurfaceParams( ColorEx.White, ColorEx.Black, ColorEx.Black, ColorEx.Black, 0, TrackVertexColor.None ); } // #endif // Dynamic lighting enabled? this.targetRenderSystem.LightingEnabled = pass.LightingEnabled; } // Using a fragment program? if ( pass.HasFragmentProgram ) { this.targetRenderSystem.BindGpuProgram( pass.FragmentProgram.BindingDelegate ); // bind parameters later since they can be per-object } else { // Unbind program? if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Fragment ) ) { this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment ); } } // Set fixed-function fragment settings //We need to set fog properties always. In D3D, it applies to shaders prior //to version vs_3_0 and ps_3_0. And in OGL, it applies to "ARB_fog_XXX" in //fragment program, and in other ways, they maybe accessed by gpu program via //"state.fog.XXX". // New fog params can either be from scene or from material // jsw - set the fog for both fixed function and fragment programs ColorEx newFogColor; FogMode newFogMode; float newFogDensity, newFogStart, newFogEnd; // does the pass want to override the fog mode? if ( pass.FogOverride ) { // New fog params from material newFogMode = pass.FogMode; newFogColor = pass.FogColor; newFogDensity = pass.FogDensity; newFogStart = pass.FogStart; newFogEnd = pass.FogEnd; } else { // New fog params from scene newFogMode = this.fogMode; newFogColor = this.fogColor; newFogDensity = this.fogDensity; newFogStart = this.fogStart; newFogEnd = this.fogEnd; } // set fog params /* float fogScale = 1f; if ( newFogMode == FogMode.None ) { fogScale = 0f; } */ // set fog using the render system this.targetRenderSystem.SetFog( newFogMode, newFogColor, newFogDensity, newFogStart, newFogEnd ); // Tell params about ORIGINAL fog // Need to be able to override fixed function fog, but still have // original fog parameters available to a shader that chooses to use // TODO: autoParamDataSource.SetFog( fogMode, fogColor, fogDensity, fogStart, fogEnd ); // The rest of the settings are the same no matter whether we use programs or not // Set scene blending this.targetRenderSystem.SetSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor ); // TODO : Set point parameters //targetRenderSystem.SetPointParameters( // pass.PointSize, // pass.IsPointAttenuationEnabled, // pass.PointAttenuationConstant, // pass.PointAttenuationLinear, // pass.PointAttenuationQuadratic, // pass.PointMinSize, // pass.PointMaxSize // ); //targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled; // TODO : Reset the shadow texture index for each pass //foreach ( TextureUnitState textureUnit in pass.TextureUnitStates ) //{ //} // set all required texture units for this pass, and disable ones not being used int numTextureUnits = this.targetRenderSystem.Capabilities.TextureUnitCount; if ( pass.HasFragmentProgram && pass.FragmentProgram.IsSupported ) { numTextureUnits = pass.FragmentProgram.SamplerCount; } else if ( Config.MaxTextureLayers < this.targetRenderSystem.Capabilities.TextureUnitCount ) { numTextureUnits = Config.MaxTextureLayers; } for ( int i = 0; i < numTextureUnits; i++ ) { if ( i < pass.TextureUnitStageCount ) { TextureUnitState texUnit = pass.GetTextureUnitState( i ); targetRenderSystem.SetTextureUnitSettings( i, texUnit ); //this.targetRenderSystem.SetTextureUnit( i, texUnit, !pass.HasFragmentProgram ); } else { // disable this unit if ( !pass.HasFragmentProgram ) { this.targetRenderSystem.DisableTextureUnit( i ); } } } // Disable remaining texture units targetRenderSystem.DisableTextureUnitsFrom(pass.TextureUnitStageCount); // Depth Settings this.targetRenderSystem.DepthBufferWriteEnabled = pass.DepthWrite; this.targetRenderSystem.DepthBufferCheckEnabled = pass.DepthCheck; this.targetRenderSystem.DepthBufferFunction = pass.DepthFunction; this.targetRenderSystem.SetDepthBias(pass.DepthBiasConstant); // Aplha Reject Settings this.targetRenderSystem.SetAlphaRejectSettings( pass.AlphaRejectFunction, (byte)pass.AlphaRejectValue, pass.IsAlphaToCoverageEnabled ); // Color Write // right now only using on/off, not per channel bool colWrite = pass.ColorWriteEnabled; this.targetRenderSystem.SetColorBufferWriteEnabled( colWrite, colWrite, colWrite, colWrite ); // Culling Mode this.targetRenderSystem.CullingMode = pass.CullingMode; // Shading mode //this.targetRenderSystem.ShadingMode = pass.ShadingMode; // Polygon Mode this.targetRenderSystem.PolygonMode = pass.PolygonMode; // set pass number this.autoParamDataSource.PassNumber = pass.Index; } return pass; }
/// <summary> /// Internal method for turning a regular pass into a shadow receiver pass. /// </summary> /// <remarks> /// This is only used for texture shadows, basically we're trying to /// ensure that objects are rendered with a projective texture. /// This method will usually return a standard single-texture pass for /// all fixed function passes, but will merge in a vertex program /// for passes with vertex programs. /// </remarks> /// <param name="pass"></param> /// <returns></returns> protected virtual Pass DeriveShadowReceiverPass( Pass pass ) { if ( this.IsShadowTechniqueTextureBased ) { Pass retPass; if ( pass.Parent.ShadowReceiverMaterial != null ) { retPass = pass.Parent.ShadowReceiverMaterial.GetBestTechnique().GetPass( 0 ); } else { retPass = ( this.shadowTextureCustomReceiverPass != null ? this.shadowTextureCustomReceiverPass : this.shadowReceiverPass ); } // Does incoming pass have a custom shadow receiver program? if ( pass.ShadowReceiverVertexProgramName != "" ) { retPass.SetVertexProgram( pass.ShadowReceiverVertexProgramName ); GpuProgram prg = retPass.VertexProgram; // Load this program if not done already if ( !prg.IsLoaded ) { prg.Load(); } // Copy params retPass.VertexProgramParameters = pass.ShadowReceiverVertexProgramParameters; // Also have to hack the light autoparams, that is done later } else { if ( retPass == this.shadowTextureCustomReceiverPass ) { if ( this.shadowTextureCustomReceiverPass.VertexProgramName != this.shadowTextureCustomReceiverVertexProgram ) { this.shadowTextureCustomReceiverPass.SetVertexProgram( this.shadowTextureCustomReceiverVertexProgram ); if ( retPass.HasVertexProgram ) { retPass.VertexProgramParameters = this.shadowTextureCustomReceiverVPParams; } } } else { retPass.SetVertexProgram( "" ); } } int keepTUCount; // If additive, need lighting parameters & standard programs if ( this.IsShadowTechniqueAdditive ) { keepTUCount = 1; retPass.LightingEnabled = true; retPass.Ambient = pass.Ambient; retPass.SelfIllumination = pass.SelfIllumination; retPass.Diffuse = pass.Diffuse; retPass.Specular = pass.Specular; retPass.Shininess = pass.Shininess; retPass.SetRunOncePerLight( pass.IteratePerLight, pass.RunOnlyOncePerLightType, pass.OnlyLightType ); // We need to keep alpha rejection settings retPass.SetAlphaRejectSettings( pass.AlphaRejectFunction, pass.AlphaRejectValue ); // Copy texture state, shift up one since 0 is shadow texture int origPassTUCount = pass.TextureUnitStageCount; for ( int t = 0; t < origPassTUCount; ++t ) { int targetIndex = t + 1; TextureUnitState tex = ( retPass.TextureUnitStageCount <= targetIndex ? retPass.CreateTextureUnitState() : retPass.GetTextureUnitState( targetIndex ) ); pass.GetTextureUnitState( t ).CopyTo( tex ); // If programmable, have to adjust the texcoord sets too // D3D insists that texcoordsets match tex unit in programmable mode if ( retPass.HasVertexProgram ) tex.TextureCoordSet = targetIndex; } keepTUCount = origPassTUCount + 1; } else { // need to keep spotlight fade etc keepTUCount = retPass.TextureUnitStageCount; } // Will also need fragment programs since this is a complex light setup if ( pass.ShadowReceiverFragmentProgramName != "" ) { // Have to merge the shadow receiver vertex program in retPass.SetFragmentProgram( pass.ShadowReceiverFragmentProgramName ); GpuProgram prg = retPass.FragmentProgram; // Load this program if not done already if ( !prg.IsLoaded ) { prg.Load(); } // Copy params retPass.FragmentProgramParameters = pass.ShadowReceiverFragmentProgramParameters; // Did we bind a shadow vertex program? if ( pass.HasVertexProgram && !retPass.HasVertexProgram ) { // We didn't bind a receiver-specific program, so bind the original retPass.SetVertexProgram( pass.VertexProgramName ); prg = retPass.VertexProgram; // Load this program if required if ( !prg.IsLoaded ) { prg.Load(); } // Copy params retPass.VertexProgramParameters = pass.VertexProgramParameters; } } else { // Reset any merged fragment programs from last time if ( retPass == this.shadowTextureCustomReceiverPass ) { // reset fp? if ( retPass.FragmentProgramName != this.shadowTextureCustomReceiverFragmentProgram ) { retPass.SetFragmentProgram( this.shadowTextureCustomReceiverFragmentProgram ); if ( retPass.HasFragmentProgram ) { retPass.FragmentProgramParameters = this.shadowTextureCustomReceiverFPParams; } } } else { // Standard shadow receiver pass, reset to no fp retPass.SetFragmentProgram( "" ); } } // Remove any extra texture units while ( retPass.TextureUnitStageCount > keepTUCount ) { retPass.RemoveTextureUnitState( keepTUCount ); } retPass.Load(); return retPass; } else { return pass; } }
/// <summary> /// Internal method for turning a regular pass into a shadow caster pass. /// </summary> /// <remarks> /// This is only used for texture shadows, basically we're trying to /// ensure that objects are rendered solid black. /// This method will usually return the standard solid black pass for /// all fixed function passes, but will merge in a vertex program /// and fudge the AutpoParamDataSource to set black lighting for /// passes with vertex programs. /// </remarks> /// <param name="pass"></param> /// <returns></returns> protected virtual Pass DeriveShadowCasterPass( Pass pass ) { if ( this.IsShadowTechniqueTextureBased ) { Pass retPass; if ( pass.Parent.ShadowCasterMaterial != null ) { retPass = pass.Parent.ShadowCasterMaterial.GetBestTechnique().GetPass( 0 ); } else { retPass = ( this.shadowTextureCustomCasterPass != null ? this.shadowTextureCustomCasterPass : this.shadowCasterPlainBlackPass ); } // Special case alpha-blended passes if ( ( pass.SourceBlendFactor == SceneBlendFactor.SourceAlpha && pass.DestinationBlendFactor == SceneBlendFactor.OneMinusSourceAlpha ) || pass.AlphaRejectFunction != CompareFunction.AlwaysPass ) { // Alpha blended passes must retain their transparency retPass.SetAlphaRejectSettings( pass.AlphaRejectFunction, pass.AlphaRejectValue ); retPass.SetSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor ); retPass.Parent.Parent.TransparencyCastsShadows = true; // So we allow the texture units, but override the color functions // Copy texture state, shift up one since 0 is shadow texture int origPassTUCount = pass.TextureUnitStageCount; for ( int t = 0; t < origPassTUCount; ++t ) { TextureUnitState tex; if ( retPass.TextureUnitStageCount <= t ) { tex = retPass.CreateTextureUnitState(); } else { tex = retPass.GetTextureUnitState( t ); } // copy base state pass.GetTextureUnitState( t ).CopyTo( tex ); // override colour function tex.SetColorOperationEx( LayerBlendOperationEx.Source1, LayerBlendSource.Manual, LayerBlendSource.Current, this.IsShadowTechniqueAdditive ? ColorEx.Black : shadowColor ); } // Remove any extras while ( retPass.TextureUnitStageCount > origPassTUCount ) { retPass.RemoveTextureUnitState( origPassTUCount ); } } else { // reset retPass.SetSceneBlending( SceneBlendType.Replace ); retPass.AlphaRejectFunction = CompareFunction.AlwaysPass; while ( retPass.TextureUnitStageCount > 0 ) { retPass.RemoveTextureUnitState( 0 ); } } // Propogate culling modes retPass.CullingMode = pass.CullingMode; retPass.ManualCullingMode = pass.ManualCullingMode; // Does incoming pass have a custom shadow caster program? if ( pass.ShadowCasterVertexProgramName != "" ) { retPass.SetVertexProgram( pass.ShadowCasterVertexProgramName, false ); GpuProgram prg = retPass.VertexProgram; // Load this program if not done already if ( !prg.IsLoaded ) { prg.Load(); } // Copy params retPass.VertexProgramParameters = pass.ShadowCasterVertexProgramParameters; // Also have to hack the light autoparams, that is done later } else { // reset vp? if ( retPass == this.shadowTextureCustomCasterPass ) { if ( retPass.VertexProgramName != this.shadowTextureCustomCasterVertexProgram ) { this.shadowTextureCustomCasterPass.SetVertexProgram( this.shadowTextureCustomCasterVertexProgram ); if ( retPass.HasVertexProgram ) { retPass.VertexProgramParameters = this.shadowTextureCustomCasterVPParams; } } } else { // Standard shadow caster pass, reset to no vp retPass.SetVertexProgram( "" ); } } return retPass; } else { return pass; } }
/// <summary>Internal method for setting up the renderstate for a rendering pass.</summary> /// <param name="pass">The Pass details to set.</param> /// <param name="evenIfSuppressed"> /// Sets the pass details even if render state /// changes are suppressed; if you are using this to manually set state /// when render state changes are suppressed, you should set this to true. /// </param> /// <param name="shadowDerivation"> /// If false, disables the derivation of shadow passes from original passes /// </param> /// <returns> /// A Pass object that was used instead of the one passed in, can /// happen when rendering shadow passes /// </returns> public virtual Pass SetPass( Pass pass, bool evenIfSuppressed, bool shadowDerivation ) { //If using late material resolving, swap now. if ( IsLateMaterialResolving ) { Technique lateTech = pass.Parent.Parent.GetBestTechnique(); if ( lateTech.PassCount > pass.Index ) { pass = lateTech.GetPass( pass.Index ); } //Should we warn or throw an exception if an illegal state was achieved? } if ( !this.suppressRenderStateChanges || evenIfSuppressed ) { if ( this.illuminationStage == IlluminationRenderStage.RenderToTexture && shadowDerivation ) { // Derive a special shadow caster pass from this one pass = DeriveShadowCasterPass( pass ); } else if ( this.illuminationStage == IlluminationRenderStage.RenderReceiverPass ) { pass = DeriveShadowReceiverPass( pass ); } // Tell params about current pass this.autoParamDataSource.CurrentPass = pass; bool passSurfaceAndLightParams = true; bool passFogParams = true; if ( pass.HasVertexProgram ) { this.targetRenderSystem.BindGpuProgram( pass.VertexProgram.BindingDelegate ); // bind parameters later // does the vertex program want surface and light params passed to rendersystem? passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates; } else { // Unbind program? if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Vertex ) ) { this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex ); } // Set fixed-function vertex parameters } if ( pass.HasGeometryProgram ) { this.targetRenderSystem.BindGpuProgram( pass.GeometryProgram.BindingDelegate ); // bind parameters later } else { // Unbind program? if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Geometry ) ) { this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Geometry ); } // Set fixed-function vertex parameters } if ( passSurfaceAndLightParams ) { // Set surface reflectance properties, only valid if lighting is enabled if ( pass.LightingEnabled ) { this.targetRenderSystem.SetSurfaceParams( pass.Ambient, pass.Diffuse, pass.Specular, pass.SelfIllumination, pass.Shininess, pass.VertexColorTracking ); } // #if NOT_IN_OGRE else { // even with lighting off, we need ambient set to white this.targetRenderSystem.SetSurfaceParams( ColorEx.White, ColorEx.Black, ColorEx.Black, ColorEx.Black, 0, TrackVertexColor.None ); } // #endif // Dynamic lighting enabled? this.targetRenderSystem.LightingEnabled = pass.LightingEnabled; } // Using a fragment program? if ( pass.HasFragmentProgram ) { this.targetRenderSystem.BindGpuProgram( pass.FragmentProgram.BindingDelegate ); // bind parameters later passFogParams = pass.FragmentProgram.PassFogStates; } else { // Unbind program? if ( this.targetRenderSystem.IsGpuProgramBound( GpuProgramType.Fragment ) ) { this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment ); } // Set fixed-function fragment settings } if ( passFogParams ) { // New fog params can either be from scene or from material FogMode newFogMode; ColorEx newFogColour; Real newFogStart, newFogEnd, newFogDensity; if ( pass.FogOverride ) { // New fog params from material newFogMode = pass.FogMode; newFogColour = pass.FogColor; newFogStart = pass.FogStart; newFogEnd = pass.FogEnd; newFogDensity = pass.FogDensity; } else { // New fog params from scene newFogMode = this.fogMode; newFogColour = this.fogColor; newFogStart = this.fogStart; newFogEnd = this.fogEnd; newFogDensity = this.fogDensity; } /* In D3D, it applies to shaders prior to version vs_3_0 and ps_3_0. And in OGL, it applies to "ARB_fog_XXX" in fragment program, and in other ways, them maybe access by gpu program via "state.fog.XXX". */ this.targetRenderSystem.SetFog( newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd ); } // Tell params about ORIGINAL fog // Need to be able to override fixed function fog, but still have // original fog parameters available to a shader that chooses to use this.autoParamDataSource.SetFog( this.fogMode, this.fogColor, this.fogDensity, this.fogStart, this.fogEnd ); // The rest of the settings are the same no matter whether we use programs or not // Set scene blending if ( pass.HasSeparateSceneBlending ) { this.targetRenderSystem.SetSeparateSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor, pass.SourceBlendFactorAlpha, pass.DestinationBlendFactorAlpha, pass.SceneBlendingOperation, pass.HasSeparateSceneBlendingOperations ? pass.SceneBlendingOperation : pass.SceneBlendingOperationAlpha ); } else { if ( pass.HasSeparateSceneBlendingOperations ) { this.targetRenderSystem.SetSeparateSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor, pass.SourceBlendFactor, pass.DestinationBlendFactor, pass.SceneBlendingOperation, pass.SceneBlendingOperationAlpha ); } else { this.targetRenderSystem.SetSceneBlending( pass.SourceBlendFactor, pass.DestinationBlendFactor, pass.SceneBlendingOperation ); } } //TODO Set point parameters //this.targetRenderSystem.SetPointParameters( // pass.PointSize, // pass.IsPointAttenuationEnabled, // pass.PointAttenuationConstant, // pass.PointAttenuationLinear, // pass.PointAttenuationQuadratic, // pass.PointMinSize, // pass.PointMaxSize // ); if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.PointSprites ) ) { this.targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled; } //targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled; // TODO : Reset the shadow texture index for each pass //foreach ( TextureUnitState textureUnit in pass.TextureUnitStates ) //{ //} // set all required texture units for this pass, and disable ones not being used var numTextureUnits = this.targetRenderSystem.Capabilities.TextureUnitCount; if ( pass.HasFragmentProgram && pass.FragmentProgram.IsSupported ) { // Axiom: This effectivley breaks GLSL. // besides this routine aint existing (anymore?) in 1.7.2 // an upgrade of the scenemanager is recommended //numTextureUnits = pass.FragmentProgram.SamplerCount; } else if ( Config.MaxTextureLayers < this.targetRenderSystem.Capabilities.TextureUnitCount ) { numTextureUnits = Config.MaxTextureLayers; } for ( var i = 0; i < numTextureUnits; i++ ) { if ( i < pass.TextureUnitStatesCount ) { var texUnit = pass.GetTextureUnitState( i ); this.targetRenderSystem.SetTextureUnitSettings( i, texUnit ); //this.targetRenderSystem.SetTextureUnit( i, texUnit, !pass.HasFragmentProgram ); } else { // disable this unit if ( !pass.HasFragmentProgram ) { this.targetRenderSystem.DisableTextureUnit( i ); } } } // Disable remaining texture units this.targetRenderSystem.DisableTextureUnitsFrom( pass.TextureUnitStatesCount ); // Depth Settings this.targetRenderSystem.DepthBufferWriteEnabled = pass.DepthWrite; this.targetRenderSystem.DepthBufferCheckEnabled = pass.DepthCheck; this.targetRenderSystem.DepthBufferFunction = pass.DepthFunction; this.targetRenderSystem.SetDepthBias( pass.DepthBiasConstant ); // Aplha Reject Settings this.targetRenderSystem.SetAlphaRejectSettings( pass.AlphaRejectFunction, (byte)pass.AlphaRejectValue, pass.IsAlphaToCoverageEnabled ); // Color Write // right now only using on/off, not per channel var colWrite = pass.ColorWriteEnabled; this.targetRenderSystem.SetColorBufferWriteEnabled( colWrite, colWrite, colWrite, colWrite ); // Culling Mode this.targetRenderSystem.CullingMode = pass.CullingMode; // Shading mode //this.targetRenderSystem.ShadingMode = pass.ShadingMode; // Polygon Mode this.targetRenderSystem.PolygonMode = pass.PolygonMode; // set pass number this.autoParamDataSource.PassNumber = pass.Index; } return pass; }
/// <summary>Internal method for setting up the renderstate for a rendering pass.</summary> /// <param name="pass">The Pass details to set.</param> /// <param name="evenIfSuppressed"> /// Sets the pass details even if render state /// changes are suppressed; if you are using this to manually set state /// when render state changes are suppressed, you should set this to true. /// </param> /// <param name="shadowDerivation"> /// If false, disables the derivation of shadow passes from original passes /// </param> /// <returns> /// A Pass object that was used instead of the one passed in, can /// happen when rendering shadow passes /// </returns> protected virtual Pass SetPass(Pass pass, bool evenIfSuppressed, bool shadowDerivation) { setPassMeter.Enter(); targetRenderSystem.BeginProfileEvent(ColorEx.Green, "SetPass: Material = " + pass.Parent.Parent.Name); totalSetPassCalls++; if (!suppressRenderStateChanges || evenIfSuppressed) { if (illuminationStage == IlluminationRenderStage.RenderToTexture && shadowDerivation) { // Derive a special shadow caster pass from this one pass = DeriveShadowCasterPass(pass); } else if (illuminationStage == IlluminationRenderStage.RenderModulativePass) { pass = DeriveShadowReceiverPass(pass); } // Tell params about current pass autoParamDataSource.CurrentPass = pass; bool passSurfaceAndLightParams = true; //setPassShadersMeter.Enter(); if (pass.HasVertexProgram) { targetRenderSystem.BindGpuProgram(pass.VertexProgram.BindingDelegate); // bind parameters later since they can be per-object // does the vertex program want surface and light params passed to rendersystem? passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates; } else { // Unbind program? if (targetRenderSystem.IsGpuProgramBound(GpuProgramType.Vertex)) { targetRenderSystem.UnbindGpuProgram(GpuProgramType.Vertex); } // Set fixed-function vertex parameters } // Using a fragment program? if (pass.HasFragmentProgram) { targetRenderSystem.BindGpuProgram(pass.FragmentProgram.BindingDelegate); // bind parameters later since they can be per-object } else { // Unbind program? if (targetRenderSystem.IsGpuProgramBound(GpuProgramType.Fragment)) { targetRenderSystem.UnbindGpuProgram(GpuProgramType.Fragment); } } //setPassShadersMeter.Exit(); //setPassLightingFogMeter.Enter(); if (passSurfaceAndLightParams) { // Set surface reflectance properties, only valid if lighting is enabled if (pass.LightingEnabled) { targetRenderSystem.SetSurfaceParams(pass.Ambient, pass.Diffuse, pass.Specular, pass.Emissive, pass.Shininess, pass.VertexColorTracking); // #if NOT } else { // even with lighting off, we need ambient set to white targetRenderSystem.SetSurfaceParams(ColorEx.White, ColorEx.Black, ColorEx.Black, ColorEx.Black, 0, TrackVertexColor.None); // #endif } // Dynamic lighting enabled? targetRenderSystem.LightingEnabled = pass.LightingEnabled; } // Set fixed-function fragment settings // Fog (assumes we want pixel fog which is the usual) // New fog params can either be from scene or from material // jsw - set the fog for both fixed function and fragment programs ColorEx newFogColor; FogMode newFogMode; float newFogDensity, newFogStart, newFogEnd; // does the pass want to override the fog mode? if (pass.FogOverride) { // New fog params from material newFogMode = pass.FogMode; newFogColor = pass.FogColor; newFogDensity = pass.FogDensity; newFogStart = pass.FogStart; newFogEnd = pass.FogEnd; } else { // New fog params from scene newFogMode = fogMode; newFogColor = fogColor; newFogDensity = fogDensity; newFogStart = fogStart; newFogEnd = fogEnd; } // set fog params float fogScale = 1f; if (newFogMode == FogMode.None) fogScale = 0f; // set fog using the render system targetRenderSystem.SetFog(newFogMode, newFogColor, newFogDensity, newFogStart, newFogEnd); // Tell params about ORIGINAL fog Need to be able to // override fixed function fog, but still have // original fog parameters available to a shader than // chooses to use autoParamDataSource.SetFog(fogMode, fogColor, fogStart, fogEnd, fogScale); //setPassLightingFogMeter.Exit(); //setPassEarlyCommonMeter.Enter(); // The rest of the settings are the same no matter whether we use programs or not // Set scene blending targetRenderSystem.SetSceneBlending(pass.SourceBlendFactor, pass.DestBlendFactor); // Set point parameters targetRenderSystem.SetPointParameters(pass.PointSize, pass.PointAttenuationEnabled, pass.PointAttenuationConstant, pass.PointAttenuationLinear, pass.PointAttenuationQuadratic, pass.PointMinSize, pass.PointMaxSize); targetRenderSystem.PointSpritesEnabled = pass.PointSpritesEnabled; //setPassEarlyCommonMeter.Exit(); // Texture unit settings //setPassTexturesMeter.Enter(); // set all required texture units for this pass, and disable ones not being used int numTextureUnits; if (pass.HasFragmentProgram) { numTextureUnits = pass.FragmentProgram.SamplerCount; } else { numTextureUnits = targetRenderSystem.Caps.TextureUnitCount; } int shadowTexIndex = pass.StartLight; for (int i = 0; i < numTextureUnits; i++) { if (i < pass.NumTextureUnitStages) { TextureUnitState texUnit = pass.GetTextureUnitState(i); // If we couldn't load the texture, skip it if (texUnit.Blank) continue; if (pass.RunOncePerLight && IsShadowTechniqueTextureBased && texUnit.ContentType == TextureContentType.Shadow) { // Need to bind the correct shadow texture, based on the start light // Even though the light list can change per object, our restrictions // say that when texture shadows are enabled, the lights up to the // number of texture shadows will be fixed for all objects // to match the shadow textures that have been generated // see ShadowListener::sortLightsAffectingFrustum and // MovableObject::Listener::objectQueryLights // Note that light iteration throws the indexes out so we don't bind here // if that's the case, we have to bind when lights are iterated // in renderSingleObject Texture shadowTex; if (shadowTexIndex < shadowTextures.Count) { shadowTex = shadowTextures[shadowTexIndex]; // Hook up projection frustum Camera cam = shadowTex.GetBuffer().GetRenderTarget().GetViewport(0).Camera; // Only set fixed-function projection if no vertex program if (!pass.HasVertexProgram) texUnit.SetProjectiveTexturing(true, cam); autoParamDataSource.SetTextureProjector(cam, shadowTexIndex); } else { // Use fallback 'null' shadow texture // no projection since all uniform colour anyway shadowTex = nullShadowTexture; texUnit.SetProjectiveTexturing(false, null); autoParamDataSource.SetTextureProjector(null, shadowTexIndex); } texUnit.SetTexturePtr(shadowTex); shadowTexIndex++; } targetRenderSystem.SetTextureUnit(i, texUnit, !pass.HasFragmentProgram); } else { if (pass.HasFragmentProgram) { targetRenderSystem.SetTextureCoordSet(i, i); } else { // Disable the ones that the pass doesn't use. targetRenderSystem.DisableTextureUnit(i); } } } //setPassTexturesMeter.Exit(); //setPassLateCommonMeter.Enter(); // Set up non-texture related material settings // Depth Settings targetRenderSystem.DepthFunction = pass.DepthFunction; targetRenderSystem.DepthCheck = pass.DepthCheck; targetRenderSystem.DepthWrite = pass.DepthWrite; targetRenderSystem.SetDepthBias(pass.DepthBiasConstant, pass.DepthBiasSlopeScale); // Alpha-reject settings targetRenderSystem.SetAlphaRejectSettings(pass.AlphaRejectFunction, (byte)pass.AlphaRejectValue); // Color Write // right now only using on/off, not per channel bool colWrite = pass.ColorWrite; targetRenderSystem.SetColorBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite); // Culling Mode if (IsShadowTechniqueTextureBased && illuminationStage == IlluminationRenderStage.RenderToTexture && shadowCasterRenderBackFaces && pass.CullMode == CullingMode.Clockwise) { // render back faces into shadow caster, can help with depth comparison targetRenderSystem.CullingMode = CullingMode.CounterClockwise; } else targetRenderSystem.CullingMode = pass.CullMode; // Shading mode targetRenderSystem.ShadingMode = pass.ShadingMode; // Polygon mode targetRenderSystem.RasterizationMode = pass.SceneDetail; //setPassLateCommonMeter.Exit(); // set pass number autoParamDataSource.PassNumber = pass.Index; } targetRenderSystem.EndProfileEvent(); setPassMeter.Exit(); return pass; }
/// <summary> /// Internal utility method for rendering a single object. /// </summary> /// <param name="renderable">The renderable to issue to the pipeline.</param> /// <param name="pass">The pass which is being used.</param> /// <param name="doLightIteration">If true, this method will issue the renderable to /// the pipeline possibly multiple times, if the pass indicates it should be /// done once per light.</param> /// <param name="manualLightList">Only applicable if 'doLightIteration' is false, this /// method allows you to pass in a previously determined set of lights /// which will be used for a single render of this object.</param> protected virtual void RenderSingleObject(IRenderable renderable, Pass pass, bool doLightIteration, List<Light> manualLightList) { targetRenderSystem.BeginProfileEvent(ColorEx.Red, "RenderSingleObject: Material = " + renderable.Material.Name); ushort numMatrices = 0; // grab the current scene detail level SceneDetailLevel camDetailLevel = cameraInProgress.SceneDetail; // // update auto params if this is a programmable pass // if(pass.IsProgrammable) { // autoParamDataSource.Renderable = renderable; // pass.UpdateAutoParamsNoLights(autoParamDataSource); // } // get the world matrices and the count renderable.GetWorldTransforms(xform); numMatrices = renderable.NumWorldTransforms; // set the world matrices in the render system if(numMatrices > 1) { targetRenderSystem.SetWorldMatrices(xform, numMatrices); } else { targetRenderSystem.WorldMatrix = xform[0]; } // issue view/projection changes (if any) UseRenderableViewProjection(renderable); if (!suppressRenderStateChanges) { bool passSurfaceAndLightParams = true; if (pass.IsProgrammable) { // Tell auto params object about the renderable change autoParamDataSource.Renderable = renderable; // Tell auto params object about the world matrices, eliminated query from renderable again autoParamDataSource.SetWorldMatrices(xform, numMatrices); pass.UpdateAutoParamsNoLights(autoParamDataSource); if (pass.HasVertexProgram) passSurfaceAndLightParams = pass.VertexProgram.PassSurfaceAndLightStates; } // issue texture units that depend on updated view matrix // reflective env mapping is one case for(int i = 0; i < pass.NumTextureUnitStages; i++) { TextureUnitState texUnit = pass.GetTextureUnitState(i); if(texUnit.HasViewRelativeTexCoordGen) { targetRenderSystem.SetTextureUnit(i, texUnit, !pass.HasFragmentProgram); } } // Normalize normals bool thisNormalize = renderable.NormalizeNormals; if(thisNormalize != normalizeNormals) { targetRenderSystem.NormalizeNormals = thisNormalize; normalizeNormals = thisNormalize; } // Set up the solid / wireframe override SceneDetailLevel requestedDetail = renderable.RenderDetail; if (requestedDetail != lastDetailLevel || requestedDetail != camDetailLevel) { if (requestedDetail > camDetailLevel) { // only downgrade detail; if cam says wireframe we don't go up to solid requestedDetail = camDetailLevel; } targetRenderSystem.RasterizationMode = requestedDetail; lastDetailLevel = requestedDetail; } // TODO: Add ClipPlanes to RenderSystem.cs //targetRenderSystem.ClipPlanes = renderable.ClipPlanes; // get the renderables render operation renderable.GetRenderOperation(op); // TODO: Add srcRenderable to RenderOperation.cs //op.srcRenderable = renderable; if(doLightIteration) { // Here's where we issue the rendering operation to the render system // Note that we may do this once per light, therefore it's in a loop // and the light parameters are updated once per traversal through the // loop doLightMeter.Enter(); if (MeterManager.Collecting) { string s = string.Format("Rendering material '{0}'", renderable.Material.Name); if (renderable is SubEntity) { SubEntity subEntity = (SubEntity)renderable; s += string.Format(", SubMesh '{0}', Entity '{1}'", subEntity.SubMesh.Name, subEntity.Parent.Name); } MeterManager.AddInfoEvent(s); } List<Light> rendLightList = renderable.Lights; bool iteratePerLight = pass.RunOncePerLight; int startLight = pass.StartLight; int lightsLeft = iteratePerLight ? rendLightList.Count - startLight : 1; List<Light> lightListToUse = null; int lightIndex = startLight; while (lightsLeft > 0) { // determine light list to use if(iteratePerLight) { localLightList.Clear(); int lightsPerIteration = pass.LightsPerIteration; int numShadowTextureLights = 0; int lightsConsidered = 0; for (int i=0; i<lightsPerIteration && lightIndex < rendLightList.Count; i++,lightIndex++,lightsLeft--) { // check whether we need to filter this one out lightsConsidered++; if(pass.RunOnlyForOneLightType && pass.OnlyLightType != rendLightList[lightIndex].Type) // skip this one continue; localLightList.Add(rendLightList[lightIndex]); // potentially need to update content_type shadow texunit // corresponding to this light if (IsShadowTechniqueTextureBased && lightIndex < shadowTextures.Count) { // link the numShadowTextureLights'th shadow texture unit int tuindex = pass.GetTextureUnitWithContentTypeIndex( TextureContentType.Shadow, numShadowTextureLights); if (tuindex < pass.NumTextureUnitStages) { TextureUnitState tu = pass.GetTextureUnitState(tuindex); tu.SetTexturePtr(shadowTextures[lightIndex]); Camera cam = shadowTextures[lightIndex].GetBuffer().GetRenderTarget().GetViewport(0).Camera; if (!pass.HasVertexProgram) tu.SetProjectiveTexturing(true, cam); autoParamDataSource.SetTextureProjector(cam, numShadowTextureLights); ++numShadowTextureLights; // Have to set TU on rendersystem right now, although // autoparams will be set later targetRenderSystem.SetTextureUnit(tuindex, tu, !pass.HasFragmentProgram); } } } // Did we run out of lights before slots? e.g. 5 lights, 2 per iteration if (lightsPerIteration != lightsConsidered) lightsLeft = 0; lightListToUse = localLightList; } else { if (startLight != 0) { if (startLight >= rendLightList.Count) { lightsLeft = 0; break; } else { localLightList.Clear(); for (int i=startLight; i<rendLightList.Count; i++) localLightList.Add(rendLightList[i]); lightListToUse = localLightList; } } else // use complete light list lightListToUse = rendLightList; lightsLeft = 0; } if(pass.IsProgrammable) { // Update any automatic gpu params for lights // Other bits of information will have to be looked up updateAutoParmsMeter.Enter(); autoParamDataSource.SetCurrentLightList(lightListToUse); pass.UpdateAutoParamsLightsOnly(autoParamDataSource); updateAutoParmsMeter.Exit(); // note: parameters must be bound after auto params are updated setGpuParmsMeter.Enter(); if(pass.HasVertexProgram) { if (MeterManager.Collecting) MeterManager.AddInfoEvent("Vertex Program " + pass.VertexProgramName); targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Vertex, pass.VertexProgramParameters); } if(pass.HasFragmentProgram) { if (MeterManager.Collecting) MeterManager.AddInfoEvent("Fragment Program " + pass.FragmentProgramName); targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Fragment, pass.FragmentProgramParameters); } setGpuParmsMeter.Exit(); } // Do we need to update light states? // Only do this if fixed-function vertex lighting applies if(pass.LightingEnabled && passSurfaceAndLightParams) { //useLightsMeter.Enter(); targetRenderSystem.UseLights(lightListToUse, pass.MaxLights); //useLightsMeter.Exit(); } // issue the render op renderOpMeter.Enter(); targetRenderSystem.Render(op); renderOpMeter.Exit(); } // iterate per light doLightMeter.Exit(); } else { // do we need to update GPU program parameters? if(pass.IsProgrammable) { // do we have a manual light list if(manualLightList != null) { // Update any automatic gpu params for lights // Other bits of information will have to be looked up autoParamDataSource.SetCurrentLightList(manualLightList); pass.UpdateAutoParamsLightsOnly(autoParamDataSource); } // note: parameters must be bound after auto params are updated if(pass.HasVertexProgram) { targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Vertex, pass.VertexProgramParameters); } if(pass.HasFragmentProgram) { targetRenderSystem.BindGpuProgramParameters(GpuProgramType.Fragment, pass.FragmentProgramParameters); } } // Use manual lights if present, and not using vertex programs if(manualLightList != null && pass.LightingEnabled && passSurfaceAndLightParams) { targetRenderSystem.UseLights(manualLightList, pass.MaxLights); } // issue the render op renderOpMeter.Enter(); targetRenderSystem.Render(op); renderOpMeter.Exit(); } } else { // suppressRenderStateChanges // Just render renderOpMeter.Enter(); targetRenderSystem.Render(op); renderOpMeter.Exit(); } // Reset view / projection changes if any ResetViewProjMode(); targetRenderSystem.EndProfileEvent(); }
/// <summary> /// Internal method for turning a regular pass into a shadow receiver pass. /// </summary> /// <remarks> /// This is only used for texture shadows, basically we're trying to /// ensure that objects are rendered with a projective texture. /// This method will usually return a standard single-texture pass for /// all fixed function passes, but will merge in a vertex program /// for passes with vertex programs. /// </remarks> /// <param name="pass"></param> /// <returns></returns> protected virtual Pass DeriveShadowReceiverPass(Pass pass) { if (IsShadowTechniqueTextureBased) { Pass retPass = (shadowTextureCustomReceiverPass != null ? shadowTextureCustomReceiverPass : shadowReceiverPass); // Does incoming pass have a custom shadow receiver program? if (pass.ShadowReceiverVertexProgramName != "") { retPass.SetVertexProgram(pass.ShadowReceiverVertexProgramName); GpuProgram prg = retPass.VertexProgram; // Load this program if not done already if (!prg.IsLoaded) prg.Load(); // Copy params retPass.VertexProgramParameters = pass.ShadowReceiverVertexProgramParameters; // Also have to hack the light autoparams, that is done later } else { if (retPass == shadowTextureCustomReceiverPass) { if (shadowTextureCustomReceiverPass.VertexProgramName != shadowTextureCustomReceiverVertexProgram) { shadowTextureCustomReceiverPass.SetVertexProgram(shadowTextureCustomReceiverVertexProgram); if (retPass.HasVertexProgram) retPass.VertexProgramParameters = shadowTextureCustomReceiverVPParams; } } else retPass.SetVertexProgram(""); } int keepTUCount; // If additive, need lighting parameters & standard programs if (IsShadowTechniqueAdditive) { keepTUCount = 1; retPass.LightingEnabled = true; retPass.Ambient = pass.Ambient; retPass.Diffuse = pass.Diffuse; retPass.Specular = pass.Specular; retPass.Shininess = pass.Shininess; retPass.SetRunNTimesPerLight(pass.RunOncePerLight, pass.PassIterationCount, pass.LightsPerIteration, pass.RunOnlyForOneLightType, pass.OnlyLightType); int origPassTUCount = pass.NumTextureUnitStages; for (int t = 0; t < origPassTUCount; ++t) { int targetIndex = t+1; TextureUnitState tex = (retPass.NumTextureUnitStages <= targetIndex ? retPass.CreateTextureUnitState() : retPass.GetTextureUnitState(targetIndex)); pass.GetTextureUnitState(t).CopyTo(tex); } keepTUCount = origPassTUCount + 1; // Will also need fragment programs since this is a complex light setup if (pass.ShadowReceiverFragmentProgramName != "") { // Have to merge the shadow receiver vertex program in retPass.SetFragmentProgram(pass.ShadowReceiverFragmentProgramName); GpuProgram prg = retPass.FragmentProgram; // Load this program if not done already if (!prg.IsLoaded) prg.Load(); // Copy params retPass.FragmentProgramParameters = pass.ShadowReceiverFragmentProgramParameters; // Did we bind a shadow vertex program? if (pass.HasVertexProgram && !retPass.HasVertexProgram) { // We didn't bind a receiver-specific program, so bind the original retPass.SetVertexProgram(pass.VertexProgramName); prg = retPass.VertexProgram; // Load this program if required if (!prg.IsLoaded) prg.Load(); // Copy params retPass.VertexProgramParameters = pass.VertexProgramParameters; } } else { // Reset any merged fragment programs from last time if (retPass == shadowTextureCustomReceiverPass) { // reset fp? if (retPass.FragmentProgramName != shadowTextureCustomReceiverFragmentProgram) { retPass.SetFragmentProgram(shadowTextureCustomReceiverFragmentProgram); if(retPass.HasFragmentProgram) retPass.FragmentProgramParameters = shadowTextureCustomReceiverFPParams; } } else // Standard shadow receiver pass, reset to no fp retPass.SetFragmentProgram(""); } } // additive lighting else // need to keep spotlight fade etc keepTUCount = retPass.NumTextureUnitStages; // Remove any extra texture units while (retPass.NumTextureUnitStages > keepTUCount) retPass.RemoveTextureUnitState(keepTUCount); retPass.Load(); return retPass; } else return pass; }
/// <summary> /// Internal method for turning a regular pass into a shadow caster pass. /// </summary> /// <remarks> /// This is only used for texture shadows, basically we're trying to /// ensure that objects are rendered solid black. /// This method will usually return the standard solid black pass for /// all fixed function passes, but will merge in a vertex program /// and fudge the AutpoParamDataSource to set black lighting for /// passes with vertex programs. /// </remarks> /// <param name="pass"></param> /// <returns></returns> protected virtual Pass DeriveShadowCasterPass(Pass pass) { if (IsShadowTechniqueTextureBased) { Pass retPass = (shadowTextureCustomCasterPass != null ? shadowTextureCustomCasterPass : shadowCasterPlainBlackPass); retPass.CullMode = pass.CullMode; retPass.ManualCullMode = pass.ManualCullMode; // Does incoming pass have a custom shadow caster program? if (pass.ShadowCasterVertexProgramName != "") { retPass.SetVertexProgram(pass.ShadowCasterVertexProgramName); GpuProgram prg = retPass.VertexProgram; // Load this program if not done already if (!prg.IsLoaded) prg.Load(); // Copy params retPass.VertexProgramParameters = pass.ShadowCasterVertexProgramParameters; // Also have to hack the light autoparams, that is done later } else { // reset vp? if (retPass == shadowTextureCustomCasterPass) { if (retPass.VertexProgramName != shadowTextureCustomCasterVertexProgram) { shadowTextureCustomCasterPass.SetVertexProgram(shadowTextureCustomCasterVertexProgram); if (retPass.HasVertexProgram) retPass.VertexProgramParameters = shadowTextureCustomCasterVPParams; } } else // Standard shadow caster pass, reset to no vp retPass.SetVertexProgram(""); } int keepTUCount = 0; // Material specifies a caster fragment program if (pass.ShadowCasterFragmentProgramName != "") { // If the material specifies a fragment program, then we need to copy the // TextureUnitStates from the original pass. int origPassTUCount = pass.NumTextureUnitStages; for (int t = 0; t < origPassTUCount; ++t) { TextureUnitState tex = (retPass.NumTextureUnitStages <= t ? retPass.CreateTextureUnitState() : retPass.GetTextureUnitState(t)); pass.GetTextureUnitState(t).CopyTo(tex); } keepTUCount = origPassTUCount; // Have to merge the shadow caster vertex program in retPass.SetFragmentProgram(pass.ShadowCasterFragmentProgramName); GpuProgram prg = retPass.FragmentProgram; // Load this program if not done already if (!prg.IsLoaded) prg.Load(); // Copy params retPass.FragmentProgramParameters = pass.ShadowCasterFragmentProgramParameters; // Did we bind a shadow vertex program? if (pass.HasVertexProgram && !retPass.HasVertexProgram) { // We didn't bind a caster-specific program, so bind the original retPass.SetVertexProgram(pass.VertexProgramName); prg = retPass.VertexProgram; // Load this program if required if (!prg.IsLoaded) prg.Load(); // Copy params retPass.VertexProgramParameters = pass.VertexProgramParameters; } } else { // Reset any merged fragment programs from last time if (retPass == shadowTextureCustomCasterPass) { // reset fp? if (retPass.FragmentProgramName != shadowTextureCustomCasterFragmentProgram) { retPass.SetFragmentProgram(shadowTextureCustomCasterFragmentProgram); if (retPass.HasFragmentProgram) retPass.FragmentProgramParameters = shadowTextureCustomCasterFPParams; } } else // Standard shadow caster pass, reset to no fp retPass.SetFragmentProgram(""); } // Remove any extra texture units while (retPass.NumTextureUnitStages > keepTUCount) { retPass.RemoveTextureUnitState(keepTUCount); } // make sure we turn off alpha rejection targetRenderSystem.SetAlphaRejectSettings(CompareFunction.AlwaysPass, 0); retPass.Load(); return retPass; } else { return pass; } }
/// <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; } } }