DX9: Deformed Textures

Started by
4 comments, last by Mibran 15 years, 10 months ago
Hi there, I'm trying to get a start on DirectX9, currently it's texture loading to learn. I've experienced a problem when displaying a texture loaded with a simple D3DXCreateTextureFromFile- I'm mapping that texture on a 3-sided pyramid, but when rotating that pyramid it deforms the texture (as shown here). Changing D3DDEVTYPE_REF to D3DDEVTYPE_HAL didn't help, D3DCREATE_SOFTWARE_VERTEXPROCESSING or D3DCREATE_HARDWARE_VERTEXPROCESSING also didn't change anything. I'm not working with lights, D3DRS_LIGHTING is set to false, the FVF type is D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1. Can anyone help? Thanks in advance, Michael Here's the source:

/***  Defines  ***/
#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff
#define SZ_CLASS	"3D Shapes"
#define WIDTH		640
#define HEIGHT		480
#define WINDOWED	TRUE
#define VERTEX_TYPE	D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1 

/*** Header Files ***/
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h> // D3DX library

/*** Structs ***/
struct sVertex{
	FLOAT		x, y, z;	// vertex position
	D3DCOLOR	color;		// vertex color
	FLOAT u,v;				// D3DFVF_TEX1
};

/***  Globals ***/
HWND			g_hWnd;
HINSTANCE		g_hInst;
IDirect3D9*		g_pD3D;
IDirect3DDevice9*	g_pD3Device;
sVertex*		g_triangleStripPyramid;
FLOAT			g_rotateY=0;
IDirect3DTexture9* g_pTexture;

/***  Methods ***/
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev,LPSTR szCmdLine, int nCmdShow);
long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg,WPARAM wParam, LPARAM lParam);

BOOL InitDirectX();	// where we initalize DirectX
BOOL UpdateGame();	// where we get input and update game data
BOOL RenderGame();	// where we render the game world
BOOL LoadTexture(const char* filename, IDirect3DTexture9** pTexture);
void ShutdownDirectX(); // where we shutdown DirectX

/*** Code ***/
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
{
	g_hInst = hInst;

	WNDCLASS wc;
	ZeroMemory(&wc,sizeof(WNDCLASS));	// init window class
	wc.lpfnWndProc   = WindowProc;		// callback method
	wc.hInstance     = hInst;		// instance handle
	wc.lpszClassName = SZ_CLASS;		// instance name
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // background color

	if(!RegisterClass(&wc))	// register window class
		return FALSE;

	g_hWnd = CreateWindow(		// create the window
	                 SZ_CLASS,	// class name
	                 SZ_CLASS,	// window name
	                 WS_CAPTION | WS_SYSMENU | WS_VISIBLE, // decorate & show window
	                 0,		// x position
	                 0,		// y position
	                 WIDTH,
	                 HEIGHT,
	                 NULL,		// parent window (none)
	                 NULL,		// menu (none)
	                 g_hInst,	// our window instance
	                 NULL);		// message (none)

	if(!g_hWnd)
		return FALSE;		// couldn't create window ?

	if(!InitDirectX())		// initialize DirectX here
		return FALSE;

	// Run message processing (until user quits)
	MSG Msg;
	ZeroMemory(&Msg, sizeof(MSG)); 	// clear message
	while(Msg.message != WM_QUIT)
	{
		// pass through any system message
		if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}

		if(!UpdateGame()) // get input & update data
			break;

		if(!RenderGame()) // render game here
			break;
	}

	ShutdownDirectX();

	UnregisterClass(SZ_CLASS, hInst); // free window resources

	return Msg.wParam;
}

long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// handle message by type
	switch(uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0); // user or system has quit application
		return 0;
	}

	// let windows do the rest
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

