예제 #1
0
        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);
        }
예제 #2
0
        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)
                       ));
        }
예제 #3
0
        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
                        );
                }
            }
        }