Directx贴图的一个小问题,急求解答,在线等

时间:2021-07-07 17:38:06
不知道为什么图片一面一点会渲染到最上面
下面为图片
[img=http://wrp5hw.bay.livefilestore.com/y1pHwtG4ny5VXddFZhp2mJ3K7HUvZmBksxku25jJYP2R0PKAV-6YCFndu9BKOe1eF2eVoXJ7Nf__zc4yOb_7vFjw230QRauMFrg/捕获.JPG?psid=1][/img]
下面这张比较明显点
[img=http://wrp5hw.bay.livefilestore.com/y1pLQLx2t2dukhe7ftO0s-Qhr6GwiGtRj52tPsrxZND_sEBxXCaCqYFOCahfWL6yKnVKgs2tukAxtEX7KAePr1suBoNx-Rbt-6r/捕获1.JPG?psid=1][/img]

#include <d3d9.h>
#include <d3dx9.h>
#include <string>
#pragma comment(lib,"d3d9.lib")   
#pragma comment(lib,"d3dx9.lib")



#define WINDOW_CLASS    "UGPDX"
#define WINDOW_NAME     "D3D Texture Mapping"
#define WINDOW_WIDTH    1024
#define WINDOW_HEIGHT   640

// Function Prototypes...
bool InitializeD3D(HWND hWnd, bool fullscreen);
bool InitializeObjects();
void RenderScene();
void Shutdown();


// Direct3D object and device.
LPDIRECT3D9 g_D3D = NULL;
LPDIRECT3DDEVICE9 g_D3DDevice = NULL;

// Matrices.
D3DXMATRIX g_projection;
D3DXMATRIX g_ViewMatrix;

// Vertex buffer to hold the geometry.
LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL;

// Holds a texture image.
LPDIRECT3DTEXTURE9 g_Texture = NULL;

// A structure for our custom vertex type
struct stD3DVertex
{
    float x, y, z,rhw;
    unsigned long color;
    float tu, tv;
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)


LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
      {
         case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
            break;

         case WM_KEYUP:
            if(wParam == VK_ESCAPE) PostQuitMessage(0);
            break;
      }

   return DefWindowProc(hWnd, msg, wParam, lParam);
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show)
{
   // Register the window class
   WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                     GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                     WINDOW_CLASS, NULL };
   RegisterClassEx(&wc);

   // Create the application's window
   HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
                            100, 100, WINDOW_WIDTH, WINDOW_HEIGHT,
                            GetDesktopWindow(), NULL, wc.hInstance, NULL);

   // Initialize Direct3D
   if(InitializeD3D(hWnd, false))
      {
         // Show the window
         ShowWindow(hWnd, SW_SHOWDEFAULT);
         UpdateWindow(hWnd);

         // Enter the message loop
         MSG msg;
         ZeroMemory(&msg, sizeof(msg));

         while(msg.message != WM_QUIT)
            {
               if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
                  {
                     TranslateMessage(&msg);
                     DispatchMessage(&msg);
                  }
               else
                  RenderScene();
            }
      }

   // Release any and all resources.
   Shutdown();

   // Unregister our window.
   UnregisterClass(WINDOW_CLASS, wc.hInstance);
   return 0;
}


bool InitializeD3D(HWND hWnd, bool fullscreen)
{
   D3DDISPLAYMODE displayMode;

   // Create the D3D object.
   g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
   if(g_D3D == NULL) return false;

   // Get the desktop display mode.
   if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))
      return false;

   // Set up the structure used to create the D3DDevice
   D3DPRESENT_PARAMETERS d3dpp;
   ZeroMemory(&d3dpp, sizeof(d3dpp));

   if(fullscreen)
      {
         d3dpp.Windowed = FALSE;
         d3dpp.BackBufferWidth = WINDOW_WIDTH;
         d3dpp.BackBufferHeight = WINDOW_HEIGHT;
      }
   else
      d3dpp.Windowed = TRUE;
   d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
   d3dpp.BackBufferFormat = displayMode.Format;

   // Create the D3DDevice
   if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
             D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_D3DDevice)))
      {
         return false;
      }

   // Initialize any objects we will be displaying.
   if(!InitializeObjects()) return false;

   return true;
}


