/// <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 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(); }