DirectX (SharpDX) 线框错误

DirectX (SharpDX) Wireframe Bug

我的 3D 场景中的线框出现问题。由于某些奇怪的原因,线框在某些地方显示为不完整。四处移动相机会使一些线条出现,而另一些则消失,而不仅仅是一个完整的线框。这里有一些图片和一些代码。我正在使用 SharpDX。有谁知道是怎么回事吗?

(以下代码已被大幅缩减,仅显示我认为与此问题相关的部分)

using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DirectInput;
using SharpDX.DXGI;
using SharpDX.Windows;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Windows.Forms;
using VoidwalkerEngine.Framework.DirectX;
using VoidwalkerEngine.Framework.DirectX.Rendering;
using VoidwalkerEngine.Framework.DirectX.Shaders;
using VoidwalkerEngine.Framework.Logic;
using VoidwalkerEngine.Framework.Maths;

namespace GrimoireTacticsGame.Client
{
    public class GameWindow : RenderForm
    {

        /**
         * Client Variables
         */
        public Camera Camera { get; set; }
        public Keyboard Keyboard { get; set; }
        public Mouse Mouse { get; set; }
        public bool IsMouseLookEnabled { get; private set; }
        public Point CurrentMouseLocation { get; set; }
        public Stopwatch ClientTimer { get; set; }
        public int RenderFrequency { get; private set; }
        public VsyncLevel Vsync { get; set; }
        private bool _isResizeNeeded { get; set; } = true;
        private Point _mouseLockLocation { get; set; }
        private float _previousFrameDeltaTime { get; set; }
        private int _frameCounter;
        private System.DateTime _previousDateTime;
        /**
         * DirectX Variables
         */
        private Texture2D _depthBuffer;
        private SwapChain _swapChain;
        private SwapChainDescription _swapChainDescription;
        private Texture2D _backBuffer = null;
        private RenderTargetView _renderView = null;
        private DepthStencilView _depthView = null;
        private SharpDX.Direct3D11.Device _device;
        private DeviceContext _graphicsCardContext;
        private Factory _factory;
        public PointLightShaderArgs _pointLightArgs;
        private BlendState BlendState { get; set; }
        private RasterizerStateDescription RasterizerState { get; set; }
        public List<StaticGeometry> StaticGeometry { get; set; }
        /**
         * Shaders
         */
        public WorldShader WorldShader;


        public GameWindow()
            : base("Grimoire Tactics")
        {
            Initialize();

        }

        public void InitializeDirectX()
        {
            // SwapChain description
            _swapChainDescription = new SwapChainDescription()
            {
                BufferCount = 1,
                ModeDescription = new ModeDescription(
                    this.ClientSize.Width,
                    this.ClientSize.Height,
                    new Rational(60, 1),
                    Format.R8G8B8A8_UNorm),
                IsWindowed = true,
                OutputHandle = this.Handle,
                SampleDescription = new SampleDescription(1, 0),
                SwapEffect = SwapEffect.Discard,
                Usage = Usage.RenderTargetOutput
            };

            SharpDX.Direct3D11.Device.CreateWithSwapChain(
                DriverType.Hardware,
                DeviceCreationFlags.None,
                _swapChainDescription,
                out _device,
                out _swapChain);
            _graphicsCardContext = _device.ImmediateContext;
            _factory = _swapChain.GetParent<Factory>();
            _factory.MakeWindowAssociation(this.Handle, WindowAssociationFlags.IgnoreAll);
            /**
             * Create RasterizerState
             */ 
            RasterizerState = new RasterizerStateDescription
            {
                CullMode = CullMode.None,
                DepthBias = 0,
                DepthBiasClamp = 0,
                FillMode = FillMode.Solid,
                IsAntialiasedLineEnabled = false,
                IsDepthClipEnabled = false,
                IsFrontCounterClockwise = false,
                IsMultisampleEnabled = false,
                IsScissorEnabled = false,
                SlopeScaledDepthBias = 0
            };
            _graphicsCardContext.Rasterizer.State = new RasterizerState(_device, RasterizerState);

            /**
             * Create BlendState
             */
            BlendStateDescription blendStateDescription = new BlendStateDescription
            {
                AlphaToCoverageEnable = false,
            };

            blendStateDescription.RenderTarget[0].IsBlendEnabled = true;
            blendStateDescription.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha;
            blendStateDescription.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha;
            blendStateDescription.RenderTarget[0].BlendOperation = BlendOperation.Add;
            blendStateDescription.RenderTarget[0].SourceAlphaBlend = BlendOption.Zero;
            blendStateDescription.RenderTarget[0].DestinationAlphaBlend = BlendOption.Zero;
            blendStateDescription.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add;
            blendStateDescription.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;
            this.BlendState = new BlendState(_device, blendStateDescription);
            this._graphicsCardContext.OutputMerger.BlendState = this.BlendState;
        }

