使用 SlimDX 时不正确的剪辑和 3D 投影 [英] Incorrect Clipping and 3D Projection when using SlimDX

查看:24
本文介绍了使用 SlimDX 时不正确的剪辑和 3D 投影的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个简单的项目,我希望在该项目中使用 SlimDX 在 WinForms 应用程序中显示 3D 对象.我创建了一个小项目来执行此操作,但是我遇到了一个问题,即我渲染的对象被裁剪在 0.0f 和 -1.0f 之间.

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.

我查看了一个朋友的类似项目的代码(他们没有这个问题),但无法弄清楚为什么会发生这种情况.我不得不将对象的大小限制在 -0.1f -> 0.1f 的范围内,以便我能够看到它.延长我的远平面没有任何作用.我朋友正在使用的项目可以加载比我的大 500 倍以上的对象,而且没有剪裁问题.

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)

表单代码

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(@"ShadersDefaultShader.vs.hlsl", "DefaultVertexShader", "vs_2_0", ShaderFlags.None);
            var psByteCode = ShaderBytecode.CompileFromFile(@"ShadersDefaultShader.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;
}

推荐答案

我找到了解决方案.基本上,当在 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.

  1. 在使用图形设备上的 SetVertexShaderConstant 函数将所有矩阵传递给顶点着色器之前,对其进行预转置.
  2. 利用 DirectX Effect 框架,它会自行处理这种预转置,从而更轻松地处理矩阵.

可以在此处.

这篇关于使用 SlimDX 时不正确的剪辑和 3D 投影的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