public MultiLights(SceneManager pSceneManager, SceneNode pCamNode, MovingObject pPlayerShip, Int32 pNumberOfLights) { oldCamLightColor = CamLightColor = new ColorEx(0.13f, 0.1f, 0.05f); PlayerLightColor = ColorEx.White; camLights = new List<Light>(pNumberOfLights); innerLights = (Int32)Math.Round(pNumberOfLights / 3.0f, MidpointRounding.AwayFromZero); outerLights = pNumberOfLights - innerLights; // create the playership's light. playerLight = pSceneManager.CreateLight("playerSpotLight"); playerLight.Type = LightType.Spotlight; playerLight.Diffuse = PlayerLightColor; playerLight.Specular = ColorEx.White; playerLight.SetSpotlightRange(0.0f, 120.0f); playerLight.Direction = Vector3.NegativeUnitZ; playerLightNode = pPlayerShip.Node.CreateChildSceneNode(); playerLightNode.AttachObject(playerLight); playerLightNode.Position = new Vector3(0, 0, 0); playerLightNode.SetDirection(new Vector3(1, 0, 0), TransformSpace.Local); // create the camera spotlights around the camera's direction. camInnerLightNode = pCamNode.CreateChildSceneNode(); camInnerLightNode.Position = new Vector3(0, 0, 0); camOuterLightNode = pCamNode.CreateChildSceneNode(); camOuterLightNode.Position = new Vector3(0, 0, 0); for (var i = 0; i < innerLights; i++) { var light = pSceneManager.CreateLight("camInnerLight " + (i + 1)); light.Type = LightType.Spotlight; light.Diffuse = CamLightColor; light.Specular = ColorEx.White; light.SetSpotlightRange(0.0f, 25.0f); light.Direction = Quaternion.FromAngleAxis(360.0 * i / innerLights * Constants.DegreesToRadians, Vector3.UnitZ) * Quaternion.FromAngleAxis(10.0 * Constants.DegreesToRadians, Vector3.UnitX) * Vector3.NegativeUnitZ; camLights.Add(light); camInnerLightNode.AttachObject(light); } for (var i = 0; i < outerLights; i++) { var light = pSceneManager.CreateLight("camOuterLight " + (i + 1)); light.Type = LightType.Spotlight; light.Diffuse = CamLightColor; light.Specular = ColorEx.White; light.SetSpotlightRange(0.0f, 25.0f); light.Direction = Quaternion.FromAngleAxis(360.0 * i / outerLights * Constants.DegreesToRadians, Vector3.UnitZ) * Quaternion.FromAngleAxis(20.0 * Constants.DegreesToRadians, Vector3.UnitX) * Vector3.NegativeUnitZ; camLights.Add(light); camOuterLightNode.AttachObject(light); } }
public PerPixelLighting() { this.trackVertexColorType = TrackVertexColor.None; this.specularEnable = false; this.blankLight = new Light(); this.blankLight.Diffuse = ColorEx.Black; this.blankLight.Specular = ColorEx.Black; this.blankLight.SetAttenuation( 0, 1, 0, 0 ); }
public void OnLoad() { //ResourceGroupManager.Instance.AddResourceLocation("media", "Folder", true); _root.SceneManager = _sceneManager = _root.CreateSceneManager(SceneType.ExteriorClose); _sceneManager.ClearScene(); _camera = _sceneManager.CreateCamera("MainCamera"); _camera.Position = new Vector3(0, 0, 500); _camera.LookAt(new Vector3(0, 0, -300)); _camera.Near = 5; _camera.AutoAspectRatio = true; _camera.FieldOfView = 0.70f; _viewport = _renderWindow.AddViewport(_camera, 0, 0, 1.0f, 1.0f, 100); _viewport.BackgroundColor = ColorEx.Black; ; _light = _sceneManager.CreateLight("light1"); _light.Type = LightType.Directional; _light.Position = new Vector3(0, 150, 300); _light.Diffuse = ColorEx.Blue; _light.Specular = ColorEx.Blue; //_light.Direction = new Vector3(0, 0, -300); _sceneManager.AmbientLight = ColorEx.White;// new ColorEx(0.2f, 0.2f, 0.2f); ResourceGroupManager.Instance.InitializeAllResourceGroups(); _inputReader = PlatformManager.Instance.CreateInputReader(); _inputReader.Initialize(_renderWindow, true, true, false, false); _inputReader.UseKeyboardEvents = true; _inputReader.UseMouseEvents = false; //_renderItems.Add(new BasicCube()); _renderItems.Add(new CubeBrowser()); foreach (var i in _renderItems) { i.Initialise(_root); } }
public LightSpotlightFalloffValue( Light light ) : base( AnimableType.Float ) { this.light = light; }
public LightSpotlightOuterValue( Light light ) : base( AnimableType.Float ) { this.light = light; }
/// <summary> /// Prepare the listener for use with a set of parameters. /// </summary> /// <param name="lightInFrustum"></param> /// <param name="lightClipVolumes"></param> /// <param name="light"></param> /// <param name="camera"></param> /// <param name="shadowCasterList"></param> /// <param name="farDistSquared"></param> public void Prepare( bool lightInFrustum, PlaneBoundedVolumeList lightClipVolumes, Light light, Camera camera, List<ShadowCaster> shadowCasterList, float farDistSquared ) { this.casterList = shadowCasterList; this.isLightInFrustum = lightInFrustum; this.lightClipVolumeList = lightClipVolumes; this.camera = camera; this.light = light; this.farDistSquared = farDistSquared; }
public override IEnumerator GetShadowVolumeRenderableEnumerator(ShadowTechnique technique, Light light, HardwareIndexBuffer indexBuffer, bool extrudeVertices, float extrusionDistance, int flags) { return dummyList.GetEnumerator(); }
protected override IList FindShadowCastersForLight( Light light, Camera camera ) { // objectsForRendering was filled at ProcessVisibleLeaf which is called // during FindVisibleObjects IList casters = base.FindShadowCastersForLight( light, camera ); for ( int i = 0; i < casters.Count; i++ ) { if ( !this.objectsForRendering.ContainsKey( ( (MovableObject)casters[ i ] ).Name ) ) { // this shadow caster is not visible, remove it casters.RemoveAt( i ); i--; } } return casters; }
public LightDiffuseColorValue(Light light) : base(AnimableType.ColorEx) { this.light = light; SetAsBaseValue(ColorEx.Black); }
/// <summary> /// Get the distance to extrude for a point/spot light. /// </summary> /// <param name="light"></param> /// <returns></returns> public abstract float GetPointExtrusionDistance( Light light );
protected void GenerateScene() { ((Axiom.SceneManagers.Multiverse.SceneManager)sceneManager).SetWorldParams(terrainGenerator, new LODSpec()); sceneManager.LoadWorldGeometry(""); AmbientLightColor = new ColorEx(0.5f, 0.5f, 0.5f); // set up directional light directionalLight = sceneManager.CreateLight("MainLight"); directionalLight.Type = LightType.Directional; directionalLight.SetAttenuation(1000 * OneMeter, 1, 0, 0); DirectionalDiffuseColor = ColorEx.White; DirectionalSpecularColor = ColorEx.White; PositionLight(); // create and position the scene node used to display the loaded model modelNode = sceneManager.RootSceneNode.CreateChildSceneNode(); modelNode.Position = modelBase; helperNode = sceneManager.RootSceneNode.CreateChildSceneNode(); helperNode.Position = modelBase; Axiom.SceneManagers.Multiverse.TerrainManager.Instance.ShowOcean = false; // Set our DisplayTerrain property to the current value. // This will set the desired SceneManager properties. this.DisplayTerrain = displayTerrain; //particleNode = scene.RootSceneNode.CreateChildSceneNode(); //particleNode.Position = new Vector3(0 * oneMeter, 50 * oneMeter, 0 * oneMeter); //ParticleSystem ps = ParticleSystemManager.Instance.CreateSystem("foo", "PEExamples/ringOfFire"); //particleNode.AttachObject(ps); //particleNode.ScaleFactor = new Vector3(1000f, 1000f, 1000f); //ps.ShowBoundingBox = true; return; }
/// <summary> /// Generates the indexes required to render a shadow volume into the /// index buffer which is passed in, and updates shadow renderables to use it. /// </summary> /// <param name="edgeData">The edge information to use.</param> /// <param name="indexBuffer">The buffer into which to write data into; current /// contents are assumed to be discardable.</param> /// <param name="light">The light, mainly for type info as silhouette calculations /// should already have been done in <see cref="UpdateEdgeListLightFacing"/></param> /// <param name="shadowRenderables">A list of shadow renderables which has /// already been constructed but will need populating with details of /// the index ranges to be used.</param> /// <param name="flags">Additional controller flags, see <see cref="ShadowRenderableFlags"/>.</param> protected virtual void GenerateShadowVolume( EdgeData edgeData, HardwareIndexBuffer indexBuffer, Light light, ShadowRenderableList shadowRenderables, int flags ) { // Edge groups should be 1:1 with shadow renderables Debug.Assert( edgeData.edgeGroups.Count == shadowRenderables.Count ); LightType lightType = light.Type; bool extrudeToInfinity = ( flags & (int)ShadowRenderableFlags.ExtrudeToInfinity ) > 0; // Lock index buffer for writing IntPtr idxPtr = indexBuffer.Lock( BufferLocking.Discard ); int indexStart = 0; unsafe { // TODO: Will currently cause an overflow for 32 bit indices, revisit short* pIdx = (short*)idxPtr.ToPointer(); int count = 0; // Iterate over the groups and form renderables for each based on their // lightFacing for ( int groupCount = 0; groupCount < edgeData.edgeGroups.Count; groupCount++ ) { EdgeData.EdgeGroup eg = (EdgeData.EdgeGroup)edgeData.edgeGroups[ groupCount ]; ShadowRenderable si = (ShadowRenderable)shadowRenderables[ groupCount ]; RenderOperation lightShadOp = null; // Initialize the index bounds for this shadow renderable RenderOperation shadOp = si.GetRenderOperationForUpdate(); shadOp.indexData.indexCount = 0; shadOp.indexData.indexStart = indexStart; // original number of verts (without extruded copy) int originalVertexCount = eg.vertexData.vertexCount; bool firstDarkCapTri = true; int darkCapStart = 0; for ( int edgeCount = 0; edgeCount < eg.edges.Count; edgeCount++ ) { EdgeData.Edge edge = (EdgeData.Edge)eg.edges[ edgeCount ]; EdgeData.Triangle t1 = (EdgeData.Triangle)edgeData.triangles[ edge.triIndex[ 0 ] ]; EdgeData.Triangle t2 = edge.isDegenerate ? (EdgeData.Triangle)edgeData.triangles[ edge.triIndex[ 0 ] ] : (EdgeData.Triangle)edgeData.triangles[ edge.triIndex[ 1 ] ]; if ( t1.lightFacing && ( edge.isDegenerate || !t2.lightFacing ) ) { /* Silhouette edge, first tri facing the light Also covers degenerate tris where only tri 1 is valid Remember verts run anticlockwise along the edge from tri 0 so to point shadow volume tris outward, light cap indexes have to be backwards We emit 2 tris if light is a point light, 1 if light is directional, because directional lights cause all points to converge to a single point at infinity. First side tri = near1, near0, far0 Second tri = far0, far1, near1 'far' indexes are 'near' index + originalVertexCount because 'far' verts are in the second half of the buffer */ pIdx[ count++ ] = (short)edge.vertIndex[ 1 ]; pIdx[ count++ ] = (short)edge.vertIndex[ 0 ]; pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; if ( !( lightType == LightType.Directional && extrudeToInfinity ) ) { // additional tri to make quad pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); pIdx[ count++ ] = (short)edge.vertIndex[ 1 ]; shadOp.indexData.indexCount += 3; } // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if ( ( flags & (int)ShadowRenderableFlags.IncludeDarkCap ) > 0 ) { if ( firstDarkCapTri ) { darkCapStart = edge.vertIndex[ 0 ] + originalVertexCount; firstDarkCapTri = false; } else { pIdx[ count++ ] = (short)darkCapStart; pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; } } } else if ( !t1.lightFacing && ( edge.isDegenerate || t2.lightFacing ) ) { // Silhouette edge, second tri facing the light // Note edge indexes inverse of when t1 is light facing pIdx[ count++ ] = (short)edge.vertIndex[ 0 ]; pIdx[ count++ ] = (short)edge.vertIndex[ 1 ]; pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; if ( !( lightType == LightType.Directional && extrudeToInfinity ) ) { // additional tri to make quad pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); pIdx[ count++ ] = (short)edge.vertIndex[ 0 ]; shadOp.indexData.indexCount += 3; } // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if ( ( flags & (int)ShadowRenderableFlags.IncludeDarkCap ) > 0 ) { if ( firstDarkCapTri ) { darkCapStart = edge.vertIndex[ 1 ] + originalVertexCount; firstDarkCapTri = false; } else { pIdx[ count++ ] = (short)darkCapStart; pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; } } } } // Do light cap if ( ( flags & (int)ShadowRenderableFlags.IncludeLightCap ) > 0 ) { ShadowRenderable lightCapRend = null; if ( si.IsLightCapSeperate ) { // separate light cap lightCapRend = si.LightCapRenderable; lightShadOp = lightCapRend.GetRenderOperationForUpdate(); lightShadOp.indexData.indexCount = 0; // start indexes after the current total // NB we don't update the total here since that's done below lightShadOp.indexData.indexStart = indexStart + shadOp.indexData.indexCount; } for ( int triCount = 0; triCount < edgeData.triangles.Count; triCount++ ) { EdgeData.Triangle t = (EdgeData.Triangle)edgeData.triangles[ triCount ]; // Light facing, and vertex set matches if ( t.lightFacing && t.vertexSet == eg.vertexSet ) { pIdx[ count++ ] = (short)t.vertIndex[ 0 ]; pIdx[ count++ ] = (short)t.vertIndex[ 1 ]; pIdx[ count++ ] = (short)t.vertIndex[ 2 ]; if ( lightShadOp != null ) { lightShadOp.indexData.indexCount += 3; } else { shadOp.indexData.indexCount += 3; } } } } // update next indexStart (all renderables sharing the buffer) indexStart += shadOp.indexData.indexCount; // add on the light cap too if ( lightShadOp != null ) { indexStart += lightShadOp.indexData.indexCount; } } } // Unlock index buffer indexBuffer.Unlock(); Debug.Assert( indexStart <= indexBuffer.IndexCount, "Index buffer overrun while generating shadow volume!" ); }
/// <summary> /// Helper method for calculating extrusion distance. /// </summary> /// <param name="objectPos"></param> /// <param name="light"></param> /// <returns></returns> protected float GetExtrusionDistance( Vector3 objectPos, Light light ) { Vector3 diff = objectPos - light.DerivedPosition; return light.AttenuationRange - diff.Length; }
public IEnumerator GetShadowVolumeRenderableEnumerator( ShadowTechnique technique, Light light, HardwareIndexBuffer indexBuffer, float extrusionDistance, bool extrudeVertices ) { return GetShadowVolumeRenderableEnumerator( technique, light, indexBuffer, extrudeVertices, extrusionDistance, 0 ); }
/// <summary> /// Gets an iterator over the renderables required to render the shadow volume. /// </summary> /// <remarks> /// Shadowable geometry should ideally be designed such that there is only one /// ShadowRenderable required to render the the shadow; however this is not a necessary /// limitation and it can be exceeded if required. /// </remarks> /// <param name="technique">The technique being used to generate the shadow.</param> /// <param name="light">The light to generate the shadow from.</param> /// <param name="indexBuffer">The index buffer to build the renderables into, /// the current contents are assumed to be disposable.</param> /// <param name="extrudeVertices">If true, this means this class should extrude /// the vertices of the back of the volume in software. If false, it /// will not be done (a vertex program is assumed).</param> /// <param name="extrusionDistance"></param> /// <param name="flags">Technique-specific flags, see <see cref="ShadowRenderableFlags"/></param> /// <returns>An iterator that will allow iteration over all renderables for the full shadow volume.</returns> public abstract IEnumerator GetShadowVolumeRenderableEnumerator( ShadowTechnique technique, Light light, HardwareIndexBuffer indexBuffer, bool extrudeVertices, float extrusionDistance, int flags );
public LightAttenuationConstantValue(Light light) : base(AnimableType.Float) { this.light = light; SetAsBaseValue(0.0f); }
protected override MovableObject _createInstance( string name, NamedParameterList param ) { Light light = new Light( name ); if ( param != null ) { // Setting the light type first before any property specific to a certain light type if ( param.ContainsKey( "type" ) ) { switch ( param[ "type" ].ToString() ) { case "point": light.Type = LightType.Point; break; case "directional": light.Type = LightType.Directional; break; case "spot": case "spotlight": light.Type = LightType.Spotlight; break; default: throw new AxiomException( "Invalid light type '" + param[ "type" ] + "'." ); } } // Common properties if ( param.ContainsKey( "position" ) ) { light.Position = Vector3.Parse( param[ "position" ].ToString() ); } if ( param.ContainsKey( "direction" ) ) { light.Direction = Vector3.Parse( param[ "direction" ].ToString() ); } if ( param.ContainsKey( "diffuseColour" ) ) { light.Diffuse = ColorEx.Parse_0_255_String( param[ "diffuseColour" ].ToString() ); } if ( param.ContainsKey( "specularColour" ) ) { light.Specular = ColorEx.Parse_0_255_String( param[ "specularColour" ].ToString() ); } if ( param.ContainsKey( "attenuation" ) ) { Vector4 attenuation = Vector4.Parse( param[ "attenuation" ].ToString() ); light.SetAttenuation( attenuation.x, attenuation.y, attenuation.z, attenuation.w ); } if ( param.ContainsKey( "castShadows" ) ) { light.CastShadows = Convert.ToBoolean( param[ "castShadows" ].ToString() ); } if ( param.ContainsKey( "visible" ) ) { light.CastShadows = Convert.ToBoolean( param[ "visible" ].ToString() ); } // TODO: Add PowerScale Property to Light if ( param.ContainsKey( "powerScale" ) ) { light.PowerScale = (float)Convert.ToDouble( param[ "powerScale" ].ToString() ); } // TODO: Add ShadowFarDistance to Light if ( param.ContainsKey( "shadowFarDistance" ) ) { light.ShadowFarDistance = (float)Convert.ToDouble( param[ "shadowFarDistance" ].ToString() ); } // Spotlight properties if ( param.ContainsKey( "spotlightInner" ) ) { light.SpotlightInnerAngle = (float)Convert.ToDouble( param[ "spotlightInner" ].ToString() ); } if ( param.ContainsKey( "spotlightOuter" ) ) { light.SpotlightOuterAngle = (float)Convert.ToDouble( param[ "spotlightOuter" ].ToString() ); } if ( param.ContainsKey( "spotlightFalloff" ) ) { light.SpotlightFalloff = (float)Convert.ToDouble( param[ "spotlightFalloff" ].ToString() ); } } return light; }
/// <summary> /// Gets the world space bounding box of the dark cap, as extruded using the light provided. /// </summary> /// <param name="light"></param> /// <param name="dirLightExtrusionDist"></param> /// <returns></returns> public abstract AxisAlignedBox GetDarkCapBounds( Light light, float dirLightExtrusionDist );
public LightAttenuationLinearValue( Light light ) : base( AnimableType.Float ) { this.light = light; this.SetAsBaseValue( 0.0f ); }
/// <summary> /// Internal method for rendering all the objects for a given light into the stencil buffer. /// </summary> /// <param name="light">The light source.</param> /// <param name="camera">The camera being viewed from.</param> protected virtual void RenderShadowVolumesToStencil( Light light, Camera camera ) { // get the shadow caster list IList casters = this.FindShadowCastersForLight( light, camera ); if ( casters.Count == 0 ) { // No casters, just do nothing return; } // Set up scissor test (point & spot lights only) bool scissored = false; if ( light.Type != LightType.Directional && this.targetRenderSystem.Capabilities.HasCapability( Capabilities.ScissorTest ) ) { // Project the sphere onto the camera float left, right, top, bottom; Sphere sphere = new Sphere( light.DerivedPosition, light.AttenuationRange ); if ( camera.ProjectSphere( sphere, out left, out top, out right, out bottom ) ) { scissored = true; // Turn normalised device coordinates into pixels int iLeft, iTop, iWidth, iHeight; this.currentViewport.GetActualDimensions( out iLeft, out iTop, out iWidth, out iHeight ); int szLeft, szRight, szTop, szBottom; szLeft = (int)( iLeft + ( ( left + 1 ) * 0.5f * iWidth ) ); szRight = (int)( iLeft + ( ( right + 1 ) * 0.5f * iWidth ) ); szTop = (int)( iTop + ( ( -top + 1 ) * 0.5f * iHeight ) ); szBottom = (int)( iTop + ( ( -bottom + 1 ) * 0.5f * iHeight ) ); this.targetRenderSystem.SetScissorTest( true, szLeft, szTop, szRight, szBottom ); } } this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment ); // Can we do a 2-sided stencil? bool stencil2sided = false; if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.TwoSidedStencil ) && this.targetRenderSystem.Capabilities.HasCapability( Capabilities.StencilWrap ) ) { // enable stencil2sided = true; } // Do we have access to vertex programs? bool extrudeInSoftware = true; bool finiteExtrude = !this.shadowUseInfiniteFarPlane || !this.targetRenderSystem.Capabilities.HasCapability( Capabilities.InfiniteFarPlane ); if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.VertexPrograms ) ) { extrudeInSoftware = false; this.EnableHardwareShadowExtrusion( light, finiteExtrude ); } else { this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex ); } // Add light to internal list for use in render call tmpLightList.Clear(); tmpLightList.Add( light ); // Turn off color writing and depth writing this.targetRenderSystem.SetColorBufferWriteEnabled( false, false, false, false ); this.targetRenderSystem.DepthBufferWriteEnabled = false; this.targetRenderSystem.StencilCheckEnabled = true; this.targetRenderSystem.DepthBufferFunction = CompareFunction.Less; // Calculate extrusion distance float extrudeDistance = 0; if ( light.Type == LightType.Directional ) { extrudeDistance = this.shadowDirLightExtrudeDist; } // get the near clip volume PlaneBoundedVolume nearClipVol = light.GetNearClipVolume( camera ); // Determine whether zfail is required // We need to use zfail for ALL objects if we find a single object which // requires it bool zfailAlgo = false; this.CheckShadowCasters( casters, nearClipVol, light, extrudeInSoftware, finiteExtrude, zfailAlgo, camera, extrudeDistance, stencil2sided, tmpLightList ); // revert colour write state this.targetRenderSystem.SetColorBufferWriteEnabled( true, true, true, true ); // revert depth state this.targetRenderSystem.SetDepthBufferParams(); this.targetRenderSystem.StencilCheckEnabled = false; this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex ); if ( scissored ) { // disable scissor test this.targetRenderSystem.SetScissorTest( false ); } }
/// <summary> /// Renders the texture lighting tagged in the specified light /// </summary> protected void RenderTextureLighting( Light light ) { if ( !( light is TextureLight ) ) { return; } var texLight = (TextureLight)light; if ( !texLight.IsTextureLight ) { return; } if ( texLight.Type == LightType.Spotlight ) { this.spotlightFrustum.Spotlight = texLight; } // no world transform required targetRenderSystem.WorldMatrix = Matrix4.Identity; // Set view / proj targetRenderSystem.ViewMatrix = cameraInProgress.ViewMatrix; targetRenderSystem.ProjectionMatrix = cameraInProgress.ProjectionMatrix; TextureUnitState lightTex = this.textureLightPass.GetTextureUnitState( 0 ); TextureUnitState normalTex = this.textureLightPass.GetTextureUnitState( 1 ); switch ( texLight.Intensity ) { case LightIntensity.Normal: normalTex.ColorBlendMode.operation = LayerBlendOperationEx.Modulate; break; case LightIntensity.ModulateX2: normalTex.ColorBlendMode.operation = LayerBlendOperationEx.ModulateX2; break; case LightIntensity.ModulateX4: normalTex.ColorBlendMode.operation = LayerBlendOperationEx.ModulateX4; break; } if ( texLight.Type == LightType.Spotlight ) { this.spotlightFrustum.Spotlight = texLight; lightTex.SetProjectiveTexturing( true, this.spotlightFrustum ); } else { lightTex.SetProjectiveTexturing( false, null ); } if ( texLight.Type == LightType.Directional ) { // light it using only diffuse color and alpha normalTex.ColorBlendMode.source2 = LayerBlendSource.Diffuse; normalTex.AlphaBlendMode.source2 = LayerBlendSource.Diffuse; } else { // light it using the texture light normalTex.ColorBlendMode.source2 = LayerBlendSource.Current; normalTex.AlphaBlendMode.source2 = LayerBlendSource.Current; } SetPass( this.textureLightPass ); if ( texLight.Type == LightType.Directional ) { // Disable the light texture targetRenderSystem.SetTexture( 0, true, lightTex.TextureName ); } // For each material in turn, cache rendering data & render IEnumerator mapEnu = this.matFaceGroupMap.Keys.GetEnumerator(); while ( mapEnu.MoveNext() ) { // Get Material var thisMaterial = (Material)mapEnu.Current; List<BspStaticFaceGroup> faceGrp = this.matFaceGroupMap[ thisMaterial ]; // if one face group is a quake shader then the material is a quake shader if ( faceGrp[ 0 ].isQuakeShader ) { continue; } ManualCullingMode cullMode = thisMaterial.GetTechnique( 0 ).GetPass( 0 ).ManualCullingMode; // Empty existing cache this.renderOp.indexData.indexCount = 0; HardwareVertexBuffer bspVertexBuffer = this.level.VertexData.vertexBufferBinding.GetBuffer( 0 ); HardwareVertexBuffer lightTexCoordBuffer = this.level.VertexData.vertexBufferBinding.GetBuffer( 1 ); // lock index buffer ready to receive data #if !AXIOM_SAFE_ONLY unsafe #endif { var pVertices = bspVertexBuffer.Lock( BufferLocking.ReadOnly ); var pTexLightMap = lightTexCoordBuffer.Lock( BufferLocking.Discard ); var pIdx = this.renderOp.indexData.indexBuffer.Lock( BufferLocking.Discard ); for ( int i = 0; i < faceGrp.Count; i++ ) { if ( faceGrp[ i ].type != FaceGroup.Patch && texLight.AffectsFaceGroup( faceGrp[ i ], cullMode ) ) { // Cache each int numElems = CacheLightGeometry( texLight, pIdx, pTexLightMap, pVertices, faceGrp[ i ] ); this.renderOp.indexData.indexCount += numElems; pIdx += numElems; } } // Unlock the buffers this.renderOp.indexData.indexBuffer.Unlock(); lightTexCoordBuffer.Unlock(); bspVertexBuffer.Unlock(); } // Skip if no faces to process if ( this.renderOp.indexData.indexCount == 0 ) { continue; } // Get the plain geometry texture TextureUnitState geometryTex = thisMaterial.GetTechnique( 0 ).GetPass( 0 ).GetTextureUnitState( 0 ); if ( geometryTex.IsBlank ) { continue; } targetRenderSystem.SetTexture( 1, true, geometryTex.TextureName ); // OpenGL requires the addressing mode to be set before every render operation targetRenderSystem.SetTextureAddressingMode( 0, new UVWAddressing( TextureAddressing.Clamp ) ); targetRenderSystem.Render( this.renderOp ); } }
private void CheckShadowCasters( IList casters, PlaneBoundedVolume nearClipVol, Light light, bool extrudeInSoftware, bool finiteExtrude, bool zfailAlgo, Camera camera, float extrudeDistance, bool stencil2sided, LightList tmpLightList ) { int flags; for ( int i = 0; i < casters.Count; i++ ) { ShadowCaster caster = (ShadowCaster)casters[ i ]; if ( nearClipVol.Intersects( caster.GetWorldBoundingBox() ) ) { // We have a zfail case, we must use zfail for all objects zfailAlgo = true; break; } } for ( int ci = 0; ci < casters.Count; ci++ ) { ShadowCaster caster = (ShadowCaster)casters[ ci ]; flags = 0; if ( light.Type != LightType.Directional ) { extrudeDistance = caster.GetPointExtrusionDistance( light ); } if ( !extrudeInSoftware && !finiteExtrude ) { // hardware extrusion, to infinity (and beyond!) flags |= (int)ShadowRenderableFlags.ExtrudeToInfinity; } if ( zfailAlgo ) { // We need to include the light and / or dark cap // But only if they will be visible if ( camera.IsObjectVisible( caster.GetLightCapBounds() ) ) { flags |= (int)ShadowRenderableFlags.IncludeLightCap; } } // Dark cap (no dark cap for directional lights using // hardware extrusion to infinity) if ( !( ( flags & (int)ShadowRenderableFlags.ExtrudeToInfinity ) != 0 && light.Type == LightType.Directional ) && camera.IsObjectVisible( caster.GetDarkCapBounds( light, extrudeDistance ) ) ) { flags |= (int)ShadowRenderableFlags.IncludeDarkCap; } // get shadow renderables IEnumerator renderables = caster.GetShadowVolumeRenderableEnumerator( this.shadowTechnique, light, this.shadowIndexBuffer, extrudeInSoftware, extrudeDistance, flags ); // If using one-sided stencil, render the first pass of all shadow // renderables before all the second passes for ( int i = 0; i < ( stencil2sided ? 1 : 2 ); i++ ) { if ( i == 1 ) { renderables = caster.GetLastShadowVolumeRenderableEnumerator(); } while ( renderables.MoveNext() ) { ShadowRenderable sr = (ShadowRenderable)renderables.Current; // omit hidden renderables if ( sr.IsVisible ) { // render volume, including dark and (maybe) light caps this.RenderSingleShadowVolumeToStencil( sr, zfailAlgo, stencil2sided, tmpLightList, ( i > 0 ) ); // optionally render separate light cap if ( sr.IsLightCapSeperate && ( ( flags & (int)ShadowRenderableFlags.IncludeLightCap ) ) > 0 ) { // must always fail depth check this.targetRenderSystem.DepthBufferFunction = CompareFunction.AlwaysFail; Debug.Assert( sr.LightCapRenderable != null, "Shadow renderable is missing a separate light cap renderable!" ); this.RenderSingleShadowVolumeToStencil( sr.LightCapRenderable, zfailAlgo, stencil2sided, tmpLightList, ( i > 0 ) ); // reset depth function this.targetRenderSystem.DepthBufferFunction = CompareFunction.Less; } } } } } }
/// <summary> /// Internal method for locating a list of shadow casters which /// could be affecting the frustum for a given light. /// </summary> /// <remarks> /// Custom scene managers are encouraged to override this method to add optimizations, /// and to add their own custom shadow casters (perhaps for world geometry) /// </remarks> /// <param name="light"></param> /// <param name="camera"></param> protected virtual IList FindShadowCastersForLight( Light light, Camera camera ) { this.shadowCasterList.Clear(); if ( light.Type == LightType.Directional ) { // Basic AABB query encompassing the frustum and the extrusion of it AxisAlignedBox aabb = new AxisAlignedBox(); Vector3[] corners = camera.WorldSpaceCorners; Vector3 min, max; Vector3 extrude = light.DerivedDirection * -this.shadowDirLightExtrudeDist; // do first corner min = max = corners[ 0 ]; min.Floor( corners[ 0 ] + extrude ); max.Ceil( corners[ 0 ] + extrude ); for ( int c = 1; c < 8; ++c ) { min.Floor( corners[ c ] ); max.Ceil( corners[ c ] ); min.Floor( corners[ c ] + extrude ); max.Ceil( corners[ c ] + extrude ); } aabb.SetExtents( min, max ); if ( this.shadowCasterAABBQuery == null ) { this.shadowCasterAABBQuery = this.CreateAABBRegionQuery( aabb ); } else { this.shadowCasterAABBQuery.Box = aabb; } // Execute, use callback this.shadowCasterQueryListener.Prepare( false, light.GetFrustumClipVolumes( camera ), light, camera, this.shadowCasterList, light.ShadowFarDistanceSquared ); this.shadowCasterAABBQuery.Execute( this.shadowCasterQueryListener ); } else { Sphere s = new Sphere( light.DerivedPosition, light.AttenuationRange ); // eliminate early if camera cannot see light sphere if ( camera.IsObjectVisible( s ) ) { // create or init a sphere region query if ( this.shadowCasterSphereQuery == null ) { this.shadowCasterSphereQuery = this.CreateSphereRegionQuery( s ); } else { this.shadowCasterSphereQuery.Sphere = s; } // check if the light is within view of the camera bool lightInFrustum = camera.IsObjectVisible( light.DerivedPosition ); PlaneBoundedVolumeList volumeList = null; // Only worth building an external volume list if // light is outside the frustum if ( !lightInFrustum ) { volumeList = light.GetFrustumClipVolumes( camera ); } // prepare the query and execute using the callback this.shadowCasterQueryListener.Prepare( lightInFrustum, volumeList, light, camera, this.shadowCasterList, light.ShadowFarDistanceSquared ); this.shadowCasterSphereQuery.Execute( this.shadowCasterQueryListener ); } } return this.shadowCasterList; }
private void SetD3D9Light( int index, Light light ) { if ( light == null ) { ActiveD3D9Device.EnableLight( index, false ); } else { var nlight = new D3D.Light(); switch ( light.Type ) { case LightType.Point: nlight.Type = D3D.LightType.Point; break; case LightType.Directional: nlight.Type = D3D.LightType.Directional; break; case LightType.Spotlight: nlight.Type = D3D.LightType.Spot; nlight.Falloff = light.SpotlightFalloff; nlight.Theta = Utility.DegreesToRadians( light.SpotlightInnerAngle ); nlight.Phi = Utility.DegreesToRadians( light.SpotlightOuterAngle ); break; } // switch // light colors nlight.Diffuse = D3DHelper.ToColor( light.Diffuse ); nlight.Specular = D3DHelper.ToColor( light.Specular ); Vector3 vec; if ( light.Type != LightType.Directional ) { vec = light.DerivedPosition; nlight.Position = new DX.Vector3( vec.x, vec.y, vec.z ); } if ( light.Type != LightType.Point ) { vec = light.DerivedDirection; nlight.Direction = new DX.Vector3( vec.x, vec.y, vec.z ); } // atenuation settings nlight.Range = light.AttenuationRange; nlight.Attenuation0 = light.AttenuationConstant; nlight.Attenuation1 = light.AttenuationLinear; nlight.Attenuation2 = light.AttenuationQuadratic; ActiveD3D9Device.SetLight( index, nlight ); ActiveD3D9Device.EnableLight( index, true ); } // if }
private void EnableHardwareShadowExtrusion( Light light, bool finiteExtrude ) { // attach the appropriate extrusion vertex program // Note we never unset it because support for vertex programs is constant this.shadowStencilPass.SetVertexProgram( ShadowVolumeExtrudeProgram.GetProgramName( light.Type, finiteExtrude, false ) ); // Set params if ( finiteExtrude ) { this.shadowStencilPass.VertexProgramParameters = this.finiteExtrusionParams; } else { this.shadowStencilPass.VertexProgramParameters = this.infiniteExtrusionParams; } if ( this.showDebugShadows ) { this.shadowDebugPass.SetVertexProgram( ShadowVolumeExtrudeProgram.GetProgramName( light.Type, finiteExtrude, true ) ); // Set params if ( finiteExtrude ) { this.shadowDebugPass.VertexProgramParameters = this.finiteExtrusionParams; } else { this.shadowDebugPass.VertexProgramParameters = this.infiniteExtrusionParams; } } this.targetRenderSystem.BindGpuProgram( this.shadowStencilPass.VertexProgram ); }
/// <summary> /// /// </summary> /// <param name="l"></param> private ImportData ConfigureTerrainDefaults( Light l ) { TerrainGlobalOptions.MaxPixelError = 8; TerrainGlobalOptions.CompositeMapDistance = 3000; TerrainGlobalOptions.LightMapDirection = l.DerivedDirection; TerrainGlobalOptions.CompositeMapAmbient = SceneManager.AmbientLight; TerrainGlobalOptions.CompositeMapDiffuse = l.Diffuse; ImportData defaultImp = terrainGroup.DefaultImportSettings; defaultImp.TerrainSize = TerrainSize; defaultImp.WorldSize = TerrainWorldSize; defaultImp.InputScale = 100; defaultImp.MinBatchSize = 33; defaultImp.MaxBatchSize = 65; defaultImp.LayerList = new List<LayerInstance>(); LayerInstance inst = new LayerInstance(); inst.WorldSize = 100; inst.TextureNames = new List<string>(); inst.TextureNames.Add( "dirt_grayrocky_diffusespecular.dds" ); inst.TextureNames.Add( "dirt_grayrocky_normalheight.dds" ); defaultImp.LayerList.Add( inst ); inst = new LayerInstance(); inst.WorldSize = 30; inst.TextureNames = new List<string>(); inst.TextureNames.Add( "grass_green-01_diffusespecular.dds" ); inst.TextureNames.Add( "grass_green-01_normalheight.dds" ); defaultImp.LayerList.Add( inst ); inst = new LayerInstance(); inst.WorldSize = 30; inst.TextureNames = new List<string>(); inst.TextureNames.Add( "growth_weirdfungus-03_diffusespecular.dds" ); inst.TextureNames.Add( "growth_weirdfungus-03_normalheight.dds" ); defaultImp.LayerList.Add( inst ); return defaultImp; }
/// <summary> /// Removes the specified light from the scene. /// </summary> /// <remarks> /// This method removes a previously added light from the scene. /// </remarks> /// <param name="light">Reference to the light to remove.</param> public virtual void RemoveLight( Light light ) { this.DestroyMovableObject( light ); }
public LightAttenuationValue( Light light ) : base( AnimableType.Vector4 ) { this.light = light; }
public override IEnumerator GetShadowVolumeRenderableEnumerator( ShadowTechnique technique, Light light, HardwareIndexBuffer indexBuffer, bool extrudeVertices, float extrusionDistance, int flags ) { Debug.Assert( indexBuffer != null, "Only external index buffers are supported right now" ); Debug.Assert( indexBuffer.Type == IndexType.Size16, "Only 16-bit indexes supported for now" ); // Potentially delegate to LOD entity if ( this.meshLodIndex > 0 && this.mesh.IsLodManual ) { Debug.Assert( this.meshLodIndex - 1 < this.lodEntityList.Count, "No LOD EntityList - did you build the manual LODs after creating the entity?" ); var lodEnt = this.lodEntityList[ this.meshLodIndex - 1 ]; // index - 1 as we skip index 0 (original LOD) if ( HasSkeleton && lodEnt.HasSkeleton ) { // Copy the animation state set to lod entity, we assume the lod // entity only has a subset animation states CopyAnimationStateSubset( lodEnt.animationState, this.animationState ); } return lodEnt.GetShadowVolumeRenderableEnumerator( technique, light, indexBuffer, extrudeVertices, extrusionDistance, flags ); } // Prep mesh if required // NB This seems to result in memory corruptions, having problems // tracking them down. For now, ensure that shadows are enabled // before any entities are created if ( !this.mesh.IsPreparedForShadowVolumes ) { this.mesh.PrepareForShadowVolume(); // reset frame last updated to force update of buffers this.frameAnimationLastUpdated = 0; // re-prepare buffers PrepareTempBlendedBuffers(); } // Update any animation UpdateAnimation(); // Calculate the object space light details var lightPos = light.GetAs4DVector(); // Only use object-space light if we're not doing transforms // Since when animating the positions are already transformed into // world space so we need world space light position var isAnimated = HasSkeleton || this.mesh.HasVertexAnimation; if ( !isAnimated ) { var world2Obj = parentNode.FullTransform.Inverse(); lightPos = world2Obj*lightPos; } // We need to search the edge list for silhouette edges var edgeList = GetEdgeList(); // Init shadow renderable list if required var init = ( this.shadowRenderables.Count == 0 ); if ( init ) { this.shadowRenderables.Capacity = edgeList.edgeGroups.Count; } var updatedSharedGeomNormals = false; EntityShadowRenderable esr = null; EdgeData.EdgeGroup egi; // note: using capacity for the loop since no items are in the list yet. // capacity is set to how large the collection will be in the end for ( var i = 0; i < this.shadowRenderables.Capacity; i++ ) { egi = (EdgeData.EdgeGroup)edgeList.edgeGroups[ i ]; var data = ( isAnimated ? FindBlendedVertexData( egi.vertexData ) : egi.vertexData ); if ( init ) { // Try to find corresponding SubEntity; this allows the // linkage of visibility between ShadowRenderable and SubEntity var subEntity = FindSubEntityForVertexData( egi.vertexData ); // Create a new renderable, create a separate light cap if // we're using hardware skinning since otherwise we get // depth-fighting on the light cap esr = new EntityShadowRenderable( this, indexBuffer, data, subEntity.VertexProgramInUse || !extrudeVertices, subEntity ); this.shadowRenderables.Add( esr ); } else { esr = (EntityShadowRenderable)this.shadowRenderables[ i ]; if ( HasSkeleton ) { // If we have a skeleton, we have no guarantee that the position // buffer we used last frame is the same one we used last frame // since a temporary buffer is requested each frame // therefore, we need to update the EntityShadowRenderable // with the current position buffer esr.RebindPositionBuffer( data, isAnimated ); } } // For animated entities we need to recalculate the face normals if ( isAnimated ) { if ( egi.vertexData != this.mesh.SharedVertexData || !updatedSharedGeomNormals ) { // recalculate face normals edgeList.UpdateFaceNormals( egi.vertexSet, esr.PositionBuffer ); // If we're not extruding in software we still need to update // the latter part of the buffer (the hardware extruded part) // with the latest animated positions if ( !extrudeVertices ) { var srcPtr = esr.PositionBuffer.Lock( BufferLocking.Normal ); var destPtr = srcPtr + ( egi.vertexData.vertexCount*12 ); // 12 = sizeof(float) * 3 Memory.Copy( srcPtr, destPtr, 12*egi.vertexData.vertexCount ); esr.PositionBuffer.Unlock(); } if ( egi.vertexData == this.mesh.SharedVertexData ) { updatedSharedGeomNormals = true; } } } // Extrude vertices in software if required if ( extrudeVertices ) { ExtrudeVertices( esr.PositionBuffer, egi.vertexData.vertexCount, lightPos, extrusionDistance ); } // Stop suppressing hardware update now, if we were esr.PositionBuffer.SuppressHardwareUpdate( false ); } // Calc triangle light facing UpdateEdgeListLightFacing( edgeList, lightPos ); // Generate indexes and update renderables GenerateShadowVolume( edgeList, indexBuffer, light, this.shadowRenderables, flags ); return this.shadowRenderables.GetEnumerator(); }
public LightSpecularColorValue( Light light ) : base( AnimableType.ColorEx ) { this.light = light; this.SetAsBaseValue( ColorEx.Black ); }