bool InitializeObjects()
{
   // Fill in our structure to draw an object.
   // x, y, z, color, texture coords.
   stD3DVertex objData[] =
      {
      {1024.0f, 0.0f, 1.0f, 2, D3DCOLOR_XRGB(255,255,255), 1.0f, 0.0f},
        {0.0f, 0.0f, 1.0f, 2, D3DCOLOR_XRGB(255,255,255), 0.0f, 0.0f},

         
      {0.0f, 640.0f, 1.0f, 2, D3DCOLOR_XRGB(255,255,255), 0.0f, 1.0f},

      {0.0f, 640.0f, 1.0f, 2, D3DCOLOR_XRGB(255,255,255), 0.0f, 1.0f},
      
      {1024.0f, 0.0f, 1.0f, 2, D3DCOLOR_XRGB(255,255,255), 1.0f, 0.0f},

         {1024.0f, 640.0f, 1.0f, 2, D3DCOLOR_XRGB(255,255,255), 1.0f, 1.0f},
      };

   // Create the vertex buffer.
   if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(objData), 0,
             D3DFVF_VERTEX, D3DPOOL_DEFAULT,
             &g_VertexBuffer, NULL))) return false;
   
   // Fill the vertex buffer.
   void *ptr;

   if(FAILED(g_VertexBuffer->Lock(0, sizeof(objData),
      (void**)&ptr, 0))) return false;

   memcpy(ptr, objData, sizeof(objData));

   g_VertexBuffer->Unlock();


   // Load the texture image from file.
   if(D3DXCreateTextureFromFile(g_D3DDevice, "1.jpg",
      &g_Texture) != D3D_OK) return false;

   // Set the image states to get a good quality image.
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER,
                             D3DTEXF_LINEAR);
g_D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER,
                             D3DTEXF_LINEAR);


// Set default rendering states.
   g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);


   // Set the projection matrix.
   D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
      WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);

   g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

   // Define camera information.
   D3DXVECTOR3 cameraPos(0.0f, 0.0f, -1.0f);
   D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);
   D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f);

   // Build view matrix.
   D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,
                      &lookAtPos, &upDir);

   return true;
}


void RenderScene()
{
   // Clear the backbuffer.
   g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
                      D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

   // Begin the scene.  Start rendering.
   g_D3DDevice->BeginScene();

      // Apply the view (camera).
      g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

      // Draw square.
      g_D3DDevice->SetTexture(0, g_Texture);
      g_D3DDevice->SetStreamSource(0, g_VertexBuffer,
                                   0, sizeof(stD3DVertex));
      g_D3DDevice->SetFVF(D3DFVF_VERTEX);
      g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

   // End the scene.  Stop rendering.
   g_D3DDevice->EndScene();

   // Display the scene.
   g_D3DDevice->Present(NULL, NULL, NULL, NULL);
}


void Shutdown()
{
   if(g_D3DDevice != NULL) g_D3DDevice->Release();
   g_D3DDevice = NULL;

   if(g_D3D != NULL) g_D3D->Release();
   g_D3D = NULL;

   if(g_VertexBuffer != NULL) g_VertexBuffer->Release();
   g_VertexBuffer = NULL;

   if(g_Texture != NULL) g_Texture->Release();
   g_Texture = NULL;
}

12 个解决方案

#1


纹理采样使用了D3DTADDRESS_WRAP和D3DTEXF_LINEAR的时候,边缘处的像素会用“对面”的像素参与混合。使用SetSampleState把D3DSAMP_ADDRESSU和D3DSAMP_ADDRESSV设置为D3DTADDRESS_CLAMP应该可以解决这个问题。

#2


纹理坐标没问题一般不会有这种情况

#3


引用 1 楼 silenker 的回复:
纹理采样使用了D3DTADDRESS_WRAP和D3DTEXF_LINEAR的时候,边缘处的像素会用“对面”的像素参与混合。使用SetSampleState把D3DSAMP_ADDRESSU和D3DSAMP_ADDRESSV设置为D3DTADDRESS_CLAMP应该可以解决这个问题。

用你的方法,加了2行代码
g_D3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP);
     g_D3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_CLAMP);

左边的没了,可是上面的还在

#4


我有个建议,把纹理坐标偏移0.5个像素
比如原来是0.0的,改成 1.0/2048.0

#5


用D3D做2D,有些地方是不太精确

#6


试试用D3DTADDRESS_BORDER。
我在OGL下也遇上过这个问题,用的是GL_CLAMP_TO_EDGE。

#7


http://hi.baidu.com/starloooooove/blog/item/21a7017a526cf8e72f73b3c7.html

#8


引用 4 楼 gamemagic 的回复:
我有个建议,把纹理坐标偏移0.5个像素
比如原来是0.0的,改成 1.0/2048.0

这个治标不治本啊,不过多谢帮忙思考

#9


    g_D3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_BORDER);能使上面变黑,其他的都是原样,很奇怪。

