2012-11-08 41 views
3

嘿在一起,網格開始跳上相機旋轉/運動

第一次在這裏發帖,因爲我該死的卡...

越遠的網格是從原點( 0,0,0)時,旋轉或移動相機時它越「跳躍」/「閃爍」。描述這種效果很難:它就像網格抖動/顫抖/有點顫抖,隨着距離原點的增加,這種顫抖變得越來越大。
對我來說,它開始在距離原點約100000個單位距離處觀察到,例如在(0,0,100000)處。翻譯的軸線和網格的類型(從Mesh.Create創建的默認網格...或者使用assimp.NET導入的3ds網格)都不會影響這種效果。當發生這種效應時,網格位置的值不會改變,通過記錄位置進行檢查。

如果我不是失去了一些東西,這個範圍縮小到兩種可能性:

  1. 我的相機代碼
  2. 的DirectX的設備

對於DirectX的設備,這是我的設備初始化代碼:

private void InitializeDevice() 
    { 
     //Initialize D3D 
     _d3dObj = new D3D9.Direct3D(); 

     //Set presentation parameters 
     _presParams = new D3D9.PresentParameters(); 
     _presParams.Windowed = true; 
     _presParams.SwapEffect = D3D9.SwapEffect.Discard; 
     _presParams.AutoDepthStencilFormat = D3D9.Format.D16; 
     _presParams.EnableAutoDepthStencil = true; 
     _presParams.PresentationInterval = D3D9.PresentInterval.One; 
     _presParams.BackBufferFormat = _d3dObj.Adapters.DefaultAdapter.CurrentDisplayMode.Format; 
     _presParams.BackBufferHeight = _d3dObj.Adapters.DefaultAdapter.CurrentDisplayMode.Height; 
     _presParams.BackBufferWidth = _d3dObj.Adapters.DefaultAdapter.CurrentDisplayMode.Width; 

     //Set form width and height to current backbuffer width und height 
     this.Width = _presParams.BackBufferWidth; 
     this.Height = _presParams.BackBufferHeight; 

     //Checking device capabilities 
     D3D9.Capabilities caps = _d3dObj.GetDeviceCaps(0, D3D9.DeviceType.Hardware); 
     D3D9.CreateFlags devFlags = D3D9.CreateFlags.SoftwareVertexProcessing; 
     D3D9.DeviceType devType = D3D9.DeviceType.Reference; 

     //setting device flags according to device capabilities 
     if ((caps.VertexShaderVersion >= new Version(2, 0)) && (caps.PixelShaderVersion >= new Version(2, 0))) 
     { 
      //if device supports vertexshader and pixelshader >= 2.0 
      //then use the hardware device 
      devType = D3D9.DeviceType.Hardware; 

      if (caps.DeviceCaps.HasFlag(D3D9.DeviceCaps.HWTransformAndLight)) 
      { 
       devFlags = D3D9.CreateFlags.HardwareVertexProcessing; 
      } 
      if (caps.DeviceCaps.HasFlag(D3D9.DeviceCaps.PureDevice)) 
      { 
       devFlags |= D3D9.CreateFlags.PureDevice; 
      } 
     } 

     //initialize the device 
     _device = new D3D9.Device(_d3dObj, 0, devType, this.Handle, devFlags, _presParams); 
     //set culling 
     _device.SetRenderState(D3D9.RenderState.CullMode, D3D9.Cull.Counterclockwise); 
     //set texturewrapping (needed for seamless spheremapping) 
     _device.SetRenderState(D3D9.RenderState.Wrap0, D3D9.TextureWrapping.All); 
     //set lighting 
     _device.SetRenderState(D3D9.RenderState.Lighting, false); 
     //enabling the z-buffer 
     _device.SetRenderState(D3D9.RenderState.ZEnable, D3D9.ZBufferType.UseZBuffer); 
     //and setting write-access exlicitly to true... 
     //i'm a little paranoid about this since i had to struggle for a few days with weirdly overlapping meshes 
     _device.SetRenderState(D3D9.RenderState.ZWriteEnable, true); 
    } 

我是否缺少一個標誌或renderstate?有什麼可能導致這種奇怪/扭曲的行爲?

我的相機類是基於Michael Silvermans C++ Quaternion Camera

//every variable prefixed with an underscore is 
//a private static variable initialized beforehand 
public static class Camera 
{ 
    //gets called every frame 
    public static void Update() 
    { 
     if (_filter) 
     { 
      _filteredPos = Vector3.Lerp(_filteredPos, _pos, _filterAlpha); 
      _filteredRot = Quaternion.Slerp(_filteredRot, _rot, _filterAlpha); 
     } 

     _device.SetTransform(D3D9.TransformState.Projection, Matrix.PerspectiveFovLH(_fov, _screenAspect, _nearClippingPlane, _farClippingPlane)); 
     _device.SetTransform(D3D9.TransformState.View, GetViewMatrix()); 
    } 