BOOL InitDirectX()
{
	// init Direct3D and set global pointer to it
	g_pD3D=Direct3DCreate9(D3D_SDK_VERSION);
	if(g_pD3D==NULL)
		return FALSE; // failed ?

	// set device params ...
	D3DPRESENT_PARAMETERS params;
	ZeroMemory(&params,sizeof(params));
	params.hDeviceWindow    = g_hWnd;
	params.Windowed = WINDOWED;
	params.SwapEffect = D3DSWAPEFFECT_DISCARD;
	params.BackBufferCount  = 1;
	params.BackBufferFormat = (WINDOWED) ? D3DFMT_UNKNOWN : D3DFMT_X8R8G8B8;
	params.BackBufferHeight = (WINDOWED) ? 0 : WIDTH;
	params.BackBufferWidth  = (WINDOWED) ? 0 : HEIGHT;

	// debug only with this (slow) device type
	D3DDEVTYPE devType=D3DDEVTYPE_REF;

	// debug only with this (slow) vertex processing type
	DWORD vertexProc=D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	/* Explain device types and vertex processing type */

	// ... and create the device with it
	g_pD3D->CreateDevice(
	        D3DADAPTER_DEFAULT,	// primary videocard
	        devType,		// see above
	        g_hWnd,			// our window handle
	        vertexProc,		// see above
	        &params,		// see above
	        &g_pD3Device);		// sets our (global) device pointer

	if(g_pD3Device==NULL)
		return FALSE; // failed ?

	// create triangle
	const int num_vert=12;
	sVertex triangle[num_vert]=
        {
            // x, y, z, color, normal
			// bottom
			{  -75.0f,   0.0f, 50.0f,  D3DCOLOR_RGBA(255,255,255,0), 1.0f,1.0f},	 // 1
			{    75.0f,  0.0f, 50.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.0f,1.0f},		 // 2
			{   0.0f,   0.0f, -90.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.5f,0.0f},		 // 3

			// front
			{  -75.0f,   0.0f, 50.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.0f,1.0f},	 // 1
			{    0.0f,  125.0f, 0.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.5f,0.0f},		 // 4
			{    75.0f,  0.0f, 50.0f,  D3DCOLOR_RGBA(255,255,255,0), 1.0f,1.0f},		 // 2

			// Right
			{    75.0f,  0.0f, 50.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.0f,1.0f},		 // 2
			{    0.0f,  125.0f, 0.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.5f,0.0f},		 // 4
			{   0.0f,   0.0f, -90.0f,  D3DCOLOR_RGBA(255,255,255,0), 1.0f,1.0f},		 // 3

			// Left
			{   0.0f,   0.0f, -90.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.0f,1.0f},		 // 3
			{    0.0f,  125.0f, 0.0f,  D3DCOLOR_RGBA(255,255,255,0), 0.5f,0.0f},		 // 4
			{  -75.0f,   0.0f, 50.0f,  D3DCOLOR_RGBA(255,255,255,0), 1.0f,1.0f}	 // 1
        };

	g_triangleStripPyramid=new sVertex[num_vert];
	memcpy(g_triangleStripPyramid,triangle,num_vert*sizeof(sVertex));

	BOOL load=LoadTexture("texture.png",&g_pTexture);
	if(load=FALSE)
		return FALSE;

	D3DXMATRIX matView;
	D3DXMatrixIdentity(&matView);
	D3DXMatrixLookAtLH(
		&matView,
		&D3DXVECTOR3(0.0f,-100.0f,-300.0f),	// Position: -500 means +500
		&D3DXVECTOR3(0.0f,10.0f,0.0f),		// Target 
		&D3DXVECTOR3(0.0f,1.0f,0.0f));		// Camera Tilt
	g_pD3Device->SetTransform(D3DTS_VIEW,&matView);

	D3DXMATRIX matProj;
	D3DXMatrixIdentity(&matProj);
	D3DXMatrixPerspectiveFovLH(
		&matProj,
		D3DX_PI/4,			// fovy [radians] (FLOAT), here: 45 Degrees
		(FLOAT)WIDTH/(FLOAT)HEIGHT,	// aspect = w/h (FLOAT)
		1.0f,				// z near (FLOAT)
		1000.0f				// z far (FLOAT)
		);
	g_pD3Device->SetTransform(D3DTS_PROJECTION,&matProj);

	g_pD3Device->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off lightning (for now)

	return TRUE;
}

void ShutdownDirectX()
{
	if(g_pTexture!=NULL)
		delete g_pTexture;
	g_pTexture=NULL;

	if(g_triangleStripPyramid!=NULL)
		delete[] g_triangleStripPyramid;
	g_triangleStripPyramid=NULL;

	if(g_pD3Device)
		g_pD3Device->Release();
	g_pD3Device=NULL;

	if(g_pD3D)
		g_pD3D->Release();
	g_pD3D=NULL;
}

BOOL UpdateGame()
{
	g_rotateY+=-0.09f;
	if(g_rotateY>2*D3DX_PI)
		g_rotateY=0.0f;

	return TRUE;
}

