使用 SlimDX 时剪辑和 3D 投影不正确
我正在开发一个简单的项目,希望使用 SlimDX 在 WinForms 应用程序中显示 3D 对象。我创建了一个小项目来执行此操作,但遇到一个问题,即我渲染的对象被裁剪在 0.0f 和 -1.0f 之间。
我查看了朋友类似项目的代码(他们没有这个问题),但无法弄清楚为什么会发生这种情况。我必须将对象的大小限制在 -0.1f -> 的范围内0.1f以便我能够看到它。扩展我的远平面没有任何作用。我朋友正在使用的项目可以加载超过我的大小 500 倍的对象,并且没有剪切问题。
有人有什么建议吗? (请参阅下面的屏幕截图和代码)
表单代码
namespace TestOfTheTest
{
using System.Drawing;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using MathHelper = Microsoft.Xna.Framework.MathHelper;
public struct VertexPositionColor
{
private static VertexDeclaration sDeclaration;
public static VertexElement[] Elements =
{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, sizeof(float) * 3, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.Color, 0),
VertexElement.VertexDeclarationEnd
};
public Vector3 Position;
public Color4 Color;
public VertexPositionColor(Vector3 position, Color4 color)
{
this.Position = position;
this.Color = color;
}
public static int DeclarationSize
{
get { return (sizeof(float) * 3) + (sizeof(float) * 4); }
}
public static VertexDeclaration GetDeclaration(Device device)
{
if (sDeclaration == null)
{
sDeclaration = new VertexDeclaration(device, Elements);
}
return sDeclaration;
}
}
public partial class Form1 : Form
{
private Device mDevice;
private VertexPositionColor[] mVertices;
private VertexBuffer mVertexBuffer;
private VertexShader mVertexShader;
private PixelShader mPixelShader;
private Point? mLastPosition = null;
private float mAngle = 0.0f;
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
this.RenderSurface.MouseDown += RenderSurface_MouseDown;
this.RenderSurface.MouseMove += RenderSurface_MouseMove;
this.RenderSurface.MouseUp += RenderSurface_MouseUp;
}
#region UI Event Handlers
private void Form1_Load(object sender, System.EventArgs e)
{
var parameters = new PresentParameters()
{
BackBufferWidth = this.RenderSurface.Width,
BackBufferHeight = this.RenderSurface.Height,
Windowed = true,
DeviceWindowHandle = this.RenderSurface.Handle
};
mDevice = new Device(new Direct3D(), 0, DeviceType.Hardware, this.RenderSurface.Handle, CreateFlags.HardwareVertexProcessing, parameters);
// Create the vertices
mVertices = new VertexPositionColor[3];
mVertices[0].Position = new Vector3(-0.1f, -0.1f, -1.0f);
mVertices[0].Color = new Color4(1.0f, 1.0f, 0.0f, 0.0f);
mVertices[1].Position = new Vector3(0.0f, 0.1f, -1.0f);
mVertices[1].Color = new Color4(1.0f, 0.0f, 1.0f, 0.0f);
mVertices[2].Position = new Vector3(0.1f, -0.1f, -1.0f);
mVertices[2].Color = new Color4(1.0f, 0.0f, 0.0f, 1.0f);
// Fill the vertex buffer
mVertexBuffer = new VertexBuffer(mDevice, VertexPositionColor.DeclarationSize, Usage.WriteOnly, VertexFormat.Position, Pool.Default);
mVertexBuffer.Lock(0, VertexPositionColor.DeclarationSize * mVertices.Length, LockFlags.None).WriteRange(mVertices);
mVertexBuffer.Unlock();
// Load the shaders
var vsByteCode = ShaderBytecode.CompileFromFile(@"\Shaders\DefaultShader.vs.hlsl", "DefaultVertexShader", "vs_2_0", ShaderFlags.None);
var psByteCode = ShaderBytecode.CompileFromFile(@"\Shaders\DefaultShader.ps.hlsl", "DefaultPixelShader", "ps_2_0", ShaderFlags.None);
mVertexShader = new VertexShader(mDevice, vsByteCode);
mPixelShader = new PixelShader(mDevice, psByteCode);
// Setup render states
mDevice.SetRenderState(RenderState.CullMode, Cull.None);
}
private void RenderSurface_MouseDown(object sender, MouseEventArgs e)
{
mLastPosition = e.Location;
}
private void RenderSurface_MouseMove(object sender, MouseEventArgs e)
{
if (mLastPosition == null)
{
return;
}
var position = e.Location;
var lastPosition = mLastPosition.Value;
mAngle += ((position.X - lastPosition.X) / 20.0f);
mLastPosition = position;
}
private void RenderSurface_MouseUp(object sender, MouseEventArgs e)
{
mLastPosition = null;
}
#endregion
#region Rendering
public void MainLoop()
{
var device = mDevice;
// Calculate matrices
Matrix projection = Matrix.PerspectiveFovRH(MathHelper.PiOver4, (float)this.RenderSurface.Width / (float)this.RenderSurface.Height, 1.0f, 1000.0f);
Matrix view = Matrix.LookAtRH(Vector3.UnitZ, Vector3.Zero, Vector3.UnitY) * Matrix.RotationY(mAngle);
Matrix viewProjection = view * projection;
// Initialize the graphics device
device.VertexShader = mVertexShader;
device.PixelShader = mPixelShader;
device.SetVertexShaderConstant(0, viewProjection);
// Render the scene
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, unchecked((int)0x00000000), 1.0f, 0);
device.BeginScene();
device.VertexDeclaration = VertexPositionColor.GetDeclaration(device);
device.SetStreamSource(0, mVertexBuffer, 0, VertexPositionColor.DeclarationSize);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, mVertices.Length);
device.EndScene();
device.Present();
}
#endregion
}
}
顶点着色器代码
float4x4 mWorldViewProjection;
struct VertexShaderInput
{
float4 Position : POSITION;
float4 Color : COLOR;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : TEXCOORD0;
};
VertexShaderOutput DefaultVertexShader ( VertexShaderInput input )
{
VertexShaderOutput output = ( VertexShaderOutput ) 0;
// Transform coordinates
output.Position = mul(input.Position, mWorldViewProjection);
// Copy other values
output.Color = input.Color;
return output;
}
像素着色器代码
struct PixelShaderInput
{
float4 Color : TEXCOORD0;
};
float4 DefaultPixelShader ( PixelShaderInput input ) : COLOR0
{
return input.Color;
}
I am working on a simple project whereby I wish to display a 3D object within a WinForms application using SlimDX. I have created a small project to do this, but I am encountering a problem where the object I have rendered is being clipped between 0.0f and -1.0f.
I have looked at a friend's code for a similar project (they do not have this problem) and cannot work out why it is happening. I've had to restrict the size of my object to the range of -0.1f -> 0.1f in order for me to be able to see it. Extending my far plane does nothing. The project my friend is using can load objects over 500 times the size of mine, with no clipping issues.
Does anyone have any suggestions? (Please see below for the screen shots and code)
Form Code
namespace TestOfTheTest
{
using System.Drawing;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using MathHelper = Microsoft.Xna.Framework.MathHelper;
public struct VertexPositionColor
{
private static VertexDeclaration sDeclaration;
public static VertexElement[] Elements =
{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, sizeof(float) * 3, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.Color, 0),
VertexElement.VertexDeclarationEnd
};
public Vector3 Position;
public Color4 Color;
public VertexPositionColor(Vector3 position, Color4 color)
{
this.Position = position;
this.Color = color;
}
public static int DeclarationSize
{
get { return (sizeof(float) * 3) + (sizeof(float) * 4); }
}
public static VertexDeclaration GetDeclaration(Device device)
{
if (sDeclaration == null)
{
sDeclaration = new VertexDeclaration(device, Elements);
}
return sDeclaration;
}
}
public partial class Form1 : Form
{
private Device mDevice;
private VertexPositionColor[] mVertices;
private VertexBuffer mVertexBuffer;
private VertexShader mVertexShader;
private PixelShader mPixelShader;
private Point? mLastPosition = null;
private float mAngle = 0.0f;
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
this.RenderSurface.MouseDown += RenderSurface_MouseDown;
this.RenderSurface.MouseMove += RenderSurface_MouseMove;
this.RenderSurface.MouseUp += RenderSurface_MouseUp;
}
#region UI Event Handlers
private void Form1_Load(object sender, System.EventArgs e)
{
var parameters = new PresentParameters()
{
BackBufferWidth = this.RenderSurface.Width,
BackBufferHeight = this.RenderSurface.Height,
Windowed = true,
DeviceWindowHandle = this.RenderSurface.Handle
};
mDevice = new Device(new Direct3D(), 0, DeviceType.Hardware, this.RenderSurface.Handle, CreateFlags.HardwareVertexProcessing, parameters);
// Create the vertices
mVertices = new VertexPositionColor[3];
mVertices[0].Position = new Vector3(-0.1f, -0.1f, -1.0f);
mVertices[0].Color = new Color4(1.0f, 1.0f, 0.0f, 0.0f);
mVertices[1].Position = new Vector3(0.0f, 0.1f, -1.0f);
mVertices[1].Color = new Color4(1.0f, 0.0f, 1.0f, 0.0f);
mVertices[2].Position = new Vector3(0.1f, -0.1f, -1.0f);
mVertices[2].Color = new Color4(1.0f, 0.0f, 0.0f, 1.0f);
// Fill the vertex buffer
mVertexBuffer = new VertexBuffer(mDevice, VertexPositionColor.DeclarationSize, Usage.WriteOnly, VertexFormat.Position, Pool.Default);
mVertexBuffer.Lock(0, VertexPositionColor.DeclarationSize * mVertices.Length, LockFlags.None).WriteRange(mVertices);
mVertexBuffer.Unlock();
// Load the shaders
var vsByteCode = ShaderBytecode.CompileFromFile(@"\Shaders\DefaultShader.vs.hlsl", "DefaultVertexShader", "vs_2_0", ShaderFlags.None);
var psByteCode = ShaderBytecode.CompileFromFile(@"\Shaders\DefaultShader.ps.hlsl", "DefaultPixelShader", "ps_2_0", ShaderFlags.None);
mVertexShader = new VertexShader(mDevice, vsByteCode);
mPixelShader = new PixelShader(mDevice, psByteCode);
// Setup render states
mDevice.SetRenderState(RenderState.CullMode, Cull.None);
}
private void RenderSurface_MouseDown(object sender, MouseEventArgs e)
{
mLastPosition = e.Location;
}
private void RenderSurface_MouseMove(object sender, MouseEventArgs e)
{
if (mLastPosition == null)
{
return;
}
var position = e.Location;
var lastPosition = mLastPosition.Value;
mAngle += ((position.X - lastPosition.X) / 20.0f);
mLastPosition = position;
}
private void RenderSurface_MouseUp(object sender, MouseEventArgs e)
{
mLastPosition = null;
}
#endregion
#region Rendering
public void MainLoop()
{
var device = mDevice;
// Calculate matrices
Matrix projection = Matrix.PerspectiveFovRH(MathHelper.PiOver4, (float)this.RenderSurface.Width / (float)this.RenderSurface.Height, 1.0f, 1000.0f);
Matrix view = Matrix.LookAtRH(Vector3.UnitZ, Vector3.Zero, Vector3.UnitY) * Matrix.RotationY(mAngle);
Matrix viewProjection = view * projection;
// Initialize the graphics device
device.VertexShader = mVertexShader;
device.PixelShader = mPixelShader;
device.SetVertexShaderConstant(0, viewProjection);
// Render the scene
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, unchecked((int)0x00000000), 1.0f, 0);
device.BeginScene();
device.VertexDeclaration = VertexPositionColor.GetDeclaration(device);
device.SetStreamSource(0, mVertexBuffer, 0, VertexPositionColor.DeclarationSize);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, mVertices.Length);
device.EndScene();
device.Present();
}
#endregion
}
}
Vertex Shader Code
float4x4 mWorldViewProjection;
struct VertexShaderInput
{
float4 Position : POSITION;
float4 Color : COLOR;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : TEXCOORD0;
};
VertexShaderOutput DefaultVertexShader ( VertexShaderInput input )
{
VertexShaderOutput output = ( VertexShaderOutput ) 0;
// Transform coordinates
output.Position = mul(input.Position, mWorldViewProjection);
// Copy other values
output.Color = input.Color;
return output;
}
Pixel Shader Code
struct PixelShaderInput
{
float4 Color : TEXCOORD0;
};
float4 DefaultPixelShader ( PixelShaderInput input ) : COLOR0
{
return input.Color;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我找到了解决方案。基本上,当在 DirectX(或本例中为 SlimDX)中单独使用顶点着色器和像素着色器并使用 SetVertexShaderConstant 函数将矩阵传递给顶点着色器时,这些矩阵是 转置 并存储为行主矩阵,而不是专栏专业。
有两种方法可以解决这个问题。
可以在此处找到导致解决方案的差异的指示。
I found the solution. Basically, when using the Vertex and Pixel Shaders separately in DirectX (or in this case, SlimDX) and using the SetVertexShaderConstant function to pass the matrices to the vertex shader, those matrices are transposed and stored as row-major matrices, instead of column-major.
There are two ways of resolving this.
Indication of this difference that lead to the resolution can be found here.