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;
我的 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;