BOOL RenderGame()
{
	// clear surface
	g_pD3Device->Clear(
	                        0,		// how many rects
	                        NULL,	// pointer to D3DRECT array (NULL = whole surface)
	                        D3DCLEAR_TARGET,// clear current target (see D3DCLEAR enum)
	                        D3DCOLOR_RGBA(0,0,0,255), // color
	                        1.0f,	// clear depth buffer to 1.0
	                        0		// clear stencil buffer to 0
	                );

	//Notify the device that we're ready to render
	g_pD3Device->BeginScene();

g_pD3Device->SetTexture(0,g_pTexture);

	g_pD3Device->SetFVF(VERTEX_TYPE);
	g_pD3Device->DrawPrimitiveUP(D3DPT_TRIANGLELIST,
	                             4,			 // number of primitives
	                             g_triangleStripPyramid,// address of vertices
	                             sizeof(sVertex));   // data size of one vertex

g_pD3Device->SetTexture(0,NULL); // forgetting this may cause memory leaks !

	D3DXMATRIX worldMatrix;
	g_pD3Device->GetTransform(D3DTS_WORLD,&worldMatrix);
	D3DXMatrixRotationY(&worldMatrix,g_rotateY);
	g_pD3Device->SetTransform(D3DTS_WORLD,&worldMatrix);

	//Notify the device that we're finished rendering for this frame
	g_pD3Device->EndScene();

	g_pD3Device->Present(
	                        NULL,	// pSourceRect
	                        NULL,	// pDestRect
	                        NULL,	// destination window (HWND)
	                        NULL	// dirty region (see "swap chains")
	                );

	return TRUE;
}

BOOL LoadTexture(const char* filename, IDirect3DTexture9** pTexture)
{
	D3DXCreateTextureFromFile(
		g_pD3Device,	// the D3DDevice
		filename,		// filename
		pTexture);		// returns texture
	
	return TRUE;
}


Advertisement
It's hard to tell, but it could be that your triangles have reversed winding, so you're seeing the back faces, not the front faces. That would mean you are seeing the inside of the pyramid, not the outside, which could give the perspective on your picture.

Trying changing the winding of your triangles (easily done by swapping vertex 2 and 3 in each triangle), or change the culling from clockwise (CW) to count-clockwise (CCW).
like Promethium said, add this in, g_pD3Device->SetRenderState(D3DRS_CULLMODE, mode);

where mode could be one of these

D3DCULL_NONE
D3DCULL_CW
D3DCULL_CCW
Just for clarification,
what you refer to as a 3-sided pyramid is a Tetrahedron
http://en.wikipedia.org/wiki/Tetrahedron
The triangles are all CCW, so that's fine.

And, from the picture, it appears you're seeing the texture coordinates you've programmed in.

It does appear somewhat distorted but you also have a very odd-shaped pyramid ( the length along x=150, along y=125, along z = 100 ) so you may very well be seeing what you've programmed.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Thanks for the answers from all of you!

Buckeye got it right: The Tetrahedron (sorry for naming it "pyramid") was pretty malformed. After recalculating it having absolutely isosceles triangles with the Y-axis running through the base triangle's centroid, the problem disappeared.

Computers only do what we tell them to do, I should more often believe in that. Or as we say in my home country: "There was a bend in my eye's pupil" [grin]

Sorry for wasting your time for that...

Michael

Here are the correct coordinates:
	sVertex triangle[num_vert]=        {            // x, y, z, color, normal			// bottom			{  -50.0f,  0.0f,  28.9f,  1.0f,1.0f},		// 1			{   50.0f,  0.0f,  28.9f,  0.0f,1.0f},		 // 2			{    0.0f,  0.0f, -57.7f,  0.5f,0.0f},		 // 3			// front			{  -50.0f,  0.0f,  28.9f,  0.0f,1.0f},		// 1			{    0.0f,  81.7f, 0.0f,  0.5f,0.0f},		// 4			{   50.0f,  0.0f,  28.9f,  1.0f,1.0f},		 // 2			// Right			{   50.0f,  0.0f,  28.9f,  0.0f,1.0f},		 // 2			{    0.0f,  81.7f,  0.0f,  0.5f,0.0f},		// 4			{    0.0f,  0.0f, -57.7f,  1.0f,1.0f},		 // 3			// Left			{    0.0f,  0.0f, -57.7f,  0.0f,1.0f},		 // 3			{    0.0f,  81.7f,  0.0f,  0.5f,0.0f},		// 4			{  -50.0f,  0.0f,  28.9f,  1.0f,1.0f},		// 1        };

This topic is closed to new replies.

Advertisement