        private void InitializeShaders()
        {
            WorldShader = new WorldShader(_device);
        }

        private void Initialize()
        {
            this.StaticGeometry = new List<StaticGeometry>();
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Camera = new Camera
            {
                MoveSpeed = 128f,
                LookSpeed = 0.50f, // 0 ~ 1 (0.50 = 50%)
                Location = new Vector3(0, 0, 0),
                FieldOfView = 1.0f, // 0.7 ~ 1.20
                NearZ = 1f,
                FarZ = 8000f,
                AccelerationMultiplier = 2.5f
            };

            InitializeDirectX();
            InitializeShaders();
            InitializeGeometry();

            /**
             * Initialize Clock
             * Probably use a DateTime instead.
             */
            ClientTimer = new Stopwatch();


            /**
             * Setup Handlers
             */
            this.KeyDown += OnKeyDown;
            this.KeyUp += OnKeyUp;
            this.UserResized += OnResize;
            this.MouseUp += OnMouseUp;
            this.MouseMove += OnMouseMove;
            this.MouseDown += OnMouseDown;
            this.FormClosing += OnFormClosing;
            /**
             * Setup User Input
             */
            DirectInput input = new DirectInput();
            this.Keyboard = new Keyboard(input);
            this.Keyboard.Properties.BufferSize = 128;
            this.Keyboard.Acquire();
            this.Mouse = new Mouse(input);
            this.Mouse.Properties.BufferSize = 8;
            this.Mouse.Acquire();
        }

        private void DrawScene(float deltaTime)
        {
            this.Text = this.Camera.Location.ToString();
            float elapsedClientTime = ClientTimer.ElapsedMilliseconds / 1000.0f;
            Matrix modelViewMatrix = Camera.ModelViewMatrix;
            Matrix projectionMatrix = Camera.ProjectionMatrix;
            Matrix modelViewProjectionMatrix = Camera.ModelViewProjectionMatrix;

            if (!WorldShader.IsBound)
            {
                WorldShader.Bind(_graphicsCardContext);
            }
            this._pointLightArgs = new PointLightShaderArgs(
                        new Vector3(16, 32, 16),
                        1024,
                        new Vector3(0, 0.06f, 0),
                        new Vector4(0.5f, 0.5f, 0.5f, 1.0f),
                        new Vector4(1, 1, 1, 1));


            _graphicsCardContext.UpdateSubresource(ref _pointLightArgs, WorldShader.PointLightShaderArgsBuffer);

            foreach (StaticGeometry geometry in this.StaticGeometry)
            {
                if (geometry.IsVisible)
                {
                    Matrix worldPositionMatrix = VoidwalkerMath.CreateRotationMatrix(geometry.Rotation) * Matrix.Translation(geometry.Location);
                    Matrix localMatrix = worldPositionMatrix * modelViewProjectionMatrix;

                    worldPositionMatrix.Transpose();
                    localMatrix.Transpose();
                    _graphicsCardContext.UpdateSubresource(ref localMatrix, WorldShader.LocalMatrixBuffer);
                    _graphicsCardContext.UpdateSubresource(ref worldPositionMatrix, WorldShader.WorldPositionBuffer);

                    Vector2 textureResolution = geometry.Mesh.DiffuseMaterial.Resolution;
                    _graphicsCardContext.UpdateSubresource(ref textureResolution, WorldShader.TextureResolutionBuffer);

                    geometry.Draw(_graphicsCardContext);
                }
            }
        }

