'2008/07'에 해당되는 글 6건

  1. 2008/07/08 [D3DX] 높이맵 완성! (3)
  2. 2008/07/08 [D3DX] 맵 타일 완성!
  3. 2008/07/08 [D3DX] ID3DXBuffer
  4. 2008/07/07 [D3DX] 서브셋의 개념
  5. 2008/07/03 메모리 접근위반에 관해
  6. 2008/07/02 [오늘의 영단어]adjacent
2008/07/08 21:39

[D3DX] 높이맵 완성!

사용자 삽입 이미지

::  높이맵을 적용하여 1089개의 버텍스가 렌더링된 모습

사용자 삽입 이미지



:: 높이맵정보를 가지고 있는 이미지 파일(웹에올리기 위해 jpg로 확장자 변환하였다.)



먼저 33 * 33 타일을 만들었다

버텍스수는 33 * 33 = 1089가 되므로 픽셀수도 1089개 되어야함..

33 * 33 짜리 이미지는 포토샵에서 필터 - 렌더 - Difference Clouds 을 적용하여 만들었다.

이미지 - 적용 에서 그레이스케일로한후 save as 에서 .raw 확장자로 저장하게되면

한 픽셀당 8 비트가 할당된 이미지가 만들어지게된다(총 1089바이트)

색상이 흰색에 가까울수록 255에 가깝고 검은색에 가까울수록 0에 가깝다

이제, 이 픽셀들을 버텍스들과 매핑시킬때 버텍스의 y 좌표값에 이 바이트값을 넣어주면 높이가 표현된다.

맵이미지 파일을 읽어올때는 fopen() 과 fscanf() 를 사용해서 읽었다.

읽은후에는 버텍스버퍼 락을걸고 1089 번 루프를 돌면서 각 버텍스의 y성분만 건드려주면된다.

제법 간지나게 나온듯해서 뿌듯하다 -_-흐흐..

.. 그리고 몇가지 이슈사항..

1. D3DXCreateVertexBuffer9 로 버텍스 버퍼를 생성할때 D3DUSAGE 인자를 넣어야하는데..
높이맵처럼 버텍스의 특정 성분(y좌표)만 수정이 빈번하게 이루어진다면 어떤 플래그를 넣어야할까..
D3DUSAGE_WRITEONLY, D3DUSAGE_DYNAMIC(이걸로 해봤더니 버텍스버퍼에 쓰기할때 에러난다), 등등등..
플래그가 여러개가 있는데.. 뭘쓰는게 가장 최적화에좋을지..

2. 1바이트는 0 부터 255까지 나타낼수있는데 이 값을 그대로 버텍스의 Y성분에 적용해버리면 안되고
0.03 정도를 곱해서 전체적인 수치를 좀 낮춰줘야한다.. 왜냐하면.. 버텍스 간의 간격이 1로되어있는데
높이가 255면 아예 화면에 보이지도 않을정도로 커져버리기때문..
이올린에 북마크하기(0) 이올린에 추천하기(0)
Trackback 0 Comment 3
2008/07/08 15:44

[D3DX] 맵 타일 완성!

사용자 삽입 이미지

3D 세계의 맵을 구성하는 가장 기본적인 단위인 "타일" 이다.
아무리 거대한 맵이라도 이 타일이 합쳐져서 큰 맵하나가 되는것이다.
이제 여기에 Y (높이맵) 값만 적용해주면 그럴싸한 지형이 완성될것이다.!!

이 타일의 버텍스버퍼와 인덱스버퍼를 만드는 코드는 다음과 같이작성했다.

void Cdx3dView::initPlane()
{
 int width = 15; // 가로 버텍스수 15개
 int height = 15; //세로 버텍스수 15개
 int total = width*height; // 총 버텍스수
 float gap = 1.0f; //버텍스 간의 거리
 
 PVertex arrTemp[225];
 for(int i=0;i<width;i++) // 행
 {
  for(int j=0;j<width;j++) // 열
  {
   arrTemp[ j + i*width ].position = D3DXVECTOR3(gap*(float)j, 0.0f, gap*(float)i);  
  }
 }
 void *pTemp;

 m_pd3dDevice->CreateVertexBuffer(sizeof(PVertex)*total, 0, PVertex::FVF, D3DPOOL_MANAGED, &planeVB, 0);
 planeVB->Lock(0, sizeof(PVertex)*total, (void**)&pTemp, 0);
 memcpy(pTemp, arrTemp, sizeof(arrTemp));
 planeVB->Unlock();

 int numPolygon = (width -1) * (width -1) * 2;
 PIndex arrTemp2[392]; // 폴리곤 갯수만큼 인덱스 생성.
 int cntPolygon = 0;
 for(int i=0;i<width-1;i++)
 {
  if(cntPolygon >= numPolygon){ break; }

  for(int j=0;j<width-1;j++)
  {
   //하단 폴리곤
   arrTemp2[cntPolygon].a = i*width + j;
   arrTemp2[cntPolygon].b = i*width + (j+1);
   arrTemp2[cntPolygon].c = (i+1)*width + (j+1);
   cntPolygon++;

   //상단 폴리곤
   arrTemp2[cntPolygon].a = i*width + j;
   arrTemp2[cntPolygon].b = (i+1) * width + j;
   arrTemp2[cntPolygon].c = (i+1) * width + (j+1);
   cntPolygon++;
  }
 }

 m_pd3dDevice->CreateIndexBuffer(sizeof(PIndex)*numPolygon, 0, D3DFMT_INDEX32, D3DPOOL_MANAGED, &planeIB, 0);
 void *pIB;
 planeIB->Lock(0, sizeof(arrTemp2), (void **)&pIB, 0);
 memcpy(pIB, arrTemp2, sizeof(arrTemp2));
 planeIB->Unlock();
}

