protected override void CreateShadowMap(EntityLightShadow light) { // create the shadow map var shadowMap = new ShadowMap { LightDirection = light.Light.LightDirection, LightPosition = light.Entity.Transformation.Translation, ShadowMapSize = light.Light.ShadowMapMaxSize, ShadowNearDistance = light.Light.ShadowNearDistance, ShadowFarDistance = light.Light.ShadowFarDistance, CascadeCount = light.Light.Type == LightType.Directional ? light.Light.ShadowMapCascadeCount : 1, // cascades are only supported for directional shadow maps LightType = light.Light.Type, Fov = light.Light.SpotFieldAngle, Filter = light.Light.ShadowMapFilterType, Layers = light.Light.Layers }; // find or create the shadow map texture ShadowMapTexture chosenTexture = null; chosenTexture = AllocateOrChooseTexture(shadowMap, light.Light.ShadowMapFilterType == ShadowMapFilterType.Variance ? texturesVsm : texturesDefault); shadowMap.Texture = chosenTexture; InternalShadowMaps.Add(shadowMap); light.ShadowMap = shadowMap; }
private ShadowMapTexture AllocateOrChooseTexture(ShadowMap newShadowMap, Dictionary <ShadowMapTexture, List <ShadowMap> > shadowMapTextures) { ShadowMapTexture chosenTexture = null; // find best texture foreach (var shadowMapTexture in shadowMapTextures) { var shadowTexture = shadowMapTexture.Key; var shadowMaps = shadowMapTexture.Value; shadowTexture.GuillotinePacker.Clear(shadowTexture.ShadowMapDepthTexture.Width, shadowTexture.ShadowMapDepthTexture.Height); var useShadowTexture = true; for (var i = 0; i < shadowMaps.Count && useShadowTexture; ++i) { useShadowTexture = shadowTexture.GuillotinePacker.TryInsert(shadowMaps[i].ShadowMapSize, shadowMaps[i].ShadowMapSize, shadowMaps[i].CascadeCount); } useShadowTexture = useShadowTexture && shadowTexture.GuillotinePacker.TryInsert(newShadowMap.ShadowMapSize, newShadowMap.ShadowMapSize, newShadowMap.CascadeCount); shadowTexture.GuillotinePacker.Clear(); if (useShadowTexture) { chosenTexture = shadowMapTexture.Key; break; } } if (chosenTexture == null) { // allocate a new texture chosenTexture = new ShadowMapTexture(GraphicsDevice, newShadowMap.Filter, 2048); chosenTexture.GuillotinePacker.Clear(chosenTexture.ShadowMapDepthTexture.Width, chosenTexture.ShadowMapDepthTexture.Height); // TODO: choose texture size based on the shadow map. For now throw exception if (!chosenTexture.GuillotinePacker.TryInsert(newShadowMap.ShadowMapSize, newShadowMap.ShadowMapSize, newShadowMap.CascadeCount)) { var message = new StringBuilder(); message.AppendFormat("Unable to allocate shadow map texture. The default size (2048 x 2048) is too small for the shadow map ({0} cascade(s) with size {1}).", newShadowMap.CascadeCount, newShadowMap.ShadowMapSize); throw new Exception(message.ToString()); } chosenTexture.GuillotinePacker.Clear(); InternalShadowMapTextures.Add(chosenTexture); var shadowMaps = new List <ShadowMap> { newShadowMap }; shadowMapTextures.Add(chosenTexture, shadowMaps); } else { shadowMapTextures[chosenTexture].Add(newShadowMap); } return(chosenTexture); }
protected override void CreateShadowMap(EntityLightShadow light) { // create the shadow map var shadowMap = new ShadowMap { LightDirection = light.Light.LightDirection, ShadowMapSize = light.Light.ShadowMapMinSize, ShadowNearDistance = light.Light.ShadowNearDistance, ShadowFarDistance = light.Light.ShadowFarDistance, CascadeCount = light.Light.ShadowMapCascadeCount, Filter = light.Light.ShadowMapFilterType, Layers = light.Light.Layers }; InternalShadowMaps.Add(shadowMap); light.ShadowMap = shadowMap; }