        private void OnRenderFrame()
        {
            if (_isResizeNeeded)
            {
                ResizeFrameBuffers();
            }
            float elapsedClientTime = ClientTimer.ElapsedMilliseconds / 1000.0f;
            float currentFrameDeltaTime = elapsedClientTime - _previousFrameDeltaTime;
            _previousFrameDeltaTime = elapsedClientTime;
            System.DateTime dateTimeNow = System.DateTime.Now;
            System.TimeSpan subtractedTime = dateTimeNow.Subtract(_previousDateTime);
            if (subtractedTime.TotalSeconds >= 1)
            {
                this.RenderFrequency = _frameCounter;
                _frameCounter = 0;
                this._previousDateTime = dateTimeNow;
            }
            _graphicsCardContext.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
            _graphicsCardContext.ClearRenderTargetView(_renderView, Color.CornflowerBlue);
            CheckKeyboardInput(currentFrameDeltaTime);
            DrawScene(elapsedClientTime);

            _swapChain.Present((int)this.Vsync, PresentFlags.None);

            _frameCounter++;
        }

        private void OnKeyUp(object sender, KeyEventArgs args)
        {
            switch (args.KeyCode)
            {
                case Keys.F2:
                    RasterizerStateDescription previousDescription = _graphicsCardContext.Rasterizer.State.Description;
                    FillMode mode;
                    mode = previousDescription.FillMode == FillMode.Solid
                        ? FillMode.Wireframe
                        : FillMode.Solid;
                    _graphicsCardContext.Rasterizer.State = new RasterizerState(_device, new RasterizerStateDescription
                    {
                        CullMode = previousDescription.CullMode,
                        DepthBias = previousDescription.DepthBias,
                        DepthBiasClamp = previousDescription.DepthBiasClamp,
                        FillMode = mode,
                        IsAntialiasedLineEnabled = previousDescription.IsAntialiasedLineEnabled,
                        IsDepthClipEnabled = previousDescription.IsDepthClipEnabled,
                        IsFrontCounterClockwise = previousDescription.IsFrontCounterClockwise,
                        IsMultisampleEnabled = previousDescription.IsMultisampleEnabled,
                        IsScissorEnabled = previousDescription.IsScissorEnabled,
                        SlopeScaledDepthBias = previousDescription.SlopeScaledDepthBias
                    });
                    break;
            }
        }

        private void ResizeFrameBuffers()
        {
            Utilities.Dispose(ref _backBuffer);
            Utilities.Dispose(ref _renderView);
            Utilities.Dispose(ref _depthBuffer);
            Utilities.Dispose(ref _depthView);
            _swapChain.ResizeBuffers(_swapChainDescription.BufferCount, this.ClientSize.Width, this.ClientSize.Height, Format.Unknown, SwapChainFlags.None);
            _backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
            _renderView = new RenderTargetView(_device, _backBuffer);
            _depthBuffer = new Texture2D(_device, new Texture2DDescription()
            {
                Format = Format.D32_Float_S8X24_UInt,
                ArraySize = 1,
                MipLevels = 1,
                Width = this.ClientSize.Width,
                Height = this.ClientSize.Height,
                SampleDescription = new SampleDescription(1, 0),
                Usage = ResourceUsage.Default,
                BindFlags = BindFlags.DepthStencil,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None
            });

            _depthView = new DepthStencilView(_device, _depthBuffer);
            _graphicsCardContext.Rasterizer.SetViewport(new Viewport(0, 0, this.ClientSize.Width, this.ClientSize.Height, 0.0f, 1.0f));
            _graphicsCardContext.OutputMerger.SetTargets(_depthView, _renderView);
            Camera.AspectRatio = this.ClientSize.Width / (float)this.ClientSize.Height;
            _isResizeNeeded = false;
        }
    }
}

没关系,我想通了。我必须禁用 alpha 混合。应该猜到了。

blendStateDescription.RenderTarget[0].IsBlendEnabled = false;