지금 이걸보면 타일의 중심이 3d 좌표계의 중심과 일치하지않는데.. 이건 좋은방법이 아닌것같다

타일의 중심과 3d 좌표계의 중심(원점)이 일치하게 하는게 좋을것같다

어차피 이 타일이라는것은 월드에서 반복적으로 그려져야 하므로.. 원점을 중심으로 하는 타일을 만들어서

이것을 재활용 하는 방식이 될것이다.. 즉 이 원점을 중심으로 하는 타일이 맵의 "템플릿"(틀) 이 될것이다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
Trackback 0 Comment 0
2008/07/08 11:16

[D3DX] ID3DXBuffer

D3DXLoadMeshFromX(....)를 호출하면 여러가지 정보를 프로그래머에게 넘겨주는데
이때 사용하는것이 ID3DXBuffer 이다

x파일로부터 메쉬를 읽어들일때, 그 메쉬의 메터리얼정보나 인접삼각형 정보까지 넘어오는데 이
정보들이 ID3DXBuffer 로 넘어온다.
ID3DXBuffer에 속한 버퍼의 타입이 결정되어있지 않으므로 명시적으로 타입을 정해야한다

받아올때 다음과같이 받아오면된다

매터리얼 정보를 받아온다고할때

ID3DXBuffer *buffer;
D3DXLoadMeshFromX( , , , ,&buffer , ) //다른 인수에대한 설명은 생략.
D3DXMATERIAL *mtrls = (D3DXMATERIAL *)(buffer -> GetBufferPointer());
mtrls[0].MatD3D // D3DMATERIAL9 구조체에 접근
mtrsl[0].pTextureFileName // 텍스쳐파일명(문자열)에 접근

이렇게 하면된다.

ID3DXBuffer 의 GetBufferPointer() 메서드는 ID3DXBuffer 가 관리하고있는 버퍼의 첫번째 메모리 블록주소를 리턴한다. 이것을 D3DXMATERIAL * 로 형변환을 하게되면 버퍼(배열)에 접근할때 오프셋이 달라지는효과가 나는것이다 D3DXMATERIAL 의 크기를 72바이트라고 가정할때, mtrls[0], mtrls[1] 둘의 메모리 블락수 차이는 72 가 되는 것이다. 즉 mtrls[1] 은 mtrls[0] 이 존재하는 메모리보다 72 블락 뒤에 있다는것이다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
Trackback 0 Comment 0
2008/07/07 17:58

[D3DX] 서브셋의 개념

하나의 메쉬에는 여러개의 서브셋이 존재할 수 있다.
서브셋이라는 개념이 필요한 이유가뭘까?
집이라는 오브젝트가 있다고해보자. 이 집은 지붕, 창문, 벽 으로 이루어져있다. 그런데 지붕, 창문, 벽의 재질이 모두 동일할까?  동일하지않다. 그래서 서브셋이라는 개념이 존재하는것이다. 집이라는 메쉬하나를 3개의 서브셋으로 분리해야만 각각의 메터리얼(재질)을 분리하여 적용할수있게된다.

텍스쳐를 적용할때도 마찬가지이다. 텍스쳐도 사실 개념적으로 메터리얼이기때문에 다이렉트X 에서
다음과같은 구조체를 만들어놓은거라고 생각한다.

D3DXMATERIAL

이 구조체를 까보면

두개의 속성이 있다

MatD3D : D3DMATERIAL9 구조체와 동일한 구조를 가진 구조체이다.
              Ambient, Diffuse, Specular, Emissive, Power 의 속성을 가졌다.

pTextureFileName : 문자열이며 텍스쳐 이미지의 파일명을 나타낸다.

x파일(맥스에서 작업한)을 읽어올때 D3DXMATERIAL 타입의 배열을 받아올수있는데,(매터리얼 버퍼라고 한다)
이 배열의 길이만큼 for문을 돌려서 메쉬를 그리면 된다.

코드로 간략하게 나타내보자.