    public static void Move(Vector3 delta) 
    { 
     _pos += delta; 
    } 

    public static void RotationYaw(float theta) 
    { 
     _rot = Quaternion.Multiply(Quaternion.RotationAxis(_up, -theta), _rot); 
    } 

    public static void RotationPitch(float theta) 
    { 
     _rot = Quaternion.Multiply(_rot, Quaternion.RotationAxis(_right, theta)); 
    } 

    public static void SetTarget(Vector3 target, Vector3 up) 
    { 
     SetPositionAndTarget(_pos, target, up); 
    } 

    public static void SetPositionAndTarget(Vector3 position, Vector3 target, Vector3 upVec) 
    { 
     _pos = position; 

     Vector3 up, right, lookAt = target - _pos; 

     lookAt = Vector3.Normalize(lookAt); 
     right = Vector3.Cross(upVec, lookAt); 
     right = Vector3.Normalize(right); 
     up = Vector3.Cross(lookAt, right); 
     up = Vector3.Normalize(up); 

     SetAxis(lookAt, up, right); 
    } 

    public static void SetAxis(Vector3 lookAt, Vector3 up, Vector3 right) 
    { 
     Matrix rot = Matrix.Identity; 

     rot.M11 = right.X; 
     rot.M12 = up.X; 
     rot.M13 = lookAt.X; 

     rot.M21 = right.Y; 
     rot.M22 = up.Y; 
     rot.M23 = lookAt.Y; 

     rot.M31 = right.Z; 
     rot.M32 = up.Z; 
     rot.M33 = lookAt.Z; 

     _rot = Quaternion.RotationMatrix(rot); 
    } 

    public static void ViewScene(BoundingSphere sphere) 
    { 
     SetPositionAndTarget(sphere.Center - new Vector3((sphere.Radius + 150)/(float)Math.Sin(_fov/2), 0, 0), sphere.Center, new Vector3(0, 1, 0)); 
    } 

    public static Vector3 GetLookAt() 
    { 
     Matrix rot = Matrix.RotationQuaternion(_rot); 
     return new Vector3(rot.M13, rot.M23, rot.M33); 
    } 

    public static Vector3 GetRight() 
    { 
     Matrix rot = Matrix.RotationQuaternion(_rot); 
     return new Vector3(rot.M11, rot.M21, rot.M31); 
    } 

    public static Vector3 GetUp() 
    { 
     Matrix rot = Matrix.RotationQuaternion(_rot); 
     return new Vector3(rot.M12, rot.M22, rot.M32); 
    } 

    public static Matrix GetViewMatrix() 
    { 
     Matrix viewMatrix, translation = Matrix.Identity; 
     Vector3 position; 
     Quaternion rotation; 

     if (_filter) 
     { 
      position = _filteredPos; 
      rotation = _filteredRot; 
     } 
     else 
     { 
      position = _pos; 
      rotation = _rot; 
     } 

     translation = Matrix.Translation(-position.X, -position.Y, -position.Z); 
     viewMatrix = Matrix.Multiply(translation, Matrix.RotationQuaternion(rotation)); 

     return viewMatrix; 
    } 
} 

你發現在相機中的代碼任何可能導致此行爲?

我無法想象,DirectX無法處理大於100k的距離。我應該渲染太陽系,我使用1單位= 1公里。因此,地球將在(0,0,152100000)處與太陽的最大距離呈現(就如一個例子)。如果這些「跳躍」持續發生,這變得不可能。 最後我想到了縮小一切,以便系統永遠不會超過距離原點100k/-100k的距離,但我認爲這不會起作用,因爲隨着離原點的距離變大,「抖動」變大。縮小一切縮小的範圍 - 我認爲 - 也會縮小跳躍行爲。

+2

我認爲這可能是您的問題。 DirectX使用通常具有6-7位精度的浮點數,這意味着當它們是152100000時,則表示的最小變化大約是10000單位。 – jcoder

+0

感謝您的評論,從來沒有想過背後的數據類型。 然後縮小整個系統應該使問題消失。 –

+1

縮小它的範圍,或者用更多的本地座標系統將你的世界分成更小的塊,這顯然是更多的工作,並且需要你以某種方式處理區域之間的移動 – jcoder

回答

1

只是爲了不離開這個問題的答覆(學分@jcoder,看問題的意見):

網格的怪異的行爲來自DX的浮點精度。你的世界越大,準確計算位置的準確性越低。

有兩種方法可以解決這個問題:

  1. 降尺度全世界
    這可能是一個「銀河式」的世界裏,你有非常大的位置偏移問題,以及非常小一些(即行星與太陽之間的距離確實很大,但是行星軌道上的太空船的距離可能非常小)
  2. 將世界劃分成更小的塊
    這樣你就可以表達所有相對於其他東西(請參閱stackoverflow.com/questions/1930421)或製作多個世界並以某種方式在它們之間移動