http://www.mystic24.com/zboard/data/idle/Q.zip
실행결과는 그냥 거멓게 나옵니다.
무엇이 문제일지.. 참으로 알수가 없게 되버렸다는...
다음은 소스 내용입니다. 텍스처인 banana.bmp는 Q.zip안에 있어요.
진하게 된 부분이 원래 텍스처 예제에서 추가만 시킨겁니다.
어디서 문제가 있었을까요??
/**-------------------------------------------------------------------------------
* brief 텍스쳐 맵핑
* 파일 : textures.cpp
*
* 설명: 3차원 오브젝트는 텍스처와 결합 될 때 더욱 현실감 있게 된다. 텍스처란 마치
* 벽지 같은 것으로, 적당하게 늘이거나 줄여서 면에 붙이게 된다. 일반적으로
* 텍스처는 이미지 파일(JPG, BMP, TGA 등)을 D3DX 계열의 함수를
* 사용하여 읽어들인 후 사용하게 된다. 정정 버퍼와 마찬가지로 Lock(),
* Unlock() 함수를 사용하여 메모리에 직접 접근할 수도 있다. 이렇게 생성한
* 텍스처를 면에 붙이는 행위를 텍스처 맵핑이라고 한다.
*
* 텍스처는 기하 정보와 연결되기 위해서 텍스처 좌표계를 갖게 되는데, 각각의
* 정점은 이러한 텍스처 좌표를 포함하고 있어야 한다. 일반적으로는 (u, v)
* 좌표계를 사용하고 u, v의 값은 0.0 ~ 1.0 사이의 값이다. 텍스처 좌표는
* 최초에 설정될 수도 있지만, 실시간으로 직접 계산하여 더 다양한 효과를 낼
* 수도 있다.(mirror, sphere 맵핑 등).
*------------------------------------------------------------------------------*/
#include <windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
/// SHOW_HOW_TO_USE_TCI 가 선언된 것과 선언되지 않은 것의 컴파일 결과를 반드시 비교해 보자.
/// #define SHOW_HOW_TO_USE_TCI
/// 전역변수
LPDIRECT3D9 g_pD3D = NULL; /// D3D 디바이스를 생성할 D3D 객체 변수
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; /// 랜더링에 사용될 D3D 디바이스
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; /// 정점을 보관할 정점버퍼
LPDIRECT3DTEXTURE9 g_pTexture = NULL; /// 텍스처 정보
/// 사용자 정점을 정의할 구조체
/// 텍스처 좌표가 추가되었다는 것을 알 수 있다.
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; /// 3차원 좌표
D3DCOLOR color; /// 색깔
#ifndef SHOW_HOW_TO_USE_TCI
FLOAT tu, tv; /// 텍스처 좌표
#endif
};
/// 사용자 정점 구조체에 관한 정보를 나타내는 FVF 값
#ifdef SHOW_HOW_TO_USE_TCI
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
#else
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
#endif
/// Direct3D 초기화
HRESULT InitD3D(HWND hWnd)
{
/// 디바이스를 생성하기 위한 D3D 객체 생성
if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
return E_FAIL;
/// 디바이스를 생성할 구조체
/// 복잡한 오브젝트를 그릴 것이므로 이 번에는 Z 버퍼가 필요하다.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
/// 디바이스 생성
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice)))
{
return E_FAIL;
}
/// 컬렁 기능을 끈다.
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
/// 조명 기능을 끈다
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
/// Z 버퍼 기능을 켠다.
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
return S_OK;
}
/// 기하정보 초기화
/// 정점 버퍼와 텍스처 생성
HRESULT InitGeometry()
{
/// D3DX 계열 함수를 사용하여 파일로부터 텍스처 생성(banana.bmp)
if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, "banana.bmp", &g_pTexture)))
{
/// 현재 폴더에 파일이 없으면 상위 폴더 검색
if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, "..banana.bmp", &g_pTexture)))
{
/// 텍스처 생성 실패
MessageBox(NULL, "Could not find banana.bmp", "Textures.exe", MB_OK);
return E_FAIL;
}
}
/// 정점 버퍼 생성
if(FAILED(g_pd3dDevice->CreateVertexBuffer(50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL)))
{
return E_FAIL;
}
/// 정점 버퍼를 값으로 채운다
/// 텍스처의 u, v 좌표값을 0.0 ~ 1.0 사이의 값으로 채워넣고 있다.
CUSTOMVERTEX *pVertices;
if(FAILED(g_pVB->Lock(0, 0, (void **)&pVertices, 0)))
return E_FAIL;
for(DWORD i=0; i<50; ++i)
{
FLOAT theta = (2*D3DX_PI*i)/(50-1);
pVertices[2*i+0].position = D3DXVECTOR3(sinf(theta), -1.0f, cosf(theta));
pVertices[2*i+0].color = 0xffffffff;
#ifndef SHOW_HOW_TO_USE_TCI
/// SHOW_HOW_TO_USE_TCI가 선언되어 있으면 텍스처 좌표를 생성하지 않는다.
pVertices[2*i+0].tu = ((FLOAT)i)/(50-1); /// 텍스처의 u좌표 0/49, 1/49, 2/49 ... 49/49 (즉 0.0 ~ 1.0)
pVertices[2*i+0].tv = 1.0f; /// 텍스처의 v좌표 1.0
#endif
pVertices[2*i+1].position = D3DXVECTOR3(sinf(theta), 1.0f, cosf(theta));
pVertices[2*i+1].color = 0xff808080;
#ifndef SHOW_HOW_TO_USE_TCI
/// SHOW_HOW_TO_USE_TCI가 선언도어 있으면 텍스처 좌표를 생성하지 않는다.
pVertices[2*i+1].tu = ((FLOAT)i)/(50-1); /// 텍스처의 u좌표 0/49, 1/49, 2/49 ... 49/49 (즉 0.0 ~ 1.0)
pVertices[2*i+1].tv = 0.0f; /// 텍스처의 v좌표 0.0
#endif
}
g_pVB->Unlock();
return S_OK;
}
/// 광원 설정
VOID SetupLights()
{
/// 재질 설정
/// 재질은 디바이스에 단 하나만 설정될 수 있다.
D3DMATERIAL9 mtrl;
ZeroMemory(&mtrl, sizeof(D3DMATERIAL9));
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial(&mtrl);
/// 광원 설정
D3DXVECTOR3 vecDir;
/// 방향성 광원(directional light)이 향할 빛의 방향
D3DLIGHT9 light;
/// 광원 구조체
ZeroMemory(&light, sizeof(D3DLIGHT9)); /// 구조체를 0으로 지운다
light.Type = D3DLIGHT_DIRECTIONAL; /// 광원의 종류(점 광원, 방향성 광원, 점적 광원)
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
vecDir = D3DXVECTOR3(cosf(timeGetTime()/350.0f), 1.0f, sinf(timeGetTime()/350.0f)); /// 광원의 방향
D3DXVec3Normalize((D3DXVECTOR3 *)&light.Direction, &vecDir); /// 광원의 방향을 단위 벡터로 만든다.
light.Range = 1000.0f; /// 광원이 다다를 수 있는 최대 거리
g_pd3dDevice->SetLight(0, &light); /// 디바이스에 0번 광원 설치
g_pd3dDevice->LightEnable(0, TRUE); /// 0번 광원을 켠다
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE); /// 광원 설정을 켠다
g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0x00202020); /// 환경 광원(ambient light)의 값 설정
}
/// 초기화된 객체들 소거
VOID Cleanup()
{
if(g_pTexture != NULL)
g_pTexture->Release();
if(g_pVB != NULL)
g_pVB->Release();
if(g_pd3dDevice != NULL)
g_pd3dDevice->Release();
if(g_pD3D != NULL)
g_pD3D->Release();
}
/// 행렬설정
VOID SetupMatrices()
{
/// 월드 행렬
D3DXMATRIXA16 matWorld;
D3DXMatrixIdentity(&matWorld);
D3DXMatrixRotationX(&matWorld, timeGetTime()/1000.0f);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
/// 뷰 행렬 설정
D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f);
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
/// 프로젝션 행렬 설정
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}
/// 화면 그리기
VOID Render()
{
/// 후면 버퍼와 Z 버퍼를 지운다.
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
/// 랜더링 시작
if(SUCCEEDED(g_pd3dDevice->BeginScene()))
{
/// 광원과 재질 설정
SetupLights();
/// 월드, 뷰, 프로젝션 행렬을 설정한다.
SetupMatrices();
/// 생성한 텍스처를 0번 텍스처 스테이지에 올린다.
/// 텍스처 스테이지는 여러 장의 텍스처와 색깔 정보를 섞어서 출력할 때 사용된다
/// 여기서는 텍스처의 색깔과 정점의 색깔 정보를 modulate 연산으로 섞어서 출력한다.
g_pd3dDevice->SetTexture(0, g_pTexture); /// 0번 스테이지에 텍스처 고정
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); /// MODULATE 연산으로 색깔을 섞음
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); /// 첫번째 섞을 색은 텍스처 색
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); /// 두번째 섞을 색은 정점 색
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); /// alpha 연산은 사용하지 않음
#ifdef SHOW_HOW_TO_USE_TCI
/// D3D의 텍스처 좌표 생성 기능을 사용하는 예를 보여준다.
/// 여기서는 카메라 좌표계에서의 정점 정보를 이용하여 텍스처 좌표를 생성한다.
/// 4x4 크기의 텍스처 변환 행렬을 텍스처 좌표 인덱스(TCI = Texture Coord Index) 전달 인자를
/// 사용하여 x, y, z TCI 좌표를 u, v 텍스처 좌표로 변환한다.
/// 사용한 것은 단순히 (-1.0 ~ +1.0) 값을 (0.0 ~ 1.0) 사이의 값으로 변환하는 행렬이다
/// 월드, 뷰, 프로젝션 변환을 거친 정점은 (-1.0 ~ +1.0) 사이의 값을 갖게 된다.
/// tu = 0.5x + 0.5
/// tv = -0.5y + 0.5
D3DXMATRIXA16 mat;
mat._11 = 0.25f; mat._12 = 0.00f; mat._13 = 0.00f; mat._14 = 0.00f;
mat._21 = 0.00f; mat._22 =-0.25f; mat._23 = 0.00f; mat._24 = 0.00f;
mat._31 = 0.00f; mat._32 = 0.00f; mat._33 = 1.00f; mat._34 = 0.00f;
mat._41 = 0.50f; mat._42 = 0.50f; mat._42 = 0.00f; mat._44 = 1.00f;
g_pd3dDevice->SetTransform(D3DTS_TEXTURE0, &mat); /// 텍스처 변환 행렬
g_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); /// 2차원 텍스처 사용
g_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION); /// 카메라 좌표계 변환
#endif
/// 정점 버퍼의 내용을 그린다.
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2*50-2);
/// 랜더링 종료
g_pd3dDevice->EndScene();
}
/// 후면 버퍼를 보이는 화면으로
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
/// 윈도우 프로시저
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/// 프로그램 시작점
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
/// 윈도우 클래스 등록
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"D3D Tutorial", NULL };
RegisterClassEx(&wc);
/// 윈도우 생성
HWND hWnd = CreateWindow("D3D Tutorial", "D3D Tutorial 05: Textures",
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL);
/// Direct3D 초기화
if(SUCCEEDED(InitD3D(hWnd)))
{
/// 기하 정보 초기화
if(SUCCEEDED(InitGeometry()))
{
/// 윈도우 출력
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
/// 메시지 루프
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
Render();
}
}
}
UnregisterClass("D3D Tutorial", wc.hInstance);
return 0;
}