D3DXMATERIAL materials[3]; //길이 3의 메터리얼 버퍼가 존재한다고 가정.

for(int i=0;i<3;i++){
      device -> SetMaterial(materials[i].MatD3D);
      // materials[i].pTextureFileName 을 참조하여 텍스쳐 객체(ID3DXTexture 였나?) 생성
     device -> SetTexture(....);
     mesh -> DrawSubset(i);
}

이 모든 설명을 2줄로 요약하면..

메터리얼과 서브셋은 1:1 대응관계이다.
즉, 메터리얼 1개에 대응되는 서브셋은 1개 !!! , 서브셋 1개에 대응되는 메터리얼도 1개 !!!

이올린에 북마크하기(0) 이올린에 추천하기(0)
Trackback 0 Comment 0
2008/07/03 11:39

메모리 접근위반에 관해

지식인 QnA 펌

질문

decoding.exe의 0x00413f9d에 처리되지 않은 예외가 있습니다. 0xC0000005: 0x00000000 위치를 기록하는 동안 액세스 위반이 발생했습니다. 엑세스 위반이라는 것으로 실행이 안되는데요.

0x00413f9d 라는 부분은 어떻게 해석을 해야 할지와 엑세스 위반이라는 것은 무엇인지

답변 부탁드리겠습니다~(__)


답변

엑세스 위반(Access Violation)은, 프로세스가 접근할 권한이 없는 메모리 영역에 접근하고자 했을 때 발생합니다.


윈도우는 메모리의 모든 영역을 가상메모리 페이지 단위로 관리하는데, 이 메모리 영역마다 접근 권한을 설정합니다. 이 권한은 프로세스가 가진 속성별로 관리됩니다. 크게 사용자가 만든 사용자 프로세스와, 윈도우 시스템에서 돌리는 커널 프로세스로 구분할 수 있죠. 윈도우에서 관리하는 메모리는 커널에서만 읽고 쓸수 있는 영억, 커널에서만 읽을 수 있는 영억,  사용자프로세스에서도 읽을 수 있는 영역, 사용자 프로세스가 읽고 쓸 수 있는 영역 등으로, 가상메모리 페이지에 권한이 설정되어 있습니다.

따라서 적절한 권한이 없는 프로세스가 제한된 메모리 영역에 읽고 쓰기를 시도할 때 엑세스 위반이 발생합니다. 대표적인 예로 "0xC0000005: 0x00000000 위치를 기록하는 동안 엑세스 위반이 발생했습니다"라는 예외는 0x00000000 번지, 즉 널 포인터에 대하여 쓰기를 시도했다는 뜻이죠. 0x00000000번지로 시작하는 메모리 영역은 유저 프로세스에 대해서는 읽기/쓰기가 금지된 영역입니다. 시스템 운영에 중요한 정보가 기록되어 있기 때문이죠. 따라서 사용자가 만든 프로그램이 이 위치를 접근하고자 하는 것은 이와 같은 에러를 냅니다.

에러 메시지에서, "decoding.exe의 0x00413f9d에 처리되지 않은 예외가 있습니다. 0xC0000005: 0x00000000 위치를 기록하는 동안 액세스 위반이 발생했습니다."의 0x00413f9d는, 0x00000000위치를 접근하고자 하는 명령이 수행된, 명령이 저장된 번지수입니다. 디버깅할 때 해당 번지수의 명령이 무엇인가를 살펴보면 비교적 헤메지 않고 버그를 잡을 수 있습니다.


답변

이런 경우는 대부분..

메모리 할당이 되지 않은 포인터(NULL Pointer)에 값을 넣었거나..

할당치를 초과하여 데이터가 입력되었을 때입니다..


답변

0x00413f9d 는 decoding.exe 이란 프로그램의 code 영역 주소입니다.

즉 decoding.exe의 0x00413f9d 주소에서 예외처리가 발생했다는것입니다.

프로그램은 대부분 0x00400000이 시작번지이므로

offset 0x00013f9d에서 0xc0000005 에러가 발생했다는것입니다.


답변

0x00413f9d는 메모리의 주소를 말하는 것으로, 동적 메모리를 할당하지 않았거나

할당항 메모리를 넘어서 접근 할 경우에 이러한 에러가 나게 됩니다.


int *temp;

temp[0] = 10; // 메모리 에러(할당하지 않고 사용한 경우)


int *temp1;

temp1 = new int [10];

temp1[15] = 10; //메모리 에러(할당은 하였지만 할당항 메모리를 넘어서 사용한 경우

 
이올린에 북마크하기(0) 이올린에 추천하기(0)
Trackback 0 Comment 0
2008/07/02 14:54

[오늘의 영단어]adjacent

adjacent [어드제이슨트]
이웃의

adjacency[어드제이선시]
이웃
인접물
이올린에 북마크하기(0) 이올린에 추천하기(0)
Trackback 0 Comment 0