private static float GetShadowFactorForPoint(Vector3 P, IShadowCaster CallingShadowCaster, Enums.ShadowCasterClass ExcludedClasses = Enums.ShadowCasterClass.None) { float?cachedValue = SpatialShadowMap.Get(P); if (cachedValue.HasValue) { return(cachedValue.Value); } byte darkestTint = 0; for (int i = 0; i < VisibleShadowCasters.Count; i++) { IShadowCaster shadowCaster = VisibleShadowCasters[i]; if ( shadowCaster == CallingShadowCaster || ( ExcludedClasses != Enums.ShadowCasterClass.None && (shadowCaster.ShadowCasterClass() & ExcludedClasses) != Enums.ShadowCasterClass.None ) ) { continue; } Box shadowVolume = shadowCaster.GetShadowVolume(); if (shadowVolume.Top < P.Y || !shadowVolume.DoesContainPoint(P)) { continue; } Texture2D shadowTexture = shadowCaster.GetShadowTexture(); byte[] colorData = GetTextureData(shadowTexture); int ix; int iy; if (shadowCaster.ShouldTile()) { ix = (int)(P.X - shadowVolume.Left) % shadowTexture.Width; iy = (int)(P.Z - shadowVolume.Back) % shadowTexture.Height; } else { ix = (int)Math.Floor((P.X - shadowVolume.Left) / shadowVolume.Width * shadowTexture.Width); iy = (int)Math.Floor((P.Z - shadowVolume.Back) / shadowVolume.Depth * shadowTexture.Height); } byte pointColorA = colorData[ix + iy * shadowTexture.Width]; if (pointColorA > darkestTint) { darkestTint = pointColorA; if (darkestTint == byte.MaxValue) { break; } } } SpatialShadowMap.AttemptInsert(darkestTint / 255f, P); return(darkestTint / 255f); }
public static Color GetShadowTintForBox(Box B, IShadowCaster CallingShadowCaster = null, Enums.ShadowCasterClass ExcludedClasses = Enums.ShadowCasterClass.None) { float darkestTint = 1f; for (int i = 0; i < VisibleShadowCasters.Count; i++) { IShadowCaster shadowCaster = VisibleShadowCasters[i]; if ( shadowCaster == CallingShadowCaster || ( ExcludedClasses != Enums.ShadowCasterClass.None && (shadowCaster.ShadowCasterClass() & ExcludedClasses) != Enums.ShadowCasterClass.None ) ) { continue; } Box shadowVolume = shadowCaster.GetShadowVolume(); Box?shadowBox = shadowVolume.GetIntersectionVolume(B); if (shadowBox == null) { continue; } Texture2D shadowTexture = shadowCaster.GetShadowTexture(); int x1; int y1; int x2; int y2; if (shadowCaster.ShouldTile()) { x1 = (int)(shadowBox.Value.Left - shadowVolume.Left); y1 = (int)(shadowBox.Value.Back - shadowVolume.Back); x2 = x1 + (int)shadowBox.Value.Width; y2 = y1 + (int)shadowBox.Value.Depth; } else { x1 = (int)Math.Floor((shadowBox.Value.Left - shadowVolume.Left) / shadowVolume.Width * shadowTexture.Width); y1 = (int)Math.Floor((shadowBox.Value.Back - shadowVolume.Back) / shadowVolume.Depth * shadowTexture.Height); x2 = x1 + (int)Math.Floor((shadowBox.Value.Width / shadowVolume.Width) * (shadowTexture.Width - 1)); y2 = y1 + (int)Math.Floor((shadowBox.Value.Depth / shadowVolume.Depth) * (shadowTexture.Height - 1)); } float a = GetShadowStrengthOverArea(shadowTexture, x1, y1, x2, y2) * (shadowBox.Value.TopDownSurfaceArea / B.TopDownSurfaceArea) * shadowCaster.GetShadowOpacity(); if (a > 0) { a = 1 - a; if (a < darkestTint) { darkestTint = a; } } } if (darkestTint == 1f) { return(Color.White); } float invertDarkest = 1 - darkestTint; return(new Color( 1 - (invertDarkest - GLOBAL_SHADOW_COLOR.R / 255f * invertDarkest), 1 - (invertDarkest - GLOBAL_SHADOW_COLOR.G / 255f * invertDarkest), 1 - (invertDarkest - GLOBAL_SHADOW_COLOR.B / 255f * invertDarkest) )); }
private void DrawShadows() { if (shadowReceiverMode != ShadowReceiverMode.Exact) { return; } DisposableList <IShadowCaster> shadowCasters = ShadowCasterHelper.VisibleShadowCasters; for (int i = 0; i < shadowCasters.Count; i++) { IShadowCaster shadowCaster = shadowCasters[i]; Box shadowVolume = shadowCaster.GetShadowVolume(); Box? shadowBox = shadowVolume.GetIntersectionVolume(BackingBox.B); if (shadowBox == null || (!BackingBox.B.isRamp && shadowBox.Value.Top < BackingBox.Top)) { continue; } Texture2D shadowTexture = shadowCaster.GetShadowTexture(); int xIndex; int yIndex; int sourceWidth; int sourceHeight; if (shadowCaster.ShouldTile()) { xIndex = (int)(shadowBox.Value.Left - shadowVolume.Left); yIndex = (int)(shadowBox.Value.Back - shadowVolume.Back); sourceWidth = (int)shadowBox?.Width; sourceHeight = (int)shadowBox?.Depth; } else { xIndex = (int)Math.Round((shadowBox.Value.Left - shadowVolume.Left) / shadowVolume.Width * shadowTexture.Width); yIndex = (int)Math.Round((shadowBox.Value.Back - shadowVolume.Back) / shadowVolume.Depth * shadowTexture.Height); sourceWidth = (int)Math.Round(shadowBox.Value.Width / shadowVolume.Width * shadowTexture.Width); sourceHeight = (int)Math.Round(shadowBox.Value.Depth / shadowVolume.Depth * shadowTexture.Height); } float opacity = (1f - (shadowVolume.Top - BackingBox.B.Top) / shadowVolume.Height) * shadowCaster.GetShadowOpacity(); if (!BackingBox.B.isRamp) { GameService.GetService <IRenderService>().PushAlphaFragment( RenderService.AlphaStacks.Shadows, shadowTexture, new Rectangle((int)Math.Round(shadowBox.Value.Left), (int)Math.Round(shadowBox.Value.Back - shadowBox.Value.Top), (int)Math.Round(shadowBox.Value.Width), (int)Math.Round(shadowBox.Value.Depth)), new Rectangle(xIndex, yIndex, sourceWidth, sourceHeight), IsTiling: shadowCaster.ShouldTile(), Tint: Color.White * opacity ); if (shadowBox.Value.Front == BackingBox.B.Front) { GameService.GetService <IRenderService>().PushAlphaFragment( RenderService.AlphaStacks.Shadows, shadowTexture, new Rectangle((int)Math.Round(shadowBox.Value.Left), (int)Math.Round(shadowBox.Value.Front - shadowBox.Value.Top), (int)Math.Round(shadowBox.Value.Width), (int)Math.Round(shadowBox.Value.Height)), new Rectangle(xIndex, yIndex + sourceHeight - 1, sourceWidth, 1), IsTiling: shadowCaster.ShouldTile(), Tint: Color.White * opacity ); } } else { GameService.GetService <IRenderService>().PushAlphaFragment( RenderService.AlphaStacks.Shadows, shadowTexture, new Rectangle((int)Math.Round(shadowBox.Value.Left), ((int)shadowBox.Value.Back - (int)BackingBox.Back) / 2 + (int)Math.Round(shadowBox.Value.Back - BackingBox.B.Top), (int)Math.Round(shadowBox.Value.Width), (int)Math.Round(shadowBox.Value.Depth * 1.5f)), new Rectangle(xIndex, yIndex, sourceWidth, sourceHeight), IsTiling: shadowCaster.ShouldTile(), Tint: Color.White * opacity ); } } }