#10


如果你要治本的话,应该使用shader来写一个2D渲染管线,这样就绝对没问题了。至少我从来没遇到这问题,采样相当精确

#11


引用 8 楼 soullessm 的回复:
这个治标不治本啊,不过多谢帮忙思考


在DX9下面,那个是标准的做法,并不是“治标不治本”,参见DX9 SDK里面的文档“Directly Mapping Texels to Pixels ”
但是在DX10/11里面就不需要这么做了。


引用 10 楼 gamemagic 的回复:
如果你要治本的话,应该使用shader来写一个2D渲染管线,这样就绝对没问题了。至少我从来没遇到这问题,采样相当精确


使用shader和使用固定管线在这个问题上是没有差别的,你没遇到这个问题可能是你的shader一开始就设置了正确的采样模式,并不是shader本身能避免这个问题。

但是使用shader可以在保证原始数据数学正确的前提下进行快速的纹理坐标0.5像素修正,这个很不错。

#12


引用 11 楼 silenker 的回复:
引用 8 楼 soullessm 的回复:
这个治标不治本啊,不过多谢帮忙思考


在DX9下面,那个是标准的做法,并不是“治标不治本”,参见DX9 SDK里面的文档“Directly Mapping Texels to Pixels ”
但是在DX10/11里面就不需要这么做了。


引用 10 楼 gamemagic 的回复:
如果你要治本的话,应该使用shader来写一个2……

我自己再去调下,谢了

#1


纹理采样使用了D3DTADDRESS_WRAP和D3DTEXF_LINEAR的时候,边缘处的像素会用“对面”的像素参与混合。使用SetSampleState把D3DSAMP_ADDRESSU和D3DSAMP_ADDRESSV设置为D3DTADDRESS_CLAMP应该可以解决这个问题。

#2


纹理坐标没问题一般不会有这种情况

#3


引用 1 楼 silenker 的回复:
纹理采样使用了D3DTADDRESS_WRAP和D3DTEXF_LINEAR的时候,边缘处的像素会用“对面”的像素参与混合。使用SetSampleState把D3DSAMP_ADDRESSU和D3DSAMP_ADDRESSV设置为D3DTADDRESS_CLAMP应该可以解决这个问题。

用你的方法,加了2行代码
g_D3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP);
     g_D3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_CLAMP);

左边的没了,可是上面的还在

#4


我有个建议,把纹理坐标偏移0.5个像素
比如原来是0.0的,改成 1.0/2048.0

#5


用D3D做2D,有些地方是不太精确

#6


试试用D3DTADDRESS_BORDER。
我在OGL下也遇上过这个问题,用的是GL_CLAMP_TO_EDGE。

#7


http://hi.baidu.com/starloooooove/blog/item/21a7017a526cf8e72f73b3c7.html

#8


引用 4 楼 gamemagic 的回复:
我有个建议,把纹理坐标偏移0.5个像素
比如原来是0.0的,改成 1.0/2048.0

这个治标不治本啊,不过多谢帮忙思考

#9


    g_D3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_BORDER);能使上面变黑,其他的都是原样,很奇怪。

#10


如果你要治本的话,应该使用shader来写一个2D渲染管线,这样就绝对没问题了。至少我从来没遇到这问题,采样相当精确

#11


引用 8 楼 soullessm 的回复:
这个治标不治本啊,不过多谢帮忙思考


在DX9下面,那个是标准的做法,并不是“治标不治本”,参见DX9 SDK里面的文档“Directly Mapping Texels to Pixels ”
但是在DX10/11里面就不需要这么做了。


引用 10 楼 gamemagic 的回复:
如果你要治本的话,应该使用shader来写一个2D渲染管线,这样就绝对没问题了。至少我从来没遇到这问题,采样相当精确


使用shader和使用固定管线在这个问题上是没有差别的,你没遇到这个问题可能是你的shader一开始就设置了正确的采样模式,并不是shader本身能避免这个问题。

但是使用shader可以在保证原始数据数学正确的前提下进行快速的纹理坐标0.5像素修正,这个很不错。

#12


引用 11 楼 silenker 的回复:
引用 8 楼 soullessm 的回复:
这个治标不治本啊,不过多谢帮忙思考


在DX9下面,那个是标准的做法,并不是“治标不治本”,参见DX9 SDK里面的文档“Directly Mapping Texels to Pixels ”
但是在DX10/11里面就不需要这么做了。


引用 10 楼 gamemagic 的回复:
如果你要治本的话,应该使用shader来写一个2……

我自己再去调下,谢了