반응형

ComPtr com 객체들을 받아주는 스마트포인터 레퍼런스카운트가 0 이 될때 삭제된다

 

IID_PPV_ARGS

id 와 포인터를 만들어내는 define

위 함수가 IID_PPV_ARGS 를 받고 있는데 이것은 id 와 이중 포인터를 받고 있는 인자임을 알수 있고 IID_PPV_ARGS는 두개의인자를 넘겨주기 수월하게 만드는 define 이다

 

 

IDXGIFactory 디바이스 출력과 관련된 부분들 ex 스왑체인

 

DX12 에선 View ==  Descriptor 과 같은 의미로 통용된다

 

ID3D12DesecriptorHeap 디스크립터 힙 

 

D3D12_CPU_DESCRIPTOR_HANDLE 리소스 버퍼의 정보를 담고 있는 핸들(리소스를 gpu 에 알려주기 위한 리소스 주소 등을 담고 있음)

 

 

 

 

반응형
반응형

 

메쉬는 같은데 데이터 값만 다른 인스턴싱의 예시 이미지들..

 

 

 

 

 

https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-drawindexedinstanced

 

ID3D11DeviceContext::D rawIndexedInstanced(d3d11.h) - Win32 apps

인덱싱된 인스턴스화된 기본 형식을 그립니다. (ID3D11DeviceContext.DrawIndexedInstanced)

learn.microsoft.com

 

 

CPU 단에서 위치등을 지정하여 gpu 에 인스턴싱을 하기 위한 방법으로 다음의 것들을 쓸 수 있다

IASetVertexBuffers

- 물체의 정점의 구조세팅을 말함, 각 물체의 위치정보들을 넘겨주게 됨

 

즉 하나의 오브젝트를 여러 위치에 대해 여러번 그리는것

 

  1. 한번에 그릴 여러 위치에 대한 데이터를 CPU 단에서 모아서GPU 에 한번에 보낸다
  2. GPU 에 넘겨줄 인스턴스 파라미들은 예를 들어 월드, 뷰, 투영행렬 등의 정보를 넘길 수 있다
  3. 리소스 버퍼 또한 한번에 데이터를 묶어 보낼 만큼의 양을 확보한다
  4.  

정점 셰이더에서 입력으로 사용될 정보들이 추가로 있는 걸 알 수 있자 world, MV, MVP

보통 월드, 카메라, 투영을 전역으로 넘겨 받는데

 

위 VS_IN 에서 인스턴싱이 꼭 이런 데이터만 넘어오는 것은 아니지만 인스턴싱시 VS 에서도 데이터를 받아서 오브젝트마다 위치를 다르게 처리 할 수 있는 예시로 볼 수 있다 ( 오브젝트 메시는 동일하지만)

다시 말해 오브젝트마다 최소한의 다른 데이터만 넘겨 주어 렌더링 한다는 것이다

 

뭉처서 넘기는 만큼 드로우 콜 횟수가 줄어들게 됨으로 더 빠른 성능을 보인다

 

파티클 같은경우 최소한의 정점만 (보통 정점 1개) 만 통과 시켜 지오메트리 셰이더에서 파티클이 그려져야 하는경우

Plane 을 마들어 파티킬을 그려 인스턴싱의 효과를 더욱 극대화 할 수 있다

https://3dmpengines.tistory.com/2317

 

성능은 1.5~2배 이상의 성능 향상을볼 수 있다( 상황에 따라 다름)

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

뒤의 인자가 인스턴싱에 대한 처리의 개수를 얘기하는것으로 정점셰이더에서는 한번만 처리하고

인스턴싱 개수만큰 파이프라인에서 정점셰이더이후의 과정을 개수만큼 반복하게 되어 cpu 에서 gpu 로의 전송 과정을 아낄 수 있다

각 인스턴싱된 오브젝트들은 SV_InstanceID 로 구분할 수 있다
 
 

 

 
파티클들의 위치나 방향을 cpu 에서 gpu 로 넘겨주는게 아니라 gpu 내부에서 SturcturedBuffer 를gpu 쪽에 만들어 놓으면 gpu 내에서 현재 파티클의 정보를 g_data 에 넣고 이것에 대한 움직이는 정보를 RWStructuredBuffer 에다가 기록을 하여 파티클을 움직이도록 처리 할수 있다, GPU 내에서.
[t9 는 t 는 텍스처 같은 형태로 자료의 크기가 상수버퍼 처럼 정해져 있지 않는 것을 사용한다는 것 또한 알 수 있다]

 

그리고 물체들의 위치는 이전 단계인 Compute Shader 에서 위치를 먼저 계산해 놓게 된다

 

 

 

그려질 필요가 없다면 지오메트리 셰이더에서 파티클을 그리지 않는다

GS 는 도형 정보를 수정 할수 있따, 추가 및 제거

최적화를 위해 정점 하나만 받아서 정점이 살아 있지 않다면 정점을 더이상(메시를) 그리지 않는다
그려질 필요가 없다면 모든 정점을 받을 필요가 없기 때문

outputSteam 은 정점을 생성 할거라면 이곳에 정점들을 추가해 이 정점에 대한 메시를 그리게 된다

즉 outputSteam 이것이 비어져 넘겨지게 되면 아무것도 그리지 않는다는것

 

VIew space 주석이 있는 곳이 정점을 뷰시점에서 사각형을 만들어 outputSteam 에 추가해 사각형을 만들고 있다는 것을 알 수 있다

 

이렇게 처리하면 CPU 와 GPU 의 병복 현상을 많이 줄일 수 있어서 성능향상이 될 수있다

 

 

전체적인 순서를 컴퓨트 셰이더를 통하여 위치나 방향 생명주기를 먼저 계산한다음 이 정보를 GPU 배열에 저장해 놓고

이 정보를 그대로 정점셰이더와 지오메트리 셰이더를 지나면서 파티클을 그리는 순서이다

반응형
반응형

흔히 쓰이는 렌더링 효과 중에는 한 단계에서 GPU가 자원 R에 자료를 기록하고, 이후의 한 단계에서 그 자원 R의 자료를 읽어서 사용하는 식으로 구현하는 것들이 많다. 그런데 GPU가 자원에 자료를 다 기록하지 않았거나 기록을 아예 시작하지도 않은 상태에서 자원의 자료를 읽으려 하면 문제가 생긴다. 이를 자원 위험 상황(Resource hazard)이라고 부른다.

 

이 문제를 해결하기 위해, Direct3D는 자원들에게 상태를 부여한다. 새로 생성된 자원은 기본 상태(default state)로 시작한다. 임의의 상태 전이를 Direct3D에게 '보고'하는 것은 전적으로 응용 프로그램의 몫이다. 

 

여러 리소스 상태들

이 덕분에, GPU는 상태를 전이하고 자원 위험 상황을 방지하는 데 필요한 일들을 자유로이 진행할 수 있다. 예를 들어 텍

응용 프로그램이 상태 전이를 Direct3D에게 보고함으로써, GPU는 자원 위험을 피하는 데 필요한 조치를 할 수 있다.(이를테면 모든 쓰기 연산이 완료되길 기다린 후에 자원 읽기를 시도하는 등)

 

상태 전이를 보고하는 부담을 프로그래머에게 부여한 것은 성능 때문이다. 응용 프로그램 개발자는 그러한 전이들이 언제 일어나는지 미리 알고 있다. 만일 이러한 전이를 자동으로 추적하게 한다면 성능에 부담이 생긴다.

 

자원 상태 전이는 전이 자원 장벽(Transition resource barrier)들의 배열을 설정해서 지정한다. 배열을 사용하는 덕분에, 한 번의 API 호출로 여러 개의 자원을 전이할 수 있다. 코드에서 자원 장벽은 D3D12_RESOURCE_BARRIER_DESC 구조체로 서술된다. 

 

다음 메서드를 호출하여 위 구조체를 사용한 자원 장벽을 설정할 수 있다.

 

다음은 호출 예를 보여주는 코드이다.

mCommandList->ResourceBarrier(1, 
&CD3DX12_RESOURCE_BARRIER::Transition(
CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET));

이 코드는 화면에 표시할 이미지를 나타내는 텍스처 자원을 제시 상태(Presentation state)에서 렌더 대상 상태로 전이한다. 자원 장벽이 명령 목록에 추가됨을 주목하기 바란다. 전이 자원 방벽이라는 것을, GPU에게 자원의 상태가 전이됨을 알려주는 하나의 명령이라고 생각하기 바란다. 명령을 통해서 자원 상태 전이를 알려주는 덕분에, GPU는 이후의 명령들을 실행할 때 자원 위험 상황을 피하는 데 필요한 단계들을 밟을 수 있다. 

 

 

ref : https://lipcoder.tistory.com/60

반응형
반응형

루트 서명 예제

 

다음 섹션에서는 비어 있음부터 완전 가득 참까지 복잡성이 다양한 루트 서명을 보여 줍니다.

빈 루트 서명

빈 루트 서명은 별로 유용하지 않을 수 있지만, 입력 어셈블러만 사용하는 간단한 렌더링 패스와 설명자에 액세스하지 않는 최소 꼭짓점 및 픽셀 셰이더에 사용할 수 있습니다. 또한 혼합 단계, 렌더링 대상 및 깊이 스텐실 단계에서도 빈 루트 서명을 사용할 수 있습니다.

단일 상수

API 바인딩 슬롯에서는 이 매개 변수의 루트 인수가 명령 목록 기록 시에 바인딩됩니다. API 바인딩 슬롯 수는 루트 서명의 매개 변수 순서에 따라 암시적입니다(첫 번째는 항상 0). HLSL 바인딩 슬롯에서 셰이더는 루트 매개 변수가 표시되는 것을 알 수 있습니다. 형식(위 예제의 "uint")은 하드웨어에 알려지지 않으며 이미지의 주석으로만 표시됩니다. 하드웨어는 콘텐츠로 단일 DWORD만 알 수 있습니다.

명령 목록 기록 시간에 상수를 바인딩하려면 다음과 비슷한 명령을 사용할 수 있습니다.

syntax복사
pCmdList->SetComputeRoot32BitConstant(0,seed); // 0 is the parameter index, seed is used by the shaders

루트 상수 버퍼 뷰 추가

이 예제에서는 두 개의 루트 상수와 DWORD 슬롯 2개에 상응하는 루트 CBV(상수 버퍼 뷰)를 보여 줍니다.

상수 버퍼 뷰를 바인딩하려면 다음과 같은 명령을 사용합니다. 첫 번째 매개 변수(2)는 이미지에 표시되는 슬롯입니다. 일반적으로 상수 배열이 설정된 후 셰이더의 b0에서 CBV로 사용할 수 있게 됩니다.

syntax복사
pCmdList->SetGraphicsRootConstantBufferView(2,GPUVAForCurrDynamicConstants);

설명자 테이블 바인딩

이 예제에서는 두 설명자 테이블의 사용을 보여 줍니다. 하나는 CBV_SRV_UAV 설명자 힙에서 실행 시 사용할 수 있는 5개의 설명자 테이블을 선언하고 다른 하나는 샘플러 설명자 힙에서 실행 시 표시될 두 설명자의 테이블을 선언합니다.

명령 목록을 기록할 때 설명자 테이블을 바인딩하려면

syntax복사
pCmdList->SetComputeRootDescriptorTable(1, handleToCurrentMaterialDataInHeap);
pCmdList->SetComputeRootDescriptorTable(2, handleToCurrentMaterialDataInSamplerHeap);

루트 서명의 또 다른 기능은 크기가 4개 DWORD인 float4 루트 상수입니다. 다음 명령은 4개 중에서 가운데에 있는 두 DWORD만 바인딩합니다.

syntax복사
pCmdList->SetComputeRoot32BitConstants(0,2,myFloat2Array,1);  // 2 constants starting at offset 1 (middle 2 values in float4)

좀 더 복잡한 루트 서명

이 예제에서는 대부분의 항목 형식을 갖는 조밀한 루트 서명을 보여 줍니다. 설명자 테이블 중 2개(슬롯 3 및 6)에는 바인딩되지 않은 크기 배열이 포함됩니다. 여기서는 애플리케이션이 힙의 유효한 설명자에만 연결해야 합니다. 바인딩되지 않은 배열 또는 아주 큰 배열에는 하드웨어 계층 2보다 높은 리소스 바인딩 지원이 필요합니다.

2개의 정적 샘플러(루트 서명 슬롯을 요구하지 않고 바인딩됨)가 있습니다.

슬롯 9에서 UAV u4 및 UAV u5는 동일한 설명자 테이블 오프셋에서 선언됩니다. 별칭이 지정된 설명자는 이렇게 사용되며, 메모리에 한 설명자가 HLSL 셰이더에서 u4 및 u5 둘 다로 표시됩니다. 이 경우 셰이더는 fxC의 D3D10_SHADER_RESOURCES_MAY_ALIAS 옵션 또는 /res_may_alias 옵션으로 컴파일되어야 합니다. 설명자에 별칭을 지정하면 셰이더를 변경하지 않고도 여러 바인딩 요소에 하나의 설명자를 바인딩할 수 있습니다.

스트리밍 셰이더 리소스 뷰

이 루트 서명은 모든 SRV가 하나의 큰 배열 내/외부로 스트리밍되는 시나리오를 보여 줍니다. 실행 시 설명자 테이블은 루트 서명이 설정될 때 한 번만 설정할 수 있습니다. 그러면 첫 번째 일부 루트 인수를 통해 공급되는 상수를 통해 배열로 인덱싱하여 모든 텍스처 읽기가 수행됩니다. 단일 설명자 힙만 필요하며, 텍스처가 사용 가능한 설명자 슬롯 내/외부로 스트리밍될 때만 업데이트됩니다.

큰 힙의 설명자 오프셋은 상수 버퍼 뷰의 상수를 사용하여 셰이더에서 식별됩니다. 예를 들어, 셰이더에 재료 ID가 지정되면 해당 상수를 사용하여 하나의 큰 배열로 인덱싱함으로써 필요한 설명자(필수 텍스처 참조)에 액세스할 수 있습니다.

이 시나리오에는 리소스 바인딩 계층이 2보다 큰 하드웨어가 필요합니다.

 

 

ref : https://docs.microsoft.com/ko-kr/windows/win32/direct3d12/example-root-signatures

반응형
반응형

DirectX SDK (June 2010) 을 Windows 7 에 설치하던 중에 Error Code S1023 이 뜹니다.

원인은 최신 버전의 Visual C++ 2010 X86/X64 Redistributable Package 가 설치되어서 발생되는 것입니다.

 

일단 이것들을 제어판에서 삭제합니다.

DOS 명령어에서 다음과 같이 입력해도 삭제됩니다.

MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}

 

그 다음에 DirectX SDK 를 설치합니다.

http://www.microsoft.com/en-us/download/details.aspx?id=6812

 

그 다음에 최신 버전의 Visual C++ 2010 X86/X64 Redistributable Package 를 설치합니다.

http://www.microsoft.com/ko-kr/download/details.aspx?id=26999

 

참고



ref DirectX SDK (June 2010) 설치할 때 Error Code S1023

출처: 
https://appmaid.tistory.com/11 [App Maid] https://appmaid.tistory.com/11

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

Dx12 기본지식 - 자원 상태 전이  (0) 2022.11.16
루트 서명 (Root Signature)  (0) 2022.09.04
키프레임 애니메이션  (0) 2016.08.06
밉맵 디테일 높이기  (0) 2013.06.10
Early Z  (0) 2013.06.08
반응형

키 프레임 애니메이션에 대한 쉬운 설명이 있어서 출처와 함께 소개합니다.

 

출처 <http://twinbraid.blogspot.kr/2016/01/blog-post_19.html>

 

 

 

애니메이션과 키프레임 용어

애니메이션은 움직이는 그림을 뜻하는데 그림이 살아 움직이는 건 아니고
여러장의 장면을 빠르게 보여줌으로써 움직이는 것처럼 보이게 한다
키 프레임의 경우 보통 중요한 컷을 말한다

애니메이션의 제작, 원화와 동화

애니메이션이 여러장의 그림을 나열하는 것은 알고 있을 것이다
그런데 그러한 그림을 노트에서 페이지 넘겨서 움직이는 졸라맨 그리듯이
무작정 순서대로 그리진 않는다
먼저 원화라고 Key Animation을 그린 후 그것을 연결하는 동화를 그린다
예를들어 공이 위에서 아래로 떨어지는 애니를 만든다면
원화가는 어디에서 공이 떨어질지에 대한 그림을 그리고
어느 바닥에 도착할지에 대한 그림을 그린다
그럼 총 두 장의 키 애니메이션이 만들어진다. 하지만 이 두 장으론 애니가 성립되지
않는다. 그것을 위해 동화맨들이 두 장을 바탕으로 중간에 연결되는 그림을 왕창
그리는 것이다.
만약 원화가가 한 장은 개를 그려놓고 한 장은 우주를 그려놓으면
동화맨으로썬 이 두 장 사이에 뭘 그리라는 건지 혼란에 빠질 것이다
그러므로 키 애니메이션은 거의 모든 중요정보를 담고있는
말 그대로 그 장면 장면의 키가 되어서 누가봐도 중간 장면을 예상할 수 있어야한다

키 프레임

애니메이션과 비교

3D 프로그램에서 동영상편집, 그리고 플래시에 이르기까지 키 프레임
거의 일상적 용어이며 위의 키 애니메이션 개념과 다르지 않다
프로그램상에서 원화가는 바로 당신을 뜻하며 동화가는 프로그램이다
예를들어 위의 공애니의 경우 공을 일정위치에 놓고 키 프레임을 하나 찍는다
그리고 또 다른 위치에 놓고 10초뒤 키 프레임을 하나 찍으면
그 중간 과정을 프로그램이 알아서 생성한다. 그럼으로써 애니메이션이 완성된다

컷 추가

프로그램상에서 타임라인의 기본은 노컷이다
완전 통짜로 되어 있어서 10초짜리 타임라인이라면 키 프레임이 들어가지 않는다면
한 장면을 10초간 보여줄 뿐이다. 여기서 키 프레임이 바로 컷의 역할을 한다
애니메이션이란게 성립할려면 최소한 2장면은 필요하다.
그래서 키 프레임이 반드시 2개 이상이 되었을때야 비로서 애니메이션이 성립하게 된다

속성

일반 애니메이션의 경우 움직임이 키의 요소지만
프로그램에선 변할 수 있는 것들은 모조리 키로 만들 수 있다
예를들면 불투명도에서 소리에 이르기까지 말이다
1초에서 불투명도를 100%로 놓은 키와 10초에서 불투명도를 0%로 놓은 키가 있다면
10초로 이르는 사이 서서히 투명해지는 애니메이션을 만들 수 있고
1초에서 볼륨을 0%로 해놓은 키와 10초에서 100%로 놓은 키가 있으면
볼륨이 서서히 커지는 효과의 애니메이션(?)을 만들 수 있는 것이다
이때 이것들은 하나의 키 프레임에서 처리하진 않고 속성들이 고유의 키 프레임을 갖는다
위와 같은 경우 키 프레임이 4개가 된다.
속성이 많으면 많을 수록 키 프레임 수도 팍팍 늘어나는데 사실 그렇게까지
많이 쓰진 않으며 각 키 프레임도 드래그로 조정 가능하게 하는 것은 기본이고
snap 기능, 복사 등등 최대한 노가다를 적게하도록 만들어져 있다. 그래도 노가다

그래프

키 프레임 자체는 잘 보인다. 그게 찍혀있으면 거기에 컷이 한장 있다는 소리고.
키 프레임을 클릭하면 수치창이 나와서 수치를 조정해줄 수 있다.
하지만 전체적인 움직임은 좀 알기 어려운 점이 있다
그래서 그러한 움직임을 직관적으로 보여주자고해서 나온 것이 그래프이다
키 프레임
와… 직관적이네요????
처음보면 무슨 개풀씨나락 까먹는 직관이냐고 생각할지 모르겠지만
우리의 수학이 더러운 주입식이라 그렇지 실제 사용에서 그래프는 매우 편리한 도구다.
저것만 봐도 쪼금이라도 키 프레임 지식이있다면 바로 초록색 수직라인은 현재 타임이고
검은 네모들은 키 프레임이고 각각의 색색 곡선들은 저위의 사각형 상자에 나와있는
방향화살표랑 색깔이 매치되는 것을 알아볼 것이다
예를들면 파란색이 저 상자의 위쪽 화살표니까 10초에서는 -7쯤 위치에 있다가
100초에 다가설수록 곡선형으로 수치가 증가해 7에 다다른다
즉 상자가 10초에서 100초가 되면서 위로 천천히 오르다가 점점 빠르게 오르다가
마지막에 가서는 완만하게 오르게 되는 것을 그래프로 한눈에 알 수 있다
보통은 그러한 움직임을 알려면 직접 플레이 해보는 수밖에 없지만 이처럼 그래프는
어떻게 진행되는 지를 한장으로 보여주는데
반하지 않을 수가 없다
(참고로 본인은 수학은 잼병에 그래프는 인류의 적이라고 생각했던 사람이다 한국교육 ㅅㅂ)
왠만한 프로그램에서는 타임라인을 잘 뒤져보면 그래프를 보여주는 옵션이 있는데
거기에 익숙해지면 작업이 엄청 편해지게 되는 것은 말할 것도 없다

3D 애니메이션

본인은 3D 애니메이션이라 하면 엄청나다는 생각만 가지고 있었고
그 실체는 역시 엄청날 것이다 라고만 생각했다
즉, 엄청난 거라고 미리 겁먹고 생각할 의지가 생기지 않았다
사실 나랑 관계없는 세계니 관여할 생각도 없었고
근데 재수없게도 약간 관계가 생겼다
그래서 그 엄청난 세계에 발디뎠는데.. 알고보니 사실 똑같았다
한 장면과 다른 장면을 찍어놓으면 프로그램이 알아서 중간과정 만드는거
위랑 하나도 안다르다.
리깅과 핸들을 만들고 마지막에 애니를 재생하면서 간신히 알아낸거지만..ㅡ,.ㅡ;
단지 똑같긴 한데 보통 2D랑 쪼끔 다른건 원하는 장면을 위한 포즈를 취하게 하는게
여간 힘든게 아니였다는랑 그걸 위해서 리깅과 핸들 같은 생소한 개념이 들어가서
헷갈렸다는 것 정도다.

결론

결국 키 프레임을 만드는 것은 변화 전과 변화 후의 장면을 만드는 것이다
우린 작곡가 처럼 오선지에 음표를 넣듯이 타임라인에 키프레임을 넣어주면 된다
1초에 도를 넣고 10초에 솔을 넣으면 컴터가 알아서 도레미파솔 이라고 연주해주는 것이다
물론 레 미 파 솔도 직접 키프레임으로 찍어 넣을 수 있다. 노가다가 그렇게 하고 싶다면

여타 프로그래밍이 그렇듯이 본질은 사실 단순한데
그걸 편하게 한다고 덕지덕지 붙이고 보니 실체는 안보이고 복잡한 외부기능들만
보여서 어려워지는 것이다.
개념만 이해하고 나면 이제 어떤 프로그램이더라도 애니메이션을 만드는데
각 프로그램의 세세한 것들만 좀 다를 뿐이지 큰 장애는 없을 것이다

Written with StackEdit.

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

루트 서명 (Root Signature)  (0) 2022.09.04
DirectX SDK (June 2010) 설치 Error Code S1023  (0) 2019.07.25
밉맵 디테일 높이기  (0) 2013.06.10
Early Z  (0) 2013.06.08
Direct3D 9 에 래스터라이즈 규칙  (0) 2013.05.10
반응형

오홍~



http://kblog.popekim.com/2013/06/blurrymipmap.html



벌써 5년넘게 써오고 있는 방법인데 생각보다 모르시는 분들이 많은 것 같아 이방법을 공유합니다.

밉맵?

일단 밉맵이 뭔지는 다 아시리라 생각하고 굳이 밉맵에 대해서는 설명하지 않겠습니다.  모르시는 분들은 여길 참고하세요.

문제점 및 일반적인 해결책

밉맵을 사용하다보면 정말 카메라를 가까이 들이밀지 않는한 텍스처의 디테일이 흐릿해 보이는 경우가 흔히 발생합니다.  보통 다음과 같은 방법들로 해결합니다.

흔히 쓰는 해결법 1 - 텍스처 크기 늘리기

밉레벨이 낮아질수록 텍스처 크기가 절반씩 줄어드는 거니 젤 높은 디테일의 밉멥 텍스처크기를 크게 키워주면 그만큼 흐려지는 현상이 덜합니다. 하지만 메모리를 많이 잡아먹는다는 단점이 있어서 정 필요한 때만 제한적으로 사용하곤 합니다. (왜 흔히 라고 한거지 그럼 -_-)

흔히 쓰는 해결법 2 - 밉맵 바이어스 쓰기

이걸 고치기 위해 흔히 쓰는 해결법은 밉맵 bias를 조절하는 방법입니다. 샘플러스테이트에서 정해주는 방법도 있고 셰이더에서 해주는 법도 있습니다. 뭐든 나쁜 방법은 아니고 가장 널리 쓰는 방법인데 여러가지 단점이 있습니다


  1. 고디테일의 텍스처(크기가 큼)를 더 많이 쓰도록 bias를 주므로 텍스처 캐쉬의 성능저하 (그만큼 넣어야할 데이터가 많으니)
  2. 밉맵이 원래 해결하려고 하는 거리에 따른 애일리어싱 문제가 쉽게 더 생긴다.
  3. 모든 경우에 적당히 잘 동작하는 bias 값을 찾기가 쉽지 않다.

흔히 쓰는 해결법 3 - 밉맵 생성시 사용하는 필터 다르게 사용하기

보통 bilinear 필터를 사용해서 밉맵을 만드는게 일반적입니다. 그럼 그냥 주변에 있는 이웃 픽셀들 2x2개 모아다가 균등하게 혼합하는게 전부입니다. 이 외에 kaiser 필터 등을 사용하면 좀더 낫다고 해서 그렇게 하는 사람들을 봤지만... 개인적으로는 별 효과가 없다고 생각합니다.


제 해결법 - sharpening filter

생각보다 매우 간단합니다. 그냥 밉맵 텍스처에 sharpening 필터 한번 더 먹여주면 됩니다. -_- 사실 밉맵들이 흐릿해 보이는 이유가 bilinear 필터링만 쓰면 그냥 경계를 뭉게버린다는건데 여기다 sharpening 필터 한번 먹여주면 경계부분은 다시 적당히 또렷하게 살아나거든요... 

오프라인 프로세스라 게임성능에 지장도 없고... 흔히 쓰는 해결법 2에서 말씀드렸던 단점들도 없습니다.. 그냥 밉맵만드실때 이런순서로 만들어 주시면 됩니다.
  1. 밉맵 0으로부터 밉맵 1 생성 (bilinear filter)
  2. 밉맵 1에 sharpening filter 적용
  3. 2번 결과물로부터 밉맵 2 생성(bilinear filter)
  4. 밉맵 2에 sharpening filter 적용
  5. 밉맵 끝까지 만들때까지 반복...

이 방법을 대충 포토샵으로 흉내낸걸 보여드리면 대충 이렇습니다. 오른쪽이 제 방법입니다.
















반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

DirectX SDK (June 2010) 설치 Error Code S1023  (0) 2019.07.25
키프레임 애니메이션  (0) 2016.08.06
Early Z  (0) 2013.06.08
Direct3D 9 에 래스터라이즈 규칙  (0) 2013.05.10
x파일에 대한 pdf  (0) 2013.03.11
반응형

http://eppengine.com/zbxe/3103


early z test 는 pixel 단위의 culling 방식이다.

 

간단히 이야기 하면, 각 픽셀을 연산이 되기전에 깊이테스트를 통해서 보이지 않는 pixel 에 대한 연산은

 

적절히 skip 하기위한 pixel culling 방식이라고 이해하면 된다.

 

하지만 Pipe Line 단계에서 Z test 는 pixel shader (fragment shader) 다음에 이루어진다.

 

그렇다면, pipe 라인상에서는 z-test 가 pixel 연산 다음에 이루어 지는데, 어떻게 앞에서 처리 할 것 인가?

 

결론부터 이야기 하면 하드웨어 단계에서 지원이 되어야만 가능한 부분이다.

 

예를들어 Nvidia Geforce 8000 대의 gpu 의 경우 특정 상황에서는 자동적으로 early z 기능이 활성화 된다.

 

 

Use

 

다음의 순서를 따른다.

 

1. 컬러쓰기를 disable 하고 write depth 만 enable 한다.

(이럴경우 nvidia 의 fx 이상급 gpu 에서는 double speed z write 가 활성화 된다.)

 

2. depth 를 clear 하지 않은 상태에서 ( depth buffer 를 clear 하지 않는다는 의미 ) 정상적인 rendering 을 실시한다.

(이때 depth test 연산자를 equal 로 설정한다. )

 

3. 1번 단계에서 기록된 depth buffer 값은 2번 단계를 거치면서 깊이비교에서 실패한 pixel 들을 자동적으로 연산에서 제외 시키게 된다. 

( early z )

 

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

키프레임 애니메이션  (0) 2016.08.06
밉맵 디테일 높이기  (0) 2013.06.10
Direct3D 9 에 래스터라이즈 규칙  (0) 2013.05.10
x파일에 대한 pdf  (0) 2013.03.11
NormalMapGenerator  (0) 2013.02.23
반응형


http://blog.naver.com/sorkelf/40151293786


Direct3D 9 에 래스터라이즈 규칙


DirectX는 삼각형 폴리곤을 베이스로써 렌더링이 수행된다.

당연하겠지만 잘 생각해보면 다음과같은 변환이 필요하다는것을 알게 된다


삼각형 폴리곤의 각 버텍스는 부동소수점(float)로 표현된다. 소수점은 이론상으로는 연속된 값이다.

이 버텍스가 여러가지로 수치변환되어 최종적으로는 스크린 좌표로 변환된다.

 

이 스크린 좌표는 [ 정수 ]로, 스크린상의 점은 엄밀히 작은 정방형이다.

정수는 아는대로 불연속한 것이다.

연속이 어느새 불연속이 된것은 그다지 신경쓰지 않지만 실은 매우 중요한 것이다


연속한 폴리곤을 불연속적인 픽셀로 바꾸려면 몇가지 룰이 필요하다.

그 룰을 [ 레스터라이제이션 룰 (Rasterization Rule) ]이라고 한다. 

예를 들면 아래 폴리곤에 있는 3개의 버텍스의 스크린 위치가 결정됐다고 했을대 그 주위와 내부는 어떻게 칠해질까를 생각해본다



   변을 포함하고 있는 어떤 파란 색으로 칠해질까? 만일 전부 칠해지나? 면적이 넓으면 칠해지나?

이것들이 제대로 결정되어있지 않으면 외관이 완전히 변해버린다.


이것은 특히 스크린 픽셀을 의식한 렌더링( 2D의 HUD나 포스트 이펙트 렌더링 같은 것)

에 커다란 영향을 주게 된다


여기에서는 이렇게 평범할수도 있지만 중요한 래스터라이제이션 룰에 대해 설명하고자 한다. 

또한 언급이 없는 한 폴리곤은 스크린의 범위로 수치가 변환되고 있다고 한다. ( 단 소수점임)

또한 사각형들은 화면의 도트 그 자체이다




① 스크린 도트와 버텍스의 위치 관계


   폴리곤이 여러가지 변환을 거쳐 스크린의 범위와 같은 값이 됐다고 하자. 단 이 값은 부동소수점 그대로이다. 이때의 폴리곤의 소수점 값과 스크린의 도트는 다음과 같은 위치 관계가 된다


 

오렌지색 점이 폴리곤이 변환된 소수점 값이며, 빨간 숫자가 스크린좌표이다. (0이 기점인 것에 주의)

소수점의 정수값(3.0이라던지)이 도트 중앙에 있는것이 포인트이다.


 DirectX에서는 [ 오렌지색 점이 폴리곤내에 포함되어있다면 기본적으로 렌더링한다 ] 라는

룰이 적용되어 있다


[ 기본적 ]이란것은, 단지 이 룰만 적용하는 것은 문제가 있다는 것이다.

예를들면, 4X4의 작은 HUD를 표시하려고 할때의 이미지는 아래와 같다

이것을 위에있던 그림과 맞춰보자

잘 보면 가로 세로 5픽셀에 걸쳐져있다. 4X4로 할려고했더니 5X5?? 


또 하나 별도의 문제. DirectX의 폴리곤은 삼각 폴리곤이다. 

위의 사각 폴리곤을 삼각형으로 분할하면 어떻게 될까

  왼쪽 하단 폴리곤과 Right-Top 폴리곤의 경계선은 오렌지색의 점을 양쪽 모두 포함하고 있다.

라는 것은 이 곳은 2번 칠해진다 라는 것이 된다. 


포함하고 있는 부분을 단순히 칠한다라는 것만으로는 여러가지 문제가 생기게 되버린다는 것이다

여기서 DirectX나 각종 GUI계에서는 [ Top - Left Filling Convention ] 이라는 룰을 채택한다



② Top-Left Filling Convention


 ①에 있는 문제를 해결하기 위해 DirectX에서는 Top-Left Filling Convention 이라는 룰을 적용하고 있다. 이것은、「Top-Left 있는 도트는 채택, Right-Bottom에 있는 도트는 채택하지 않음」이라는 심플한 룰이다. 여기서 말하는 Left-Top과 Right-Bottom이란 무엇인가?


    우선 [ Left ] 이란 삼각 폴리곤의 변이 폴리곤의 중앙으로부터 봤을때 왼쪽에 있는 측면을 말한다.

[ Right ]는 그 반대이고, [ Top ]은 수평이며 중앙보다 위에있는 부분을 가리킨다. [ Bottom ]은 Top과 반대이다

 

 

   칠하려고했던 도트가 변에 대응(相当)하고 있는 경우, 그것이 Top-Left이면 채택, Right-Bottom이면 채택 하지 않는다. 이 룰을 위에서 봤던 사각 폴리곤에 적용하면 아래와 같이 된다

 

   파란색 셀은 왼쪽 하단의 폴리곤에 의해 칠해지는 곳이다. 이 폴리곤에는 왼쪽, 오른쪽, 하단이 있지만 그 가운데 오른쪽변과 아래쪽 변에 속해있는 셀은 칠하지 않는다.

따라서 대각선의 부분과 가장 아래에있는 부분은 색칠 되지 않는다.

 

오른쪽상단의 0,0 도트는 왼쪽 변과 오른쪽 변의 양쪽을 공유하고 있다.

이 경우 채택하지 않는다.


    한편 빨간 셀은 오른쪽 상단의 폴리곤에 의해 칠해지는 셀이다. 여기에는 Top, Left, Right 변이 있다.

오른쪽 변은 채택되지않기때문에 오른쪽 끝이 (4,4)도트가 칠해지지 않았고,  

왼쪽 변( 대각선을 말함) 은 칠해진다.

 

이것에 의해 Right-Bottom 폴리곤과의 경계선이 여러번 칠해지는 문제도 해결된다. 

사각형의 크기도 생각한대로 4X4이다

  

 기본적으로는 이 룰에 따라 칠해지나, 예외도 있다



③ Top-Left Filling Convention가 적용되지 않는 경우


 그런데 이 룰이 적용되지 않는 경우가 있다. 예를들면 아래와같은 경우이다:

 

방금전과 같은 크기의 사각 폴리곤이 조금 왼쪽 상단으로 이동했다.

이 경우 TLFC 룰(Top-Left Filling Convention)을 적용하면, 오른쪽이 불필요하게 비어있다.

DirectX는 이럴 경우 TLFC룰을 적용하지 않는다.

이것을 위에 그림에서 대각선의 크로스한 부분에서 판별한다


 이곳이 픽셀의 경계선에 들어있지 않은 경우등, 특정 조건을 만족할 경우, TLFC룰은 사용되지 않는다

이렇게 각 규칙에 따라 잘 움직이고 있으며 외관상으로 모순없는 렌더링이 가능한 것이다



④ 또 다른 문제「픽셀에서 벗어나는 문제」


 2D의 HUD등을 렌더링할때에는 가능하면 Dot by Dot 형태로 렌더링 하고 싶을 것이다.

(Dot by Dot:화면의 1도트에 텍스처 1픽셀이 렌더링 된 상태)

하지만 DirectX에서는 보이지 않는 룰에 의해 의도되지 않게 되는 경우가 있다


    매우 간단한 예로 재현해보자.

2X2의 텍스처가 있다고 했을대 이것과 같은 크기의 사각 폴리곤도 있다고 하자.

이것을 아래와 같이 스크린에 렌더링 한다고 하자

 

이때, 실제 화상은 어떻게 될까? 아마 이렇게 될것이다


 

뭔가 칙칙해졌다. 이것은 혼색(混色)이 되버렸기 때문이다. 왜 이렇게 된것일까? 

이것은 텍스처로부터 샘플링 하는 UV가 관계하고있다.


   래스터라이즈가 수행되면, 스크린의 유효 도트에 대해서 UV가 계산된다. 구체적으로는 각 도트의 중심점(오렌지색의 점)에 대응한 값이 보간되어 계산된다. UV를 적어보면 아래와 같이 된다

 


 

UV에 있는 색은 위의 그림과 같다. 각 UV 샘플링 점이 변 및 교점에 있는 것에 주목하도록.

 

이 경우 샘플러의 설정에 의한 것도 있지만, 주변의 색 정보를 활용해서 중간색이 나오게 된다.

그렇기 때문에 결과 화면같이 혼색된 색이 나와버리게 된다


  3D 모델을 렌더링 할때에는 애초에 Dot by Dot 가 되는것은 보통 없기 때문에, 이러한 것에 신경쓸 필요는 거의 없지만, 예를들어 포스트 이펙트를 셰이더에서 만들때 같은 경우에는 이 영향에 직격탄을 맞을 것이다.


  혼색되면 안되는 건 당연하다. 그럼 어떻게 막을까? 위의 그림에 답이 있지만 원래의 폴리곤의 좌표를 Top-Left로 0.5 이동시킨다. 그러면 원래의 색을 칠하고 싶은 위치와 폴리곤이 입혀지는 위치가 외관상 맞아 떨어진다



이 UV에서 샘플링 하면, 정확히 텍스처의 색이 반영된다.

원래의 폴리곤 좌표를 ( -0.5, -0.5) 오프셋 처리 하지 않으면 이론상 Dot by Dot가 되지 않는다.

또한, 이것은 원래 폴리곤 좌표가 정수가 아니면 성립하지 않기 때문에 주의 하도록..



⑤ 어디서-0.5를 이동 시킬 것인가?

 

   이론은 알았지만 어디서 -0.5를 이동시키면 될 것인가? 사각 폴리곤을 좌표변환이 끝난 버텍스에서 작성하고있는 사람이라면 직접 버텍스 좌표를 오프셋 처리를 하면 된다.

그렇지 않고 사각 폴리곤을 좌표변환이 끝난 버텍스를 사용하지 않고 3D 공간상의 폴리곤으로써 취급할 경우, 위치를 이동시킬 기회는 두번이 있는데....

   

    첫번째는 월드 행렬 변환이다. 이곳에 스크린에서 봤을때 (-0.5, -0.5)이동시키는 오프셋을 추가한다. 단 일반적으로 이건 꽤 어렵다.


   또 다른 방법은 셰이더 내에서 처리하는 것이다. 사각형 폴리곤 렌더링용 셰이더가 있다는 전제이지만, WVP행렬을 곱한 후의 버텍스에 대해서 직접 계산을 수행한다



 VS_OUT vs_main( VS_IN In )

{

    VS_OUT Out = (VS_OUT)0;

    Out.pos = mul( In.pos, WVPMatrix );  // 투영공간으로 이동

    // 스크린 좌표에 대해서(-0.5, -0.5)의 오프셋
    Out.pos /= Out.pos.w;

    // 투영공간의 좌표를 한번 스크린 좌표로 해서、
    // 0.5씩 오프셋 처리를 하고 원래대로 돌아온다
    // 아래와 같이 작성해도 컴파일러가 최적화를 시켜준다
    Out.pos.x = (Out.pos.x * screenW - 0.5f) / screenW;
    Out.pos.y = (Out.pos.y * screenH + 0.5f) / screenH;

    return Out;
}


WVPMatrix(월드 X 뷰 X 프로젝션)를 로컬 좌표로 곱한 후에 각 성분을 w성분으로 나누면 

버텍스 좌표는 (-1, -1, 0) ~ (1,1,1)이라는 작은 영역으로 제한된다. 

이것이 늘어나 스크린좌표가 되는 것이다. 


지금은 스크린 좌표 베이스에서 0.5 오프셋을 넣는것이기에 한번 스크린 의 폭과 높이를 좌표에 곱해 스크린 좌표로 변환해서 0.5 오프셋을 넣고 다시 스크린의 폭과 높이로 나누어 작은 영역으로 되돌린다. 


y 성분은 스크린의 축과 투영공간의 축의 방향이 반대이기 때문에 덧셈을 하는것에 주의 한다



  Dot By Dot 표시는 2D 시대에는 당연한(애초에 그것밖에 없음)것 이었지만 3D가 베이스가 되는 DirectX에 있어서는 의외로 어려운 것이다. 하지만 래스터라이제이션 룰과 버텍스 보간의 내부를 역수로 취하면 가능 할 것이다


MSDN에서 설명하는 래스터라이즈 규칙

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

밉맵 디테일 높이기  (0) 2013.06.10
Early Z  (0) 2013.06.08
x파일에 대한 pdf  (0) 2013.03.11
NormalMapGenerator  (0) 2013.02.23
x파일 뷰어  (0) 2013.02.17
반응형

http://goo.gl/ZngnS


x파일에 대한 문서.pdf


반응형
반응형

down link :  NormalMapGenerator






http://goo.gl/bdQfP




올리기올려짐: 2004-09-16 06:33    주제: 높이맵이 문제네요....

lachesis님의 조언대로 NormalMapGenerator라는 노말맵 생성 프로그램의 소스를 분석해 노말맵 생성프로그램을 구현 해보았습니다.(코드량 정말 쪼끔) 
그런데 문제는 그 소벨필터링은 일반적인 칼라이미지가 아닌 높이맵을 읽어서 노말맵을 생성한다는 것입니다. 일단은 GPG2의 부록 CD에 있는 높이맵을 가지고 테스트 해봤습니다. 물론 제대로 노말맵이 생성됩니다. 
그런데 이 높이맵을 어떻게 칼라맵에서 뽑아 낼지가 관건입니다. 

일단은 높이맵이 그레이스케일 이미지라고 해서 픽셀의 RGB값을 더해서(R+G+B) 3으로 나누어 다시 RGB에 똑같은 값으로 저장해 보았습니다. 

RED = (R+G+B)/3; 
GREEN = (R+G+B)/3; 
BLUE = (R+G+B)/3; 

하지만 부록 CD에 있는 높이맵 처럼 나오지가 않습니다. ㅡㅡ 

이 높이맵을 생성할 수 있는 방법을 알고싶네요......................... 


그전에 GPG2 CD의 RadeonDot3Bump3DLight폴더에 있는 FieldstoneBump파일이 높이맵이 맡는지 물어보고 싶네요... 높이맵 같은데 파일 이름끝에 Bump라고 붙어 있어서... ㅡㅡ






voidpeople님께서 지금 하고있으신 작업은 대부분 ATI개발자에 자료가 꽤 있습니다. 

노말맵생성에 대해서도 역시 NormalMapGenerator라는 툴을 제공하고있는데 
소스도 같이 배포하고 있구요, 소스파일은 고작 하나뿐인데 300줄 밖에 되지않습니다. 

TGA형태의 height map을 읽어서 normal map으로 바꿔주는데, 
질문하신 sobel filter를 적용하는 부분도 나와있구요. 

그리고 또 찾아보시면 NormalMapper라는 툴도 소스와 함께 제공하는데, 
보통 Doom 3나 FarCry 등에서 쓰는 하이폴리곤에서 노말맵을 
추출하는 polybump 형태의 툴도 있습니다.


반응형
반응형

DXViewer.exe



예전버전인듯..

반응형
반응형

http://www.nvidia.co.kr/geforce-experience/



드라이버를 최신 상태로 유지하고 게임을 최적화할 수 있는 가장 쉬운 방법

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

NormalMapGenerator  (0) 2013.02.23
x파일 뷰어  (0) 2013.02.17
더미(dummy)  (0) 2013.02.13
스크린 스페이스 데칼  (0) 2013.02.13
기하정보 저장 버퍼  (0) 2013.02.10
반응형

http://goo.gl/9yU00




반응형
반응형

http://kblog.popekim.com/2012/10/kgc-2012_12.html

2012년 10월 12일 금요일

스크린 스페이스 데칼 (KGC 2012 발표자료)

KGC 2012에서 발표했던 "스크린 스페이스 데칼에 대해 자세히 알아보자"의 슬라이드 자료 공개합니다.

뒤에 서서 보시는 분들도 여럿 계실정도로 강의실이 꽉 찼던데.... 모두들 찾아와주셔서 감사합니다.


 
스크린 스페이스 데칼에 대해 자세히 알아보자(워햄머 40,000: 스페이스 마린) from 포프 김 


제 시그래프 자료는 이보단 약간 부실한데.. 굳이 궁금하신 분들은 영문 블로그를 참고해주시기 바랍니다.

반응형
반응형
http://memset.tistory.com/129

기하정보 저장 버퍼

 

버퍼사용 이유

배열이 아닌 버퍼에 저장하는 이유는 버퍼를 비디오 메모리에 저장할 수 있기 때문으로, 시스템 메모리의 데이터를 렌더링하는 것보다는 비디오 메모리의 데이터를 렌더링하는 것이 훨씬 빠르기 때문이다.

버텍스 버퍼 

버텍스 데이터를 보관하는 연속적인 메모리 덩어리
HRESULT IDirect3DDevice9::CreateVertexBuffer(
UNIT Length,                   //버퍼에 할당할 바이트 수
DWORD Usage,              //버퍼가 이용되는 몇 가지 부가적인 특성
DWORD FVF,                 //버텍스 보관될 버텍스 포멧
D3DPOOL Pool,             //버퍼가 위치할 메모리 풀
IDirect3DVertexBuffer9** ppVerTexBuffer, 
                                   //만들어질 버텍스 버퍼를 받을 포인터 
HANDLE* pShareHandle    //이용하지 않는다.0으로 지정
);

ex) 8개 버텍스 정보를 가질수 있는 버퍼 생성
IDirect3DDeviceVertexBuffer9* vb;
Device->CreateVertexBuffer( 8*sizeof(Vertex), 0, 
D3DFVF_XYZ, D3DPOOL_MANAGED, 
&vb,0 );

인덱스 버퍼

인덱스 데이터를 보관하는 연속적인 메모리 덩어리
HRESULt IDirect3DDevice9::CreateIndexBuffer(
   UNIT Length,
   DWORD Usage,
   D3DFORMAT Format,         //만들어질 인덱스 버퍼를 받을 포인터
   D3DPOOL Pool,
   IDirect3DIndexBuffer9** ppIndexBuffer,
   HANDEL* pShareHandle
};

ex) 8개 버텍스 정보를 가질수 있는 버퍼 생성
IDirect3DDeviceIndexBuffer9* ib;
Device->CreateIndexBuffer( 36*sizeof(WORD),D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 
D3DFMT_INDEX16, D3DPOOL_MANAGED, 
&ib,0 );
Usage에서 사용되는 플래그
D3DUSAGE_DYNAMIC – 버퍼를 동적으로 만든다.
D3DUSAGE_POINTS – 버퍼가 포인트 기본형을 보관할 것임을 지정
D3DUSAGE_SOFTWAREPROCESSING – 버텍스 프로세싱을 소프트웨어로 처리
D3DUSAGE_WRITEONLY – 애플리케이션이 버퍼에 쓰기만을 수행할 것임을 지정.만약 버퍼를 읽으려고 하면 오류 발생

정적버퍼

비디오 메모리상 효율적인 메모리 처리, 접근속도 제약이 있음 주로 정적 데이터 처리, D3DUSAGE_DYNAMIC 플래그 지정하지 않은 버퍼 해당
ex) 
데이터 처리빈도가 적은 지형, 건물 기하정보(애플리케이션 초기화 때 정적버퍼에 기하정보 저장)

동적버퍼

D3DUSAGE_DYNAMIC 플래그 지정, AGP메모리 저장, 메모리 처리속도는 비디오 메모리 전송과정이 필요하므로 정적보다 느림, 그러나 갱신속다가 빠름(고속 CPU쓰기 처리)
ex) 파티클 시스템, 프레임별 기하정보 변환이 필요하므로 동적 필요

Tip

비디오 메모리나 AGP메모리에서의 읽기 작업은 상당히 느리므로 런타임시에 기하정보를 자주 읽어 들여야 한다면 지역 시스템 메모리에 복사본을 남겨두고 이를 읽어들이는 것이 바람직하다.

버퍼 메모리에 접근하기

HRESULT IDirect3DVerTexBuffer9::Lock(
   UNIT OffsetLock,   //잠금을 시작할 버퍼 위치의 오프셋
   UNIT SizeLock,     //잠글 바이트의 수(offsetlock + sizelock)
   BYTE** ppbData,   //잠근 메모리의 시작을 가리키는 포인터 수
   DWORD Flags );    //잠근을 이루어지는 방법 지정. 0을 지정하거나 플래그를 지정

HRESULT IDirect3DIndexBuffer9::Lock(
   UNIT OffsetLock,
   UNIT SizeLock,
   BYTE** ppbData,
   DWORD Flags );

ex)
Vertex* vetice;
Vb->Lock( 0, 0, (void**)&vertice, 0 );
Vertice[0] = Vertex( -1.0f, 0.0f , 2.0f );
Vertice[1] = Vertex( 0.0f, 1.0f, 2.0f );
Vertice[2] = Vertex( 1.0f, 0.0f, 2.0f );
Vb -> Unlock();
DWORD Flag 인자
D3DLOCK_DISCARD – 동적 버퍼에만 이용. 하드웨어에게 버퍼를 버리도록 지시하고 새로 할당된 버퍼의 포인터를 리턴
D3DLOCK_NOOVERWRITE – 이 플래그는 동적 버퍼에만 이용. 버퍼에 데이터를 추가하는 작업만 가능하도록 하는 것
D3DLOCK_READONLY – 읽기 전용으로 버퍼를 잠글 것임을 지정

※D3DLOCK_DISCARD와 D3DLOCK_NOOVERWRITE  이 두 플래그를 이용할 수 있는 상황이라면 버퍼를 잠글 때도 렌더링이 정지되는 것을 막을 수 있다.

버텍스/인덱스 버퍼에 대한 정보

상황에 따라 버텍스/인덱스에 대한 정보를 얻는데 이용되는 메서드 이용의 예이다.

D3DVERTEXBUFFER_DESC vbDescription;
vertexBuffer->GetDesc(&vbDescription);   //버텍스 버퍼 정보를 얻는다.

D3DINDEXBUFFER_DESC ibDescription;
indexBuffer->GetDesc(&ibDescription);   //인덱스 버퍼 정보를 얻는다.

렌더 상태

Direct3D는 기하정보가 렌더링되는 방식을 결정하는 다양한 렌더링 상태를 캡슐화하고 있다. 렌더 상태는 모두 디폴트 값을 가지고 있으므로 여러분의 애플리케이션에서 디폴트가 아닌 다른 동작을 필요로 하는 경우에만 이를 변경하면 된다. 
렌더 상태를 알고 싶다면 SDK문서의 D3DRENDERSTATETYPE항목에서 찾을 수 있다
HRESULT IDirect3DDevice9::SetRenderState(
   D3DRENDERSTATETYPE State,         //변경 할 상태
   DWORD Value );                            //새로운 상태 값

ex) 와이어프레임으로 렌더링
device->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );

드로잉

스트림 소스 지정

스트림 소스를 버텍스 버퍼와 연결하여 버퍼의 기하정보를 렌더링파이프라인 보낼 수 있도록 한다.
 HRESULT IDirect3DDevice9::SetStreamSource(
   UNIT StreamNumber,      //버텍스 버퍼를 연결할 스트림 
                                    //소스를 지정.
   IDirect3DVertexBuffer9* pStreamData,  
                                    //스트림과 연결하고자 하는 버텍스 버퍼
                                    //로의 포인토
   UNIT offsetInBytes,
                                    //렌더링 파이프라인으로 공급될 버텍스 
                                    //데이터의 시작을 지정 스트림의 오프셋
   UNIT Stride
                                   //스트림에 연결하고자 하는 버텍스 버퍼 
                                   //내 각 요소의 바이트 수
);
ex)
device->SetStreamSource( 0, vb, 0, sizeof( Vertex ) );

버텍스 포맷을 지정

이후의 드로잉 호출에서 이용될 버텍스포맷을 지정하는 단계
device->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEXT);

인덱스 버퍼를 지정

인덱스 버퍼는 한 번에 하나의 인덱스 버퍼만 이용할 수 있다. 따라서 인덱스 버퍼를 가진 물체를 그려야한다면 인덱스 버퍼를 전환하는 과정이 필요하다.
device->SetIndices( ib ); //인덱스 버퍼 포인터의 복사본을 전달한다.

버텍스/인덱스 버퍼를 이용한 드로잉

DrawPrimitive나 DrawIndexPrimitive 메서드를 이용해 기하정보를 렌더링 파이프라인으로 보내는 실질적인 드로잉을 수행할 수 있다.
버텍스 정보 이용 그리기
HRESULT IDirect3DDevice9::DrawPrimitive( 
   D3DPRIMITIVETYPE PrimitiveType,    //그리고자 하는 기본형 타입
   UNIT StartVertex,                           //버텍스읽기를 시작할 버텍스 
                                                    //요소로의 인덱스.
   UNIT PrimitiveCount                       //그리고자 하는 기본형의 수
 );

ex)
device->DrawPrimitive( D3DPT_TRIANGLELIST, 0 , 4 );

인덱스 정보 이용 그리기
HRESULT IDirect3DDevice9::DrawIndexPrimitive(
D3DPRIMITIVETYPE Type,   //그리고자 하는 기본형 타입
INT BaseVetexIndex,          //이번 호출에 이용될 인덱스에 더해질 기
                                     //반 번호를 지정
UNIT MinIndex,                 //참조할 최소 인덱스 값
UNIT NumVertice,              //이번 호출에 참조될 버텍스의 수
UNIT StartIndex                //인덱스 버퍼내에서 읽기를 시작할 요소로
                                    //의 인덱스
UNIT PrimitiveCount          //그리고자 하는 기본형의 수
);

ex)
device->DrawIndexPrimitive( D3DPT_TRIANGLELIST, 0 ,0 ,8 ,0 , 12 );

장면의 시작과 끝

마지막으로 기억해두어야 할 사항으로는 모든 드로앙 메서드가 BeginScene와 EndScene 호출 내부에 포함되어야 한다.
device->BeginScene();
device->DrawPrimitive();
device->EndScene();

D3DX 기하 물체

코드 내에서 각각의 삼각형을 연결하여 3D물체를 구성하는 작업은 상당히 지루할 것이다.
그래서 우리는 편하게 D3DX에서 제공하는 라이브러리는 몇 가지의 간단한 3D 물체 메쉬 데이터를 생성하는 메서드를 제공한다.

D3DXCreateBox, D3DXCreateSphere, D3DXCreateCylinder, D3DXCreateTeapot, D3DXCreatePolygon,  D3DXCreateTours
생성된 기하 물체를 그리려면 다음 함수를 이용한다.

ID3DXMesh::DrawSubset(DWORD AttribId);
// 드로잉(Drawing) 하는 메쉬의 서브 세트를 지정하는 DWORD. 이 값은, 메쉬내의 면을, 1 개 또는 복수의 속성 그룹에 속하고 있다고 하여 구별하기 위해서 사용된다. 
ex) 티포트 생성
HRESULT D3DXCreateTeapot(
LPDIRECT3DDEVICE9  pDevice,   //메쉬와 연계된 장치
LPD3DMESH* ppMesh,            //메쉬를 받을 포인터
LPD3DXBUFFER* ppAdjacency    //현재는 0으로 지정
);         
ID3DXMESH* mesh = 0;
D3DXCreateTeapot( device, &mesh, 0 );

device->BeginScene();
device->DrawSubset(0);
device->EndScene;

//after using
mesh->Release();
mesh = 0;

[출처] Direct3D 그리기 |작성자 아이엠쏭


반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

더미(dummy)  (0) 2013.02.13
스크린 스페이스 데칼  (0) 2013.02.13
버텍스버퍼 활용  (0) 2013.02.10
Primitive 종류 설명  (0) 2013.02.09
TGA파일에서 알파채널 만들기  (1) 2013.01.31
반응형

http://www.gpgstudy.com/forum/viewtopic.php?topic=8829





엔진 속도를 올려볼려고, 파티클의 빌보드 한개당 DrawPrimitive하던것을 
긴 버텍스 버퍼에 월드 좌표로 때려밖은후에 렌더링 하려고 고치는 중입니다. 

DrawPrimitive횟수도 많이 줄이고요, SetRenderState, SetTexture횟수도 줄이도록 정렬하고있습니다. 

그런데.. 버텍스 버퍼가 크다보니 락/언락만 해도 프레임이 10%로 내려가더군요.. 
엄청난 속도 저하이죠..^^ 정확히 이야기하면 락/언락 하고 그버퍼의 폴리곤 1개만 찍어도 그러더군요.. 
안찍으면 락/언락해도 전혀 안내려가고요... 

버텍스 버퍼를 D3DPOOL_MANAGED로 만들어서 DrawPrimitive하는순간 시스템메모리에있는 복사본을 
VGA로 넘기나 봅니다. 
그래서 D3DPOOL_DEFAULT로 생성했더니 속도저하가 없더군요..다만 디바이스 리셋시 삭제/복구만 잘해주면 
될듯 싶습니다.. 그게 귀찮아서 이제껏 D3DPOOL_MANAGED만 사용했었거든요.. 

지오메트리랑, 스킨모두 D3DPOOL_MANAGED로 사용하고있거든요.. 
지오메트리야 정점 버퍼 자체는 변하지 않아서 첨 생성해서 만든다음 그냥 사용하고 
스킨은 Tick()마다 락/언락을 하거든요.. 

궁금한점 
1. 락/언락을 하지 않는 버퍼는 D3DPOOL_MANAGED와 D3DPOOL_DEFAULT가 성능이 같나요? 
2. 락/언락을 하는 D3DPOOL_MANAGED버퍼는 DrawPrimitiveUP하고 성능이 같나요? 
3. 모두 D3DPOOL_DEFAULT로 바꾼다면 비디오메모리가 모자랄경우 D3DPOOL_MANAGED에 비해 단점이 있나요? 혹은 디바이스 리셋시 삭제/복구말고, 락할때 옵션이라던지 다른 관리들이 필요한지 궁금하네요..








SDK 도움말에 설명이 나와있하지만.. 그래도 꽤 많은 분들이 헷갈려하시는거 같습니다. 

D3DPOOL_MANAGED 는 풀이 시스템메모리에 백업되고 필요시에 비디오메모리로 로드됩니다. 한번 로드된 풀은 해제되거나 아니면 메모리의 부족으로 강제로 내려갈때까진 메모리상에서 유효합니다. 
시스템메모리에 백업되어있기때문에 디바이스 리셋시에도 별다른 조치를 할 필요가 없습니다. 

D3DPOOL_DEFAULT 는 풀이 비디오메모리에 바로 생성되고 메모리가 부족하면 풀을 만들때 오류를 뱉어냅니다. 따로 백업되어있지않기때문에 디바이스 리셋시에 더이상 유효하지 않게 됩니다. 

D3DPOOL_MANAGED 는 시스템메모리에 백업되어있기때문에 'Read' 하는것에는 별다른 문제가 없습니다. 다만 'Write' 는 하게될때마다 메모리에서 내렸다가 다시 로드되어야되기때문에 무리가 따릅니다. (레퍼런스상에서도 D3DPOOL_MANAGED 로 생성된 버텍스버퍼나 인덱스버퍼는 런타임상에서 업데이트하는걸 성능상에 문제로 추천하고 있지 않습니다. 같은 이유로 렌더타겟같은것들은 D3DPOOL_MANAGED 로 만들수가 없습니다.) 

D3DPOOL_DEFAULT 는 따로 시스템메모리에 백업이 없기때문에 'Read' 에 무리가 있습니다. 다만 'Write' 하는것에는 D3DPOOL_MANAGED 로 만들어진것보단 적합해서 각종 다이나믹 버텍스버퍼/인덱스버퍼 등에 쓰이게 됩니다. 

다이나믹 버텍스버퍼나 인덱스버퍼를 쓸때 자주 쓰이는 옵션인 D3DLOCK_DISCARD 와D3DLOCK_NOOVERWRITE 는 CPU 와 GPU 의 병목현상을 막기위한 플래그들입니다. 
D3DLOCK_DISCARD 는 현재 드라이버가 잡고있는 풀은 그대로 내버려두고 같은 크기의 새로운 풀을 잡아서 거기에 업데이트를 할수 있게합니다. 그리고 잡고있던 풀이 다 쓰여지고 나면 그 풀을 해제되고 새롭게 만들어졌던 풀이 쓰이게 되는거죠. 드라이버가 다 그릴때까지 멈춰있을수없으니 이런식으로 쓰게 됩니다. 
D3DLOCK_NOOVERWRITE 는 현재드라이버가 잡고있는 풀을 업데이트하지 않겠다고 명시적으로 말하는거가 되겠네요. 렌퍼런스에서는 저 두개의 옵션중에 한가지는 꼭 Lock 할때 써주는것을 추천하고 있습니다. (두개같이 쓰는건 비추하고 있습니다.) 

이런저런 이유로 보통 다이나믹 버텍스버퍼나 인덱스버퍼를 쓸때는 조금 큰 하나의 풀을 잡아놓고 거기에 조금씩 알맞는 플래그로 업데이트해가며 렌더링하는게 여러가지면에서 좋은거 같습니다. 

unsigned int uOffset = 0; 
Loop { 
unsigned int uVertexSize = ...; 
if(uOffset+uVertexSize > uVertexBufferSize) { 
uOffset = 0; 

unsigned long dwLockFlag = D3DLOCK_DISCARD; 
if(uOffset > 0) dwLockFlag = D3DLOCK_NOOVERWRITE; 
pVertexBuffer->Lock(uOffset, uVertexSize, ..., dwLockFlag); 
... 
pVertexBuffer->Unlock(); 
DrawPrimitive(...); 
uOffset += uVertexSize; 


1. 
D3DPOOL_MANAGED 나 D3DPOOL_DEFAULT 나 업데이트를 하지 않는다는 조건에서는 성능은 같습니다. (다만 D3DPOOL_MANAGED 로 생성된 많은양의 풀들이 한꺼번에 비디오메모리로 로드되는 순간에는 버벅임같은것을 느낄수는 있습니다.) 
2. 
D3DPOOL_MANAGED 로 생성된 풀을 런타임상에서 계속 Lock/Unlock 하는건 DrawPrimitiveUP 보다 더 느릴수도 있습니다. 
3. 
모두 D3DPOOL_DEFAULT 로 바꾼다면 비디오메모리가 부족하면 아예 풀생성 자체가 안됩니다. 용도에 따라 꼭 D3DPOOL_MANAGED 가 되어야되는경우도 있습니다. (텍스쳐같은걸 Lock/Unlock 등을 통해서 읽어야되는경우) 레퍼런스상에서는 특별한 경우를 제외하곤 D3DPOOL_MANAGED 를 쓰라고 하고 있습니다.

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

스크린 스페이스 데칼  (0) 2013.02.13
기하정보 저장 버퍼  (0) 2013.02.10
Primitive 종류 설명  (0) 2013.02.09
TGA파일에서 알파채널 만들기  (1) 2013.01.31
포샵에서 DDS파일 만들기(2)  (0) 2013.01.31
반응형

http://tadis.tistory.com/category/Direct%20X:



이렉트3D는 정해진 기본형(primitive)을 이용해서 그리는 함수를 4가지를 제공한다.

 

1. 인덱스 버퍼(vertex buffer)를 이용하지 않고 기본형을 그리는 함수

  1) DrawPrimitive(): Drawprimitive 함수는 데이터 입력스트림의 현재 집합으로부터 지정된 형식의 '인덱스 되지 않은 기본형들을 렌더링' 한다. 이 경우 유일한 '데이터 스트림은 SetStreamSource함수에 의해 선언'된 것이다. (버텍스 버퍼를 이용한다.)

 

  - Syntax-

    HRESULT DrawPrimitive(
   D3DPRIMITIVETYPE primitiveType,

   UINT StartVertex, 
   UINT PrimitiveCount

   );

 

  - Parameter-

   ○ primitiveType(Type: D3DPRIMITIVETYPE)

   : 열거된 D3DPRIMITIVETYPE의 맴버로 '랜더링될 기본형의 종류'

   ○ StartVertex(Type: UINT)

   : '첫번째로 로드될 버텍스의 번호'. 첫번째 번호가 설정되면 버텍스 버퍼의 끝까지 읽어들인다.

   ○ PrimitiveCount(Type: UINT): '렌더링할 기본형의 개수'. 출력가능한 최대 개수는 D3DCAPS9 구조체에 있는 MaxPrimitiveCount에서 정보를 얻을 수 있다.

 

   - Return value-

   HRESULT

   : 성공하면 D3D_OK를 리턴한다. 실패하면 D3DERR_INVALIDCALL을 리턴한다.

 

 2) DrawPrimitiveUp(): DrawprimitiveUp 함수는 사용자 메모리 포인터에 의해 지정된 타입의 기본형정보를 렌더링 한다. (버텍스 버퍼를 이용하지 않는다.)

  - Syntax-

  HRESULT DrawPrimitiveUP(
   D3DPRIMITIVETYPE PrimitiveType,
  UINT PrimitiveCount,
  const void *pVertexStreamZeroData,
  UINT VertexStreamZeroStride

  );

 

   - Parameter-

  ○ primitiveType(TYPE: D3DPRIMITIVETYPE)

  : 열거된 D3DPRIMITIVETYPE의 맴버로 '랜더링될 기본형의 종류'

  ○ primitiveCount(Type: UINT): '렌더링할 기본형의 개수'. 출력가능한 최대 개수는 D3DCAPS9 구조체에 있는 MaxPrimitiveCount에서 정보를 얻을 수 있다.

  ○ pVertexStreamZeroData(Type: const void*): 버텍스 데이터의 유저 메모리 포인터 

  ○ pVertexStreamZeroStride(Type: UINT): 각 각의 버텍스데이터의 크기 

 

  - Return value-

   HRESULT

   : 성공하면 D3D_OK를 리턴한다. 실패하면 D3DERR_INVALIDCALL을 리턴한다.

 

3) DrawIndexedPrimitive(): DrawIndexedPrimitive 함수는 인덱스 되어 있는 버텍스를 기본으로 버텍스들의 기본형들을 렌더링 한다. (인덱스 버퍼+버텍스 버퍼를 이용한다.)

 

- Syntax-

   HRESULT DrawIndexedPrimitive(
     D3DPRIMITIVETYPE Type,
     INT BaseVertexIndex,

     UINT MinIndex,

     UINT NumVertices,

     UINT StartIndex,

     UINT PrimitiveCount
  );

 

  - Parameter-

  ○ primitiveType(TYPE: D3DPRIMITIVETYPE)

    : 열거된 D3DPRIMITIVETYPE의 맴버로 '랜더링될 기본형의 종류'

  ○ BaseVertexIndex(TYPE: INT): 버텍스 버퍼의 시작에서 부터 첫번째 버텍스까지의 오프셋

   ○ MinIndex(TYPE: UINT)

    : 호출하는 동안 사용될 최소의 버텍스 인덱스. 0이면 BaseVertexIndex가 기본이 된다.

   ○ NumVertices(TYPE: UINT): 함수 호출하는 동안에 사용될 버텍스들의 숫자. 첫 버택스는 BaseVertexIndex+MinIndex에 위치해 있다.

   ○ StartIndex(TYPE: UINT): 버텍스 버퍼에 접근할때 이용될 첫번째 인덱스의 숫자. 버텍스 버퍼에서 startIndext부터 Index가 시작한다.

   ○ PrimitiveCount(TYPE: UINT): '렌더링할 기본형의 개수'. 출력가능한 최대 개수는 D3DCAPS9 구조체에 있는 MaxPrimitiveCount에서 정보를 얻을 수 있다.

 

  - Return value-

  HRESULT

  : 성공하면 D3D_OK를 리턴한다. 실패하면 D3DERR_INVALIDCALL을 리턴한다.

  

4) DrawIndexedPrimitiveUp(): DrawIndexedPrimitiveUp 함수는 유저에 의해 지정된 메모리 포인터를 이용해여 지정된 기본형들을 렌더링 한다. (인덱스 버퍼+버텍스 버퍼를 이용하지 않는다.)

 

  - Syntax-

  HRESULT DrawIndexedPrimitiveUP(
    D3DPRIMITIVETYPE PrimitiveType,
    UINT MinVertexIndex,
    UINT NumVertices,
    UINT PrimitiveCount,
    const void *pIndexData,
    D3DFORMAT IndexDataFormat,
    const void *pVertexStreamZeroData,
    UINT VertexStreamZeroStride
  );

 

  - Parameter-

  ○ primitiveType(TYPE: D3DPRIMITIVETYPE)

   : 열거된 D3DPRIMITIVETYPE의 맴버로 '랜더링될 기본형의 종류'

  ○ MinVertexIndex(TYPE: UINT): 최소 버텍스 인텍스 (0부터 시작하는 인덱스이다.)

  ○ NumVertices(TYPE: UINT): 함수 호출하는 동안에 사용될 버텍스들의 숫자. 첫번째 버텍스는 MinVertexIndex에서 설정한 인덱스에 있다.

  ○ PrimitiveCount(TYPE: UINT): '렌더링할 기본형의 개수'. 출력가능한 최대 개수는 D3DCAPS9 구조체에 있는 MaxPrimitiveCount에서 정보를 얻을 수 있다.

  ○ pIndexData(TYPE: const void*): 인덱스 데이터의 메모리 포인터.

  ○ IndexDataFormat(TYPE: D3DFORMAT ): D3DFORMAT에서 열거되어 있는 타입. 인덱스 데이터의 형태를 나타만다. 가능한 설정값은 D3DFMT_INDEX16, D3FMT_INDEX32 이다.

  ○ pVertexStreamZeroData(TYPE: const void*): 버텍스 데이터의 메모리 포인터. 이때 버텍스 데이터는 stream0에 위치해야 한다.

  ○ VertexStreamZeroStride(TYPE: UINT): 각각의 버텍스 데이터(자료형의) 크기

 

- Return value-

HRESULT

: 성공하면 D3D_OK를 리턴한다. 실패하면 D3DERR_INVALIDCALL을 리턴한다.

 

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

기하정보 저장 버퍼  (0) 2013.02.10
버텍스버퍼 활용  (0) 2013.02.10
TGA파일에서 알파채널 만들기  (1) 2013.01.31
포샵에서 DDS파일 만들기(2)  (0) 2013.01.31
포샵에서 DDS파일 만들기(1)  (0) 2013.01.31
반응형


[포토샵] TGA파일에서 알파채널 만들기  Producer 

2010/11/09 19:16

복사http://blog.naver.com/kamikaze329/140117866938



TGA파일에서 알파채널을 만들어 보자. TGA파일은 에프터이팩트에서 여러장의 사진을 불러와 애니메이션 효과를 낼 수 있다. (다른 파일도 가능)

TGA파일을 불러온 후 채널란에 알패채널이 없다. 이제 추가 해보자.



레이어 창을 누른 뒤 background를 더블 클릭 후에 엔터를 쳐 새로운 레이어를 만들자.




새로운 레이어가 만들어 졌으면  왼쪽에 있는 툴을 선택해 알파채널을 만들 부분을 선택한다.



선택한후 Delete키를 누르면 체크 무늬의 배경이 생긴다.


 

여기서 ctrl + Shift + I 를 누르고 오른쪽 아래 채널에서 표시된 아이콘을 누르면 알파 채널이 생성이 된다.

 

ctrl + d 를 누르면 선택을 취소 한다.

ctrl  + s를 눌러 저장을 한다. 저장시 본래의 TGA파일로 선택 후 저장한다.



끝.~


반응형
반응형

DDS파일로 변환하기 두번째  PHOTOSHOP강좌 

2006/09/13 05:21

복사http://blog.naver.com/enuom/30008693994


그림파일 만드시는게 힘드신듯 한데, 예제 소스를 이용하시는 것을 보니 소스 설명은 접어
 
두고 어떻게 알파채널이 적용된 그림파일을 만드는지만 설명하겠습니다.
 
일단, 전 DDS파일 포멧으로 작업을 할것인데, 알파채널을 지원한다면 어떠한 파일 포멧
 
이어도 상관 없어요, 예로써 tga도 상관 없다는 거죠
 
필요한 준비물은 포토샾하고, dds를 다루기 위한 플러그인이 필요한데,
 
NVIDIA홈페이지 가면 있어요
 
http://developer.nvidia.com/object/photoshop_dds_plugins.html
 
다운 받으셨으면, 포토샾 플러그인에 넣어주면 다른이름 저장할때 dds포멧으로
 
저장 가능해질 겁니다.
 
준비 됐으니 만들어 보죠
 
(출처 : '빌보드의 텍스쳐 투명화 하는 법좀 자세힝 알려주세요' - 네이버 지식iN)

 

위와같은 그림으로 이미지를 만들었다고 하고

하얀부분은 투명해야 한다고 한다면

 

선택툴로 하얀 부분만 선택해줍니다.

마술봉(Magic Wand)으로 선택해주면 됩니다.

그런다음

 

채널에 보시면 알파채널이 없을 겁니다.

RGB채널만 있고 알파채널이 없으면 만들어 줍니다.

새로 만들면 선택 영역이 그대로 남아 있는데, 투명하게 되어야 할 곳을 검은색으로

색을 채워줍니다.

이제 dds파일로 저장만 해 주면 되는데 주의 사항이 있습니다.

 

레이어가 여러개일시 Merge시켜서 배경레이어로 합쳐주셔야 합니다.


원문:http://kin.naver.com/db/detail.php?d1id=1&dir_id=10103&eid=E68Wb2DBCvfjTZwNY9sUcsJGOQc8bv2n&qb=RERTxsTAz8DMtvU/

출처 : 지식인에서 crusader2k(출처 : '빌보드의 텍스쳐 투명화 하는 법좀 자세힝 알려주세요' - 네이버 지식iN)

 

DDS파일로 변환하기 두번째/영화광 강일웅(enuom)


반응형
반응형


포샵에서 DDS파일 만들기  PHOTOSHOP강좌 

2006/09/11 03:31

복사http://blog.naver.com/enuom/30008624015

DDS 포맷으로 저장할 일이 생겨서 하루종일 뒤적이고 물어가면서 얻은 팁인데 3D MMORPG의 경우 대다수의 개발사에서 이미지포맷으로 DDS를 사용하고 있으니 알아두면 좋을것 같아 정리해서 올립니다.

 

DDS는 DirectX(이하 DX)의 Texture 포맷과 일대일로 대응하는 파일 포맷으로 손실압축방식이라 다른 포맷에 비해서 상대적으로 비디오메모리를 아낄 수 있고, 많은 갯수의 텍스쳐, 큰 크기의 텍스쳐를 적은 용량으로 해결할 수 있는데다 DDS포맷 용량 그대로 비디오메모리에 올릴 수 있어 높은 퀄리티의 화면을 높은 프레임으로 구현하기가 용이합니다. 현재는 DDS가 거의 모든 그래픽카드에서 가속을 지원한다고 합니다.

 

DDS의 태생에 대해 잠깐 알아두자면, 처음에 S3TC포맷을 Savage사에서 개발하자, 3DFX에서 FXT1라는 포맷을 만들었다고 합니다. 그러자 S3사가 이 포맷을 NVIDIA, ATI에게 라이센스 해줌과 동시에 DX에서 공식적으로 지원하게 되었답니다.

아래 Nvidia 사이트에 가면 포토샵에서 DDS를 컨트롤할 수 있는 플러그인을 다운받을 수 있습니다.

 

http://developer.nvidia.com/object/photoshop_dds_plugins.html 

 

굳이 이 프로그램을 설치하지 않더라도 이 글에 첨부한 파일(dds.8bi)을 포토샵이 설치된 폴더 아래에 있는 Plug-Ins/Import-Export 폴더에 넣어주시면 됩니다.

 

자, 준비가 됐으면 시작해 보겠습니다.

예제 이미지로 얼룩말 무늬 이미지를 갖고 설명을 드리겠습니다.

1.우선 포토샵에서 얼룩말 이미지를 dds로 저장해 보겠습니다.

Save as 에서 파일포맷 dds(*.dds)를 선택하시면 아래와 같은 창이 나타납니다.


2. 창의 각 항목중 중요한 두가지 항목을 설명드리겠습니다.

 

Save Format DDS의 픽셀포맷을 정하는 것입니다.

DXT1, DXT2, DXT3, DXT5, 4:4:4:4 ARGB, 1:5:5:5 ARGB 등등 여러가지 포맷중 하나를 선택해야 합니다.

3. 각각의 선택기준은 상황에 따라 다릅니다만 DXTn 포맷만이 손실압축이고 그 외의 포맷은 비손실  압축이라 DXTn 포맷 외에는 쓸 일이 거의 없어 설명은 하지 않겠습니다.

 

1. DXT1 RGB(No Alpha) : 알파채널이 없는 이미지일 경우 (칼라는 4단계로 보간) 
2. DXT1 ARGB(1bit alpha) : 알파채널이 있지만 alpha test의 용도로만 쓰는 경우(칼라가 3단계로 보간되므로 DXT1 RGB보다 약간 퀄리티가 떨어짐) 
3. DXT3 ARGB(Explicit Alpha) : 알파채널이 있는 이미지 (칼라는 4단계로 보간되고 알파는 4비트로 표현) 
4. DXT5 ARGB(Interpolated) : 알파채널이 그라데이션 스타일인 경우 DXT5를 쓴다. (칼라는 4단계로 보간되고 알파는 8단계로 보간되므로 품질이 가장 좋음) 

 

그외의 포맷은 모르셔도 무방할것 같습니다. 어떤것이냐고 간단히 말씀드리면 4:4:4:4 ARGB는 ARGB(Alpha, Red, Green, Blue)의 심도가 각각 4bit란 얘기입니다. 1:5:5:5 는 Alpha=1bit(알파채널이 있다,없다만 표시), Red=5bit, Green=5bit, Blue=5bit 란 얘기지요.

 

한가지 주의할 점은 DXTn 포맷으로 저장하려는 이미지의 사이즈는 2의 승수가 되어야 합니다(2, 4, 8, 16, 32, 64, 128, 256, 512, 1024...)

2의 승수가 아니면 'DXT is supported for power 2 only' 란 멧세지가 나오면서 Save 버튼이 비활성화됩니다.

 

UI 이미지 같은 경우는 DDS 포맷으로 쓰는것은 심각하게 고려해야 합니다. 앞서 설명드렸듯이 손실압축이라 이미지가 상당히 깨질 수 있기 때문입니다. (슈마에서 렌즈온라인 만들때 UI 이미지를 DDS로 변환했더니 이미지가 아주 작살이 나더군요;;)

알파채널이 있는 UI 이미지는 PNG나 TGA를 쓰는것이 현명하다고 판단됩니다.

 

픽셀포맷 지정옵션 밑에 있는것이 렌더링 방식을 지정하는 옵션인데요. 2D texture, Cube Map, Volume Texture 가 있습니다.


 

4. 각각의 특성을 폴리곤에 맵핑하는 방법을 예로 들어 설명을 드리자면

 

1. 2D Texture : 각 폴리곤들의 texture coordinate(UV)값을 이용해서 입히는 방식(현재 게임 모델링 데이터에 맵핑하는 방식)

2. Cube Map : UV없이 폴리곤의 면적에 따라 맵핑하는 방식

3. Volume Texture : 좀 더 복잡한 굴곡이 있는 폴리곤에 UV없이 면적에 맵핑하는 방식

 

현재 게임개발에선 2D Texture 외엔 쓰지 않는다고 하니 나머지는 중요치 않습니다.

 

MIPMap Generation MIPMap의 생성갯수를 정합니다.(0~13)

MIPMap 은 같은 그림인데 다른 사이즈를 같이 지닌 형태를 말합니다. 한 이미지 파일에 여러 사이즈를 만들어 놓고 맵핑하고자 하는 폴리곤에 가장 근사한 크기를 갖는 밉맵을 이용하여 텍스쳐맵핑을 수행하는 것을 MIP Mapping이라고 하는거죠.

예를 들면 LOD 같은 것인데요, 게임배경으로 쓰인 돌이 멀리 있을때는 작은 사이즈의 이미지를 맵핑하고 가까이 왔을 때는 큰 이미지를 골라 맵핑하는 방법을 쓰는겁니다. 그렇게 되면 퀄리티의 큰 저하없이 좋은 퍼포먼스를 낼 수 있겠지요.

MIPMap의 갯수를 6으로 하여 미리보기를 해 보겠습니다.



5. 원래 사이즈에  1/4 씩 작아진 사이즈 5개가 생성된 것을 보실 수 있습니다.

이 중 제일 작은 사이즈는 굉장히 멀리 있는 오브젝트에 적용되고 그 오브젝트가 가까이 다가올수록 그 거리에 따라 자동으로 적절한 사이즈의 이미지를 골라 맵핑시키는 방식을 쓰는 겁니다. MIPMap의 갯수가 적으면 멀리 있던 이미지가 가까이 올때 흐리던 이미지가 갑자기 팍 선명해져서 어색할 수 있으니 MIPMap의 갯수는 보통은 5~8개 정도로 합니다만 상황에 따라 적절히 선택하시면 되겠습니다.

 

이정도에서 저장해 주시면 되겠습니다. 저장뿐 아니라 dds로 저장된 파일도 포토샵에서 불러와 편집이 됩니다.

 

나름대로 자세히 정리했는데 더 궁금하신 점은 댓글을 달아 주시면 성심껏 답변드리겠습니다.

 

원본위치 : http://cafe.naver.com/ui.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=613

에 dx에서 많이 쓰는 dds포맷에 관한 자료가 있어서 퍼왔습니다.쓰신분은 세거이(seguy)님..

 

 

DDS에 대한 좋은 설명 요약 



chaen님의 DDS에 대한 의견. 



파일포맷과 픽셀포맷에 대한 구분이 좀 있었으면 합니다. TGA, JPG, DDS는 파일 포맷이고, A8R8G8B8, DXT1 같은 것은 픽셀 포맷입니다. 따라서 DDS == DXTn 은 아닙니다. 

DDS는 DirectX의 Texture 포맷과 일대일로 대응하는 '파일 포맷'일 뿐입니다. 
DDS에서도 A8R8G8B8 로 저장할 수 있습니다. 그 내용은 TGA 32bpp와 거의 똑같다고합니다. 
파일 사이즈 역시 거의 비슷하다고 합니다. R8G8B8, A8R8G8B, X1R5G5B5 같은 포맷은 TGA에서 지원하고, R8G8B8 같은 포맷은 JPG(어떻게 보면 압축된 R8G8B8), BMP같은 대부분의 일반적인 이미지 파일포맷들이 지원합니다. 다만, DXTn(DTXc,S3TC)을 저장할 마땅한 포맷이 없어서 DDS를 쓰다보니 DDS == DXTn 이라고 이야기들을 하시는 것같습니다. 

DDS는 밉맵의 각 레벨의 서피스를 묶어서 하나의 파일로 저장할 수도 있고, 심지어 Cube 텍스쳐나 Volume 텍스쳐로도 저장이 가능합니다. 이런 면들을 볼 때 DDS 포맷의 진짜 목적은 DirectX에서 쓰는 텍스쳐와 같은 포맷을 사용함으로써, 텍스쳐 생성 후 파일에서 로딩한 데이터를 텍스쳐의 서피스로 복사해서 넣을 때, 압축해제나 픽셀포맷 변환없이 바로 사용할 수 있다는 게 아닐까 생각됩니다. 예를 들어, TGA 24bpp 이미지는 R8G8B8( B8G8R8 ) 이지만 오늘날 대부분의 그래픽 카드에서는 DirectX에서 이에 해당하는 D3DFMT_R8G8B8 포맷을 잘 지원하지 않습니다. 
대신 대부분 D3DFMT_X8R8G8B8 포맷을 지원하죠. 따라서, 알파 없는 TGA 파일을 사용한다면 항상 모든 픽셀에 대해서 포맷 변환 작업이 필요하게 됩니다. 이때 DDS로 X8R8G8B8 포맷을 만들어서 사용한다면 그런 변환 작업이 필요 없어집니다. 

그럼에도 불구하고 대부분의 개발자들이 JPG나 TGA 파일을 여전히 선호하는 결정적인 이유는 Preview(미리보기)가 가능하기 때문인 거 같습니다. ACDSee나 알씨 같은 이미지 뷰어에서 이미지를 미리 볼 수 없다는 것은 상당히 답답한 일이죠. ( Deep Exploration 같은 좋은 툴이 DDS 포맷을 지원하기는 합니다만.) 또, 포토샵 같은 그래픽툴에서 바로 쓸 수 없어 번거롭죠. (물론, 플러그인 등을 깔면 가능합니다.) 

PC 같이 다양한 하드웨어가 상존하는 플랫폼에서는 어쩌면 픽셀 포맷 변환이라는 것이 필수 불가결한 일 일지도 모릅니다. 적당한 픽셀 포맷을 미리 지정해서 DDS 포맷으로 저장했다고 하더라도, 이를 지원하지 않는 하드웨어를 가진 일부 사용자들은 결국 픽셀변환이 필요하기 때문이죠. 때로는 더 나은 성능을 위해서 32bpp나 24bpp 포맷을 16bpp 포맷으로 변환하는 작업이 필요할 때도 있습니다. 

DXT 포맷을 제외한 나머지 포맷들은 전혀 압축이 되지 않아서 전체 게임데이터 양을 크게 만든다는 단점도 있습니다. 이는 파일서버 여유공간이 부족한 개발사에겐 게임 개발 과정 중 데이터 유지관리에 부담이 될 수도 있으며, 게임 설치후 HDD를 차지하는 공간이 커져서 소비자에게 부담스러울 수도 있습니다. 물론, 퀘이크 시리즈처럼 게임 데이터들을 ZIP 파일로 한번 더 묶어 줌으로서 해결할 수 있는 문제이기도 합니다. 

간단히 추론하자면 적당한 환경이 갖춰진다면 모든 텍스쳐 포맷을 DDS로 쓰는 게 게임의 성능을 위해서 좋지만 현실적으로는 일반적인 이미지 포맷과 DDS를 섞어 쓰는 것도 나쁘지 않다고 생각합니다. 혹은 개발중에는 섞어 쓰다가 릴리즈용 리소스들을 묶어 주면서, 모든 텍스쳐를 DDS 포맷으로 자동으로 변환해 주는 배치 파일이나 툴을 만드는 것도 괜찮을 거 같습니다. 플랫폼과 일대일로 대응하는 포맷을 미리 리소스로 만드는 작업은 콘솔 플랫폼에서는 거의 필수적인 일입니다. 



etds님의 DDS사용에 대한 제안. 


- DXTn을 썼을 때의 장점 
1. 메모리를 꽤 적게 쓴다. (또 메모리 대역폭도 아낄 수 있다.) 
2. 대부분의 비디오카드가 하드웨어 가속을 지원하므로 성능 저하가 없다. 
3. 메모리를 적게 쓰는데 비해 퀄리티가 나쁘지 않다. 특히, 노이즈 같은 주파수가 높은 텍스쳐들에 효율적이다. 
(반대로 그라데이션같은 느낌의 텍스쳐에서는 계단이 눈에 띄게 보인다. 그래서 편법을 쓰지 않으면 노말맵에 쓰기에도 별로 좋지 않다.) 

제가 사용하는 DXTn 사용시 가이드라인은, 
1. 알파채널이 없는 경우 무조건 Opaque DXT1을 쓴다. (칼라는 4단계로 보간) 
2. 알파채널이 있지만 alpha testing의 용도로 쓰는 경우 1bit alpha DXT1을 쓴다. (이 경우 칼라가 3단계로 보간되므로 Opaque DXT1보다 약간 퀄리티가 떨어져 보일 수 있다.) 
3. 알파채널이 중요한 경우 DXT3을 쓴다. (칼라는 4단계로 보간되고 알파는 4비트로 표현) 
4. 알파채널이 그라데이션 스타일인 경우 DXT5를 쓴다. (칼라는 4단계로 보간되고 알파는 8단계로 보간) 
5. 그래픽 디자이너가 이상하다고 하는 경우나, GUI에 쓰이는 글씨 이미지 같은 경우 jpg 또는 tga를 그냥 쓴다. 

이분의 경우 소속된 회사에서 서비스하고 있는 온라인 게임에서 보통 3번째까지 적용하면 대부분 문제가 없었고, 이펙트 등에 쓰이는 알파가 중요하게 들어간 텍스쳐만 4번째까지 적용하곤 했다합니다. 그래픽 디자이너들과의 의견 조율 및 절충으로 5번까지 가는 경우는 생각보다 드물었다고 합니다. 



그외 DDS에 관한 참고가 될만한 이야기. 



비회원으로 로그인 하신분의 글. 



DDS 포맷의 태생은 S3사의 S3TC인데 당시 이 포맷이 나왔을 때에는 비디오메모리가 많이 부족한 시절(4M, 8M)이었고 S3 Savage에서는 S3TC 하드웨어 가속이 가능했었습니다. 또, 당시 DX에서는 지금처럼 기본 텍스춰 포맷으로 지원하지 않고 있었습니다. 당시 가장 좋은(?) 그래픽카드였던 Voodoo2의 경우에는 S3TC의 위력을 보여주기 위해 만든 데모와 같은 고 퀄리티의 화면을 높은 프레임으로 구현하기가 힘들었죠.. 아마도 현재는 이 기술이 모든 그래픽카드에서 가속을 지원한다고 추론해 보았을 때(실제 DDS포맷 용량 그대로 비디오메모리에 올릴 수 있습니다) 

DDS의 장점은 손실압축이지만, 일반 포맷에 비해 상대적으로 비디오메모리를 아낄 수 있고, 많은 개수의 텍스춰, 큰 크기의 텍스춰를 낮은 코스트로 사용할 수 있을 것..만 같습니다. 정확한건 벤치마킹을 해봐야 겠죠. DDS의 압축 특성상 사용해야 할 곳은 색들이 고르게 분포된 텍스춰일 것이고요.. 가장 좋은 예로는 지형 텍스춰들일 것이고, MMORPG의 경우 캐릭터들은 대부분 3인칭에서 보므로, 줌인시의 퀄리티가 HDTV처럼 땀구멍까지 보이게 할 필요도 없으므로 캐릭터 텍스춰에도 적절히 쓸 수 있을 것 같습니다. myevan님이 지적해 주신 UI같은 경우, 매번 줌인(?)되서 보이는 텍스춰 인데다가, DDS의 특성상 주위 픽셀에 따라 색이 많이 왜곡되고, width, height이 낮은 pixel의 텍스춰도 찍어야 되는 상황이 많으므로 DDS를 사용하지 않는 것이 좋겠네요.. 



자료를 좀 더 찾아보니, 처음에 S3사가 S3TC포맷을 Savage사에서 개발하자, 3DFX에서 FXT1라는 
포맷을 만들었다고 합니다. 그러자 S3사가 이 포맷을 NVIDIA, ATI에게 라이센스 해줌과 동시에 DX에서 공식적으로 지원하게 되었답니다. S3TC와 FXT1에 대한 URL이기는 하지만, 퀄리티가 어떻게 나빠지나에 대해 참고가 될 것 입니다. 

http://www.digit-life.com/articles/reviews3tcfxt1/

반응형
반응형


[2007.12.15] 파티클 (Particle)  Direct3D Study 

2007/12/15 23:12

복사http://blog.naver.com/csm3138/110025403677


파티클(Particle)

- 파티클이란, 아주 작은 입자들로서 게임화면에서 눈, 비, 폭발, 연기등의 특수한 효과를 구현하기

  위하여 사용하는 점단위 입자를 말한다.

- 파티클은 매우 작은 입자이며 하나의 점(point)로 모델링이 이루어진다.

- D3DPRIMITIVETYPE에서 점을 그리는 인자값은 D3DPT_POINTLIST(점단위 렌더링) 이다.

   그러나 파티클을 표현하기 위해서는 D3DPT_POINTSPRITE를 사용한다. D3DPT_POINTSPRITE를

   사용하는 이유는 똑같은 점단위 렌더링을 하지만 POINTSPRITE는 텍스처의 적용이 가능하며,

   크기또한 변경이 가능하기 때문이다.

 

파티클 점(point)를 구성하는 구조체

 strucr   Particle

{

      D3DXVECTOR3   pos;            // 파티클 점의 위치

      D3DCOLOR        color;          // 파티클의 컬러값

      static  const  DWORD  FVF;   // 플래그 값

};

const DWORD Particle::FVF = D3DFVF_XYZ|D3DFVF_DIFFUSE;

-> 이 구조체는 파티클의 한점의 정보를 저장하는 구조체이다. 기본적으로 점의 3차원 위치와

     컬러값, 플래그값을 가지고 있다.

     여기에 부동소수점 변수(float형)를 추가하면 파티클의 크기를 지정할수 있다. 파티클의 크기의

     변경은 직접하기보다는 렌더 상태에서 파티클의 크기를 제어해 주어야 한다. 이유는 직접

     파티클 크기를 변경을 지원하지 않는 그래픽 카드도 있기 때문이다.

 

파티클의 크기지정 변수를 추가한 구조체

struct Particle

{

      D3DXVECTOR3   pos;

      D3DCOLOR        color;

      float                  size;        // 파티클의 크기

      static  const  DWORD  FVF;

};

const  DWORD  Particle::FVF = D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_PSIZE;

-> 플래그값도 하나 더 추가하여 준다. D3DFVF_PSIZE

 

포인트 스프라이트 렌더 상태

- 포인트 스프라이트의 동작들은 거의 대부분 렌더 상태에 의하여 제어된다.

  -> SetRenderState()

 

D3DRS_POINTSPRITEENABLE

- 텍스처 매핑에 이용할 텍스처의 형태를 지정하여준다.

- 값은 bool값으로 true, false 값이다.

true : 현재 지정된 전체 텍스처를 포인트 스프라이트 텍스처 매핑에 사용한다.

false : 스프라이트 텍스처 좌표로 지정한(스프라이트 이미지 좌표값에서) 텍셀을 이용하여 포인트

          스프라이트의 텍스처를 입힌다.

(ex) m_pDevice->SetRenterState(D3DRS_POINTSPRITEENABLE, true);

 

D3DRS_POINTSCALEENABLE

- 포인트의 크기를 뷰 또는 스크린 스페이스 단위로 해석지정을 한다.

true : 포인트의 크기를 뷰스페이스 단위로 해석 지정

false : 포인트 크기를 스크린 스페이스 단위로 해석 지정

(ex) m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true);

 

D3DRS_POINTSIZE

- 포인트 스프라이트의 크기를 지정하여준다.

(ex) m_pDevice->SetRender(D3DRS_POINTSIZE, (크기 DWORD));

 

D3DRS_POINTSIZE_MIN

D3DRS_POINTSIZE_MAX

- 포인트 스프라이트의 최대 크기와 최소 크기를 지정하여 준다.

(ex) m_pDevice->SetRenderState(D3DPT_POINTSIZE_MIN, (크기 DWORD));

       m_pDevice->SetRenderState(D3DPT_POINTSIZE_MAX, (크기 DWORD));

 

D3DRS_POINTSCALE_A

D3DRS_POINTSCALE_B

D3DRS_POINTSCALE_C

- 거리에 따른 포인트 스프라이트의 크기를 제어 한다.

- 최종적인 포인트 스프라이트의 크기는

 이다.

   - ViewportHeight : 뷰포트의 높이

   - A, B, C : SCALE의 값

   - D : 뷰 스페이스(카메라 좌표)내의 포인트 스프라이트와 카메라 위치와의 거리

 

파티클과 파티클의 속성들

- 파티클은 위치와 컬러 이외에도 많은 속성들로 이루어져 있다.

- 파티클을 렌더링할때 필요한 데이터와 속성들은 Particle 구조체가 아닌 Attribute 구조체에 따로

  보관하며, 렌더링할 준비가 완료되면 Particle 구조체로 위치와 속성을 복사하여 사용한다.

- 파티클의 속성은 모델링하려는 파티클 시스템의 종류에 따라 달라진다.

- 다음의 구조체는 몇 가지의 공통적인 파티클 속성을 포함하고 있다.

 struct Attribute

{

        D3DXVECTOR3  pos;                  // 월드 스페이스 내의 파티클의 위치

        D3DXVECTOR3  velocity;             // 파티클의 이동속도, 초당 이동단위

        D3DXVECTOR3  acceleration;      // 파티클의 가속도, 초당 이동단위

        D3DXVECTOR3  lifetime;              // 파티클의 생존시간

        D3DXVECTOR3  age;                  // 파티클의 나이(???)

        D3DXVECTOR3  color;                // 파티클의 컬러

        D3DXVECTOR3  colorfade;          // 파티클의 컬러가 시간의 흐름에 따라 변하는 방법

        D3DXVECTOR3  isalive;              // 파티클 생존유무!! 생존 true, 소멸 false

};

 

 

 

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

포샵에서 DDS파일 만들기(2)  (0) 2013.01.31
포샵에서 DDS파일 만들기(1)  (0) 2013.01.31
용책, 해골책  (0) 2013.01.31
간략한 파티클 시스템  (0) 2013.01.31
파티클 간단한 렌더링  (0) 2013.01.31
반응형

http://www.cyworld.com/romejune/


이 블로그에서 용책과 해골책의 소스를 거진 올려놓음 음;;;; 그래도 되나? ㅋ

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

포샵에서 DDS파일 만들기(1)  (0) 2013.01.31
Direct 에서 파티클 SetRenderState 설정 설명  (0) 2013.01.31
간략한 파티클 시스템  (0) 2013.01.31
파티클 간단한 렌더링  (0) 2013.01.31
CommitChanges  (0) 2013.01.27
반응형


http://www.cyworld.com/romejune/5142517


//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: pSystem.h
//
// Author: Frank Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0
//
// Desc: Represents a geneal particle system.
//         
//////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __pSystemH__
#define __pSystemH__

#include "d3dUtility.h"
#include "camera.h"
#include <list>


namespace psys
{
 ////파티클의 위치와 컬러를 표현하는 데의 구조체 포맷.
 struct Particle
 {
  D3DXVECTOR3 _position;
  D3DCOLOR    _color;
  static const DWORD FVF;
 };
 
 struct Attribute
 {
  Attribute()
  {
   _lifeTime = 0.0f;
   _age      = 0.0f;
   _isAlive  = true;
  }

  // 파티클과 파티클의 속성들.
  
  // 파티클을 렌더링하는데 필요한 데이터와 파티클 속성을 별도의 구조체 내에 보관하게 되는데,
  // 파티클을 만들고 파괴하고 갱신할 때는 바로 이러한 속성을 이용해 작업하는 것이며,
  // 이를 렌더링할 준비가 완료되면 Particle 구조체로 위치와 속성을 복사해 이용.

  D3DXVECTOR3 _position;     // 월드 스페이스 내의 파티클 위치.
  D3DXVECTOR3 _velocity;     // 파티클의 속도, 보통은 초당 이동 단위로 기록.
  D3DXVECTOR3 _acceleration; // 파티클의 가속. 보통은 초당 이동 단위로 기록.
  float       _lifeTime;     // 파티클이 소멸할 때까지 유지되는 시간.
                                // 예, 레이저 빔 파티클은 특정한 시간동안만 유지.
  
float       _age;          // 파티클의 현재 나이
  D3DXCOLOR   _color;        // 파티클의 컬러
  D3DXCOLOR   _colorFade;    // 파티클의 컬러가 시간의 흐름에 따라 퇴색하는 방법
  bool        _isAlive;    // 파티클이 생존한 경우 true, 소멸한 경우 false
 };

 

 // 파티클 시스템의 요소들.
 
 // 파티클 시스템은 파티클들의 모임이며 파티클을 보여주고 관리하는 역할을 담당한다.
 // 파티클의 크기나 파티클 원천의 위치, 파티클에 적용할 텍스처 등
 // 시스템 내의 모든 파티클에 영향을 주는 전역 특성들을 관리.
 // 기능적 관점에서 보면
 // 파티클 갱신과 디스플레이, 소멸, 생성 등을 관장하는 역할.

 class PSystem
 {
 public:
  // 디폴트 값을 초기화하는 생성자와
  // 장치 인터페이스 (버텍스 버퍼, 텍스처)를 해제하는 디스트럭터
  PSystem();
  virtual ~PSystem();

 

  // init - 포인트 스프라이트를 저장하기 위한 버텍스 버퍼를 만들고
  // 텍스처를 만드는 등의 Direct3D의 장치 의존적인 초기화 작업을 처리.
  
virtual bool init(IDirect3DDevice9* device, char* texFileName);
  
  // 시스템 내의 모든 파티클 속성을 리셋.
  virtual void reset();
  
  virtual void resetParticle(Attribute* attribute) = 0;

  

// 시스템에 파티클을 추가.
  virtual void addParticle();

 

 // 시스템 내의 모든 파티클들을 갱신.
  virtual void update(float timeDelta) = 0;

 

 // 렌더링에 앞서 지정해야 할 초기 렌더 상태를 지정.
  // 이 메서드는 시스템에 따라 달라질 수 있으므로 가상 함수로 선언.
  virtual void preRender();

 

  // 시스템 내의 모든 파티클들을 렌더링
  virtual void render();

 

  // 특정 파티클 시스템이 지정했을 수 있는 렌더 상태를 복구하는 데 이용.
  // 이 메서드는 시스템에 따라 달라질 수 있으므로 가상 메서드로 선언.
  virtual void postRender();

 

  // 현재 시스템에 파티클이 없는 경우 true 리턴.
  bool isEmpty();

  

// 시스템 내의 파티클이 모두 죽은 경우 true 리턴.
  bool isDead();

 

protected:
  // 속성 리스트 _particle을 검색하여 죽은 파티클을 리스트에서 제거.
  virtual void removeDeadParticles();

 protected:
  IDirect3DDevice9*       _device;
  D3DXVECTOR3             _origin;  // 시스템의 원천, 시스템 내에서 파티클이 시작되는 곳.
  d3d::BoundingBox        _boundingBox;  // 파티클이 이동할 수 있는 부피를 제한하는 데 이용.
  // 예, 산 정상을 둘러싼 지역에만 눈이 오는 시스템.
  // 원하는 영역을 경계상자로 정의하면 이 영역을 벗어난 파티클들을 곧바로 소멸.
  float                   _emitRate;   // 시스템에 새로운 파티클이 추가되는 비율. 보통은 초당 파티클 수로 기록.
  float                   _size;       // 시스템 내 모든 파티클의 크기
  IDirect3DTexture9*      _tex;
  IDirect3DVertexBuffer9* _vb;
  std::list<Attribute>    _particles;  // 시스템 내 파티클 속성의 리스트.

  // 우리는 파티클을 만들고 제거하고 갱신하는 데 이 리스트를 이용.
  // 파티클을 그릴 준비가 완료되면
  // 리스트 노드의 일부를 버텍스 버퍼로 복사하고
  // 파티클 드로잉 과정을 거친다.
  // 이어 다음 단계의 데이터를 복사하고 다시 파티클을 그리며,
  // 모든 파티클을 그릴 때까지 이 과정을 반복.

 

  int                     _maxParticles; // 주어진 시간 동안 시스템이 가질 수 있는 최대 파티클의 수.
  // 예, 파티클이 파괴되는 속도보다 만들어지는 속도가 빠르다면
  // 엄청나게 많은 수의 파티클이 동시에 존재할 수 있다.
  // 이 멤버는 이와 같은 상황을 막는다.

 

  DWORD _vbSize;      // 버텍스 버퍼가 보관할 수 있는 파티클의 수.
  // 이 값은 실제 파티클 시스템 내의 파티클 수와는 독립적.
  DWORD _vbOffset;    // 파티클 시스템의 렌더링에 이용.
  DWORD _vbBatchSize; // 파티클 시스템의 렌더링에 이용.
 };

 

 // 눈
 class Snow : public PSystem
 {
 public:
  // 생성자
  // 경계 상자 구조체를 가리키는 포인터와 시스템 내 파티클의 수
  // 경계 상자는 눈송이가 떨어질 부피를 정의하며,
  // 만약 눈송이가 이 범위 밖으로 벗어 나면 즉시 소멸하고 다시 만들어짐.
  // 항상 같은 수의 파티클을 유지.
  Snow(d3d::BoundingBox* boundingBox, int numParticles);
  void resetParticle(Attribute* attribute);
  void update(float timeDelta);
 };

 // 불꽃놀이
 class Firework : public PSystem
 {
 public:
  Firework(D3DXVECTOR3* origin, int numParticles);
  void resetParticle(Attribute* attribute);
  void update(float timeDelta);
  void preRender();
  void postRender();
 };

 // 입자총
 class ParticleGun : public PSystem
 {
 public:
  ParticleGun(Camera* camera);
  void resetParticle(Attribute* attribute);
  void update(float timeDelta);
 private:
  Camera* _camera;
 };
}

#endif // __pSystemH__

 

//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: pSystem.cpp
//
// Author: Frank Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0
//
// Desc: Represents a geneal particle system.
//         
//////////////////////////////////////////////////////////////////////////////////////////////////

#include <cstdlib>
#include "pSystem.h"

using namespace psys;

const DWORD Particle::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

// 초기화하는 생성자
PSystem::PSystem() 
{
 _device = 0;
 _vb     = 0; //버텍스 버퍼
 _tex    = 0; //텍스처
}

 

// 인터페이스 해제하는 디스트럭터
PSystem::~PSystem()
{
 d3d::Release<IDirect3DVertexBuffer9*>(_vb);
 d3d::Release<IDirect3DTexture9*>(_tex);
}

 

// init - 포인트 스프라이트를 저장하기 위한 버텍스 버퍼를 만들고
// 텍스처를 만드는 등의 Direct3D의 장치 의존적인 초기화 작업을 처리.
bool PSystem::init(IDirect3DDevice9* device, char* texFileName)
{
 // 우리는 동적 버텍스 버퍼를 이용할 것임.
 // 매 프레임 마다 파티클을 갱신해야 하며 이는 곧 버텍스 버퍼의 메모리에 접근해야 함을 의미.
 // 정적 버텍스 버퍼로의 접근 속도는 상당히 느리다는 데 주의.
 // 동적 버텍스 버퍼를 이용하는 것은 바로 이 때문.
 _device = device; 

 HRESULT hr = 0;

 hr = device->CreateVertexBuffer(
  // 버텍스 버퍼 크기가 _viSize에 의해 미리 정의되며
  // 시스템 내의 파티클 수와는 관련이 없음을 주의.
  _vbSize * sizeof(Particle),
  // 버텍스 버퍼가 포인트 스프라이트를 보관할 것임을 지정하는 D3DUSAGE_POINTS를 이용.
  D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, 
  Particle::FVF,
  // 동적 버텍스 버퍼는 관리 메모리 풀에 보관할 수 없으므로 디폴트 메모리 풀을 이용.
  D3DPOOL_DEFAULT,
  &_vb,
  0);
 
 if(FAILED(hr))
 {
  ::MessageBox(0, "CreateVertexBuffer() - FAILED", "PSystem", 0);
  return false;
 }

 hr = D3DXCreateTextureFromFile(
  device,
  texFileName,
  &_tex);

 if(FAILED(hr))
 {
  ::MessageBox(0, "D3DXCreateTextureFromFile() - FAILED", "PSystem", 0);
  return false;
 }

 return true;
}

 

// 시스템 내의 모든 파티클 속성을 리셋.
void PSystem::reset()
{
 std::list<Attribute>::iterator i;
 for(i = _particles.begin(); i != _particles.end(); i++)
 {
  // 한 파티클의 속성을 리셋.
  // 파티클의 속성이 리셋되는 방식은 파티클 시스템에 따라 달라짐.
  // 따라서 하위 클래스에서 메서드를 구현하도록 추상 메서드로 선언.
  resetParticle( &(*i) );
 }
}

// 시스템에 파티클을 추가.
// 이 메서드는 리스트에 추가 하기전에 파티클을 초기화 하는데 resetPaticle 메서드를 이용.
void PSystem::addParticle()
{
 Attribute attribute;

 resetParticle(&attribute);

 _particles.push_back(attribute);
}

// 포인트 스프라이트 렌더 상태.
void PSystem::preRender()
{
 _device->SetRenderState(D3DRS_LIGHTING, false);

 // 현재 지정된 전체 텍스처를 포인트 스프라이트의 텍스처 매핑에 이용할것임을 의미.
 _device->SetRenderState(D3DRS_POINTSPRITEENABLE, true);

 // 포인트 크기를 뷰 스페이스 단위로 해석하도록 지정.
 // 뷰 스페이스 단위는 간단히 카메라 공간 내의 3D 포인트를 나타내며,
 // 포인트 스프라이트의 크기는 카메라와의 거리에 따라 적절하게 조정됨.
 // 즉, 카메라와 멀리 떨어진 파티클은 가까운 파티클에 비해작게 나타남.
 _device->SetRenderState(D3DRS_POINTSCALEENABLE, true);

 // 포인트 스프라이트의 크기를 지정.
 // 이 값은 D3DRS_POINTSCALEENABLE 상태 값에 따라서 뷰 스페이스 내의 크기나
 // 스크린 스페이스 내의 크기로 해석.
 // FtoDw 함수는 float을 DWORD로 형 변환한다.
 // 이 함수가 필요한 것은 일반적인 IDirect3DDevice9::SetRenderState 호출이
 // float이 아닌 DWORD를 필요로 하기 때문.
 _device->SetRenderState(D3DRS_POINTSIZE, d3d::FtoDw(_size));

 

 // 포인트 스프라이트의 지정할 수 있는 최소 크기를 지정.
 _device->SetRenderState(D3DRS_POINTSIZE_MIN, d3d::FtoDw(0.0f));

 

// 이 세 개의 상수는 거리에 따라 포인트 스프라이트의 크기가 변하는 방법을 제어.
 // 여기에서 말하는 거리란 카메라와 포인트 스프라이트 간의 거리.
 _device->SetRenderState(D3DRS_POINTSCALE_A, d3d::FtoDw(0.0f));
 _device->SetRenderState(D3DRS_POINTSCALE_B, d3d::FtoDw(0.0f));
 _device->SetRenderState(D3DRS_POINTSCALE_C, d3d::FtoDw(1.0f));
  
 // 텍스처의 알파를 이용.
 _device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
 _device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

 

 // 알파 블렌딩을 활성화하여 텍스처의 알파 채널이 텍스처의 픽셀 투명도를 결정하도록 했음.
 // 이를 통해 다양한 효과를 얻을 수 있으며,
 // 가장 대표적인 것이 사각형이 아닌 다른 파티클 형태를 구현 하는 것.
 // 예, "눈덩이와 비슷한" 둥근 파티클을 얻기 위해서는
 // 흰색의 원형과 검은색의 알파 채널을 갖는 흰색 텍스처를 이용하면 됨.
 // 이렇게 하면 사각형의 흰색 텍스처 전체가아닌 흰색 원 모양의 파티클을 만들 수 있다.
 _device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
 _device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    _device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
}

 

// 특정 파티클 시스템이 지정했을 수 있는 렌더 상태를 복구하는 데 이용.
// 이 메서드는 시스템에 따라 달라질 수 있으므로 가상 메서드로 선언.
void PSystem::postRender()
{
 _device->SetRenderState(D3DRS_LIGHTING,          true);
 _device->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
 _device->SetRenderState(D3DRS_POINTSCALEENABLE,  false);
 _device->SetRenderState(D3DRS_ALPHABLENDENABLE,  false);
}

 

// 렌더링 메서드
void PSystem::render()
{
 //
 // Remarks:  The render method works by filling a section of the vertex buffer with data,
 //           then we render that section.  While that section is rendering we lock a new
 //           section and begin to fill that section.  Once that sections filled we render it.
 //           This process continues until all the particles have been drawn.  The benifit
 //           of this method is that we keep the video card and the CPU busy. 

 if( !_particles.empty() )
 {
  //렌더 상태를 지정.
  preRender();
  
  _device->SetTexture(0, _tex);
  _device->SetFVF(Particle::FVF);
  _device->SetStreamSource(0, _vb, 0, sizeof(Particle));


  // render batches one by one
  //

  // 버텍스 버퍼를 벗어날 경우 처음부터 시작한다.
  
  // _vbOffset - 버텍스 버퍼에서 복사를 시작할 파티클 내 다음 단계로의 오프셋(바이트가 아닌 파티클 단위)
  // 예, 단계 1이 0부터 499까지 항목이라면 단계 2로의 오프셋은 500이 된다.
  if(_vbOffset >= _vbSize)
   _vbOffset = 0;

  Particle* v = 0;

  // _vbBatchSize - 하나의 단계에 정의된 파티클의 수.
  _vb->Lock(
   _vbOffset    * sizeof( Particle ),
   _vbBatchSize * sizeof( Particle ),
   (void**)&v,
   _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);

  DWORD numParticlesInBatch = 0;

 

  // 모든 파티클이 렌더링될 때까지
  //
  std::list<Attribute>::iterator i;
  for(i = _particles.begin(); i != _particles.end(); i++)
  {
   if( i->_isAlive )
   {

    // 한단계의 생존한 파티클을다음 버텍스 버퍼 세그먼트로 복사.
    //
    v->_position = i->_position;
    v->_color    = (D3DCOLOR)i->_color;
    v++; // next element;

    numParticlesInBatch++; //단계 카운터를 증가시킨다.

    // 현재 단계가 모두 채워져 있는가?
    if(numParticlesInBatch == _vbBatchSize)
    {
     //
     // 버텍스 버퍼로 복사된 마지막 단계의 파티클들을 그린다.
     //
     _vb->Unlock();

     _device->DrawPrimitive(
      D3DPT_POINTLIST,
      _vbOffset,
      _vbBatchSize);

     //
     // 단계가 그려지는 동안 다음 단계를 파티클로 채운다.
     //

     // 다음 단계의 처음 오프셋으로 이동한다.
     _vbOffset += _vbBatchSize;

 

     // 버텍스 버퍼의 경계를 넘는메모리로 오프셋을 설정하지 않는다.
     // 경계를 넘을 경우 처음부터 시작.
     if(_vbOffset >= _vbSize)
      _vbOffset = 0;      

     _vb->Lock(
      _vbOffset    * sizeof( Particle ),
      _vbBatchSize * sizeof( Particle ),
      (void**)&v,
      _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);

     numParticlesInBatch = 0; // 다음 단계를 위한 리셋
    } 
   }
  }

  _vb->Unlock();

 

  // (numParticlesInBatch == _vbBatchSize) 조건이
  // 만족되지 못하여 마지막 단계가 렌더링되지 않는 경우가 발생할 수 있다.
  // 일부만 채워진 단계는 바로 이곳에서 렌더링 된다.
  
  if( numParticlesInBatch )
  {
   _device->DrawPrimitive(
    D3DPT_POINTLIST,
    _vbOffset,
    numParticlesInBatch);
  }

  // 다음 블록
  _vbOffset += _vbBatchSize;

  //
  // reset render states
  //

  postRender();
 }
}

// 현재 시스템에 파티클이 없는 경우 true 리턴.
bool PSystem::isEmpty()
{
 return _particles.empty();
}

 

// 시스템 내의 파티클이 모두 죽은 경우 true 리턴.
// 모든 파티클이 죽은 상태와 시스템이 빈 상태를 혼동하지 않도록.
// 빈 상태는 시스템 내에 파티클이 없는 상태를 의미
// 죽은 상태는 파티클이 존재하지만 죽은 것으로 표시된 상태를 의미.
bool PSystem::isDead()
{
 std::list<Attribute>::iterator i;
 for(i = _particles.begin(); i != _particles.end(); i++)
 {
  // is there at least one living particle?  If yes,
  // the system is not dead.
  if( i->_isAlive )
   return false;
 }
 // no living particles found, the system must be dead.
 return true;
}

 

// 속성 리스트 _particle을 검색하여 죽은 파티클을 리스트에서 제거.
void PSystem::removeDeadParticles()
{
 std::list<Attribute>::iterator i;

 i = _particles.begin();

 while( i != _particles.end() )
 {
  if( i->_isAlive == false )
  {
   // erase는 다음 반복자를 리턴하므로
      // 우리가 반복자를 증가시킬 필요가 없다.
   i = _particles.erase(i);
  }
  else
  {
   i++; // next in list
  }
 }
}

//*****************************************************************************
// Snow System
//***************

// 생성자
  // 경계 상자 구조체를 가리키는 포인터와 시스템 내 파티클의 수
  // 경계 상자는 눈송이가 떨어질 부피를 정의하며,
  // 만약 눈송이가 이 범위 밖으로 벗어 나면 즉시 소멸하고 다시 만들어짐.
  // 항상 같은 수의 파티클을 유지.
Snow::Snow(d3d::BoundingBox* boundingBox, int numParticles)
{   
 _boundingBox   = *boundingBox;
 _size          = 0.25f;
 _vbSize        = 2048;  // 버텍스 버퍼의 크기
 _vbOffset      = 0;   // 시작 오프셋
 _vbBatchSize   = 512;
 
 for(int i = 0; i < numParticles; i++)
  addParticle();
}

 

// 한 파티클의 속성을 리셋.
// 파티클의 속성이 리셋되는 방식은 파티클 시스템에 따라 달라짐.
// 따라서 하위 클래스에서 메서드를 구현하도록 추상 메서드로 선

// 경계 상자 내 임의의 x와 z좌표 위치에서 눈송이를 만들고
// y좌표를 경계 상자의 최상단과 같도록 지정.
// 이어 눈송이에 속도를 부여하여 아래 방향으로 그리고 약간 왼쪽으로 떨어지도록 한다.
// 눈송이는 흰색으로 표현.
void Snow::resetParticle(Attribute* attribute)
{
 attribute->_isAlive  = true;

 

// GetRandomVector - 최소점 min과 최대점 max로 정의된 상자 내의 임의 벡터를 출력.
 // 눈송이의 위치 지정을 위해 임의의 x, z 좌표를 얻는다.
 d3d::GetRandomVector(
  &attribute->_position,
  &_boundingBox._min,
  &_boundingBox._max);

 

// 높이 (y좌표) 는 항상 경계 상자의 최상단.
 
attribute->_position.y = _boundingBox._max.y;

 

// GetRandowFloat - [ lowBound, highBound ] 범위에 있는 임의의 float을 리턴.
 // 눈송이는 아래쪽으로 떨어지며 약간 왼쪽을 향한다.
 attribute->_velocity.x = d3d::GetRandomFloat(0.0f, 1.0f) * -3.0f;
 attribute->_velocity.y = d3d::GetRandomFloat(0.0f, 1.0f) * -10.0f;
 attribute->_velocity.z = 0.0f;

 

// 흰색의 눈송이
 
attribute->_color = d3d::WHITE;
}

 

// 시스템 내의 모든 파티클들을 갱신.
// 메서드의 구현은 특정 파티클 시스템에 따라 달라지므로
// 하위 클래스에서 메서드를 구현하도록 추상 메서드로 선언.

// 파티클의 위치를 갱신하며
// 시스템의 경계 상자를 벗어났는지 확인.
// 만약 경계 상자를 벗어났다면 해당 파티클을 초기화.
void Snow::update(float timeDelta)
{
 std::list<Attribute>::iterator i;
 for(i = _particles.begin(); i != _particles.end(); i++)
 {
  i->_position += i->_velocity * timeDelta;

  

// 포인트가 경계를 벗어났는가?
  
if( _boundingBox.isPointInside( i->_position ) == false )
  {
   // 경계를 벗어난 파티클을 재활용.
   resetParticle( &(*i) );
  }
 }
}

//*****************************************************************************
// Explosion System
//********************

// 불꽃놀이 생성자
// 시스템 원천(불꽃이 폭발할 장소) 으로의 포인터, 시스템이 가진 파티클의 수.
Firework::Firework(D3DXVECTOR3* origin, int numParticles)
{
 _origin        = *origin;
 _size          = 0.9f;
 _vbSize        = 2048;
 _vbOffset      = 0;  
 _vbBatchSize   = 512;

 for(int i = 0; i < numParticles; i++)
  addParticle();
}

 

// 시스템 원천의 파티클을 초기화하고 구체 내에서 임의의 속도를 만들며,
// 시스템 내의 파티클들은 임의의 컬러를 부여.
// 각 파티클들이 2초 동안 유지하도록 수명을 지정.
void Firework::resetParticle(Attribute* attribute)
{
 attribute->_isAlive  = true;
 attribute->_position = _origin;

 D3DXVECTOR3 min = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
 D3DXVECTOR3 max = D3DXVECTOR3( 1.0f,  1.0f,  1.0f);

 d3d::GetRandomVector(
  &attribute->_velocity,
  &min,
  &max);

 

// 구체를 만들기 위한 정규화
 
D3DXVec3Normalize(
  &attribute->_velocity,
  &attribute->_velocity);

 attribute->_velocity *= 100.0f;

 attribute->_color = D3DXCOLOR(
  d3d::GetRandomFloat(0.0f, 1.0f),
  d3d::GetRandomFloat(0.0f, 1.0f),
  d3d::GetRandomFloat(0.0f, 1.0f),
  1.0f);

 attribute->_age      = 0.0f;
 attribute->_lifeTime = 2.0f; // 2초 동안의 수명을 가진다.
}

 

// 각 파티클의 위치를 갱신하고 수명을 초과한파티클의 죽음을 처리.
// 이 시스템은 죽은 파티클을 제거하지 않는다.
// 이것은 새로운 불꽃을 만들 때 기존의 죽은 Firework 시스템을 재활용할 수 있기 때문.
// 즉, 파티클을 만들고 제거하는 번거로운 과정을 최소화.
void Firework::update(float timeDelta)
{
 std::list<Attribute>::iterator i;

 for(i = _particles.begin(); i != _particles.end(); i++)
 {
  // 생존한 파티클만 갱신.
  if( i->_isAlive )
  {
   i->_position += i->_velocity * timeDelta;

   i->_age += timeDelta;

   if(i->_age > i->_lifeTime) // 죽인다.
    i->_isAlive = false;
  }
 }
}

 

// 렌더링에 앞서 지정해야 할 초기 렌더 상태를 지정.
// 이 메서드는 시스템에 따라 달라질 수 있으므로 가상 함수로 선언.

// 다른 블렌드 인수가 이용.
// 깊이 버퍼로의 쓰기도 허용되지 않음.
// 디폴트 블렌드 인수와 쓰기 여부를 변경하고자 한다면
// pSystem::preRender와 pSystem::postRender 메서드를 오버라이드하면 됨.
void Firework::preRender()
{
 PSystem::preRender(); // 부모 버전의 메서드를 호출.

 _device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
    _device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

 // z 버퍼 읽기는 가능 하지만 쓰기는 허용하지 않는다.
 _device->SetRenderState(D3DRS_ZWRITEENABLE, false);
}

void Firework::postRender()
{
 PSystem::postRender();

 _device->SetRenderState(D3DRS_ZWRITEENABLE, true);
}

//*****************************************************************************
// Laser System
//****************
// 입자총 생성자

// 카메라로의 포인터를 받는다.
// 새로운 파티클을 만들 때마다 카메라의 위치와 방향에 대한 정보가 필요.
ParticleGun::ParticleGun(Camera* camera) 
{   
 _camera          = camera;
 _size            = 0.8f;
 _vbSize          = 2048;
 _vbOffset        = 0; 
 _vbBatchSize     = 512;
}

 

// 파티클의 위치를 카메라의 현재 위치로 지정하고
// 파티클의 속도를 카메라가 보고 있는 방향의 100배로 지정.
// 이 같은 방법으로 현재 바라보고 있는 방향으로 "총알"을 발사할 수 있다.
// 파티클의 컬러는 녹색으로 지정.
void ParticleGun::resetParticle(Attribute* attribute)
{
 attribute->_isAlive  = true;

 D3DXVECTOR3 cameraPos;
 _camera->getPosition(&cameraPos);

 D3DXVECTOR3 cameraDir;
 _camera->getLook(&cameraDir);

 

// 파티클 위치에 카메라 위치를 이용.
 attribute->_position = cameraPos;
 attribute->_position.y -= 1.0f; // 카메라보다 약간 아래쪽으로 이동해
                          // 총을 들고 있는 것 같은 효과를 얻는다.

 // 카메라가 바라보는 방향으로 발사한다.
 attribute->_velocity = cameraDir * 100.0f;

 

 // 녹색
 attribute->_color = D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f);

 attribute->_age      = 0.0f;
 attribute->_lifeTime = 1.0f; // 수명은 1초
}

 

// 파티클의 위치를 갱신하고
// 수명이 다한 경우 죽은 것으로 처리한다.
// 파티클 리스트를 검색하여 죽은 파티클을 제거.
void ParticleGun::update(float timeDelta)
{
 std::list<Attribute>::iterator i;

 for(i = _particles.begin(); i != _particles.end(); i++)
 {
  i->_position += i->_velocity * timeDelta;

  i->_age += timeDelta;

  if(i->_age > i->_lifeTime) // kill
   i->_isAlive = false;
 }
 removeDeadParticles();
}

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

Direct 에서 파티클 SetRenderState 설정 설명  (0) 2013.01.31
용책, 해골책  (0) 2013.01.31
파티클 간단한 렌더링  (0) 2013.01.31
CommitChanges  (0) 2013.01.27
Effect::CommitChanges()  (0) 2013.01.25
반응형


http://blog.naver.com/clous02?Redirect=Log&logNo=110023903727



1) 파티클의 버텍스 버퍼이용 방법

* 버텍스 버퍼정의(최대한의 일정한 사이즈로)

* 파티클의 속성을 다룰 구조체를 정의

   * 구조체 리스트에 이벤트나 최대 숫자의 개수를 정하고 소멸시 하나를 생성하는 방법으로 생성

* 속성에 존재하는 베텍스 데이터 자료를 버텍스 버퍼로 동적인 복사

* 파티클에 관련된 RenderState를 설정

* 렌더링한다.


2) 작동방식

* FVF의 지정: D3DFVF_XYZ | D3DFVF_PSIZE

* Particle 속성을 위한 구조체

: 동적인 버텍스 생성과 소멸  List

* 위치 한계의 최대 사이즈 결정

* 버텍스 버퍼 마련

* 파티클을 생성(총알은 속도 일정 위치 변경)

* 버텍스 버퍼에 이동

* 파티클의 생성  변경  소멸  생성의 과정

* 렌더링 : DrawPrimitive(D3DPT_POINTLIST)

 

3) 파티클 구현 방법

* Particle

  - Bilboard이용 파티클 구현(사각형)

  - D3DPT_POINTLIST : 하나의 픽셀로 렌더링된다

  - Point Sprite(점하나로 가능)

 Texture 적용이 가능  Blending으로 알파 연산

• 크기 변경 가능

• 하나의 포인트로 사용가능

• 성능향상과 메모리 이익

 

4) 파티클의 종류

* 일정한 사이즈로 반복 되는 현상

  - 눈 비등

        - 박스속에 거두고 충돌처리로 사망을 시키면서 사망이 하나라도 벌어지면 자동으로 생성

           한다

 - 파티클정보를 담고 있는 리스트에서 erase시키고 push_back한다

* 이벤트가 발생하면 생성되는 스타일

 - 버텍스 버퍼는 가능한 총알의 최대 사이즈를 지정

 - 속성리스트를 만들고 렌더링해야할 만큼  버텍스 버퍼에 지정하고 렌더링한다

 - 이벤트 발생시 생성

 - 카메라의 위치에서 카메라의 방향으로 발사

 - 일정한 위치를 전진하면 소멸

 - 생성  변경  소멸의 단계

* 두가지 방식다

 - 위치의 속성은 계속하여 변화함으로 일정한 사이즈로 만들어 놓은 버텍스 버퍼에

위치값을 계속하여 갱신한다

5) 파티클에서 주의할 점

* 파티클 사이즈 조정시 주의할 점

  - 렌더스테이트의 사이즈 조정은 모두 DWORD

  - 이벤트에 의하여 파티클이 증가할 경우 조정하지 않으면 버텍스 버퍼의 한계를 초가하는 경우가 발생

  - 눈이 한 개만 출력될 때는 인덱스 증가가 벌어지지 않기 때문

 

6) Point Sprite 렌더 상태

 * D3DRS_POINTSPRITEENABE : default  false

  - true : 지정된 전체 텍스트를 포인트 스프라이트에 텍스쳐 매핑

  - false : 포인트 스프라이트의 텍스쳐 좌표를 이용하여 지정

 * D3DRS_POINTSCALEENABLE : default  false

  - true : 포인트 크기를 뷰스페이스 단위로 해석(카메라와의 거리값에 따라 변화)

  - false : 스크린 스페이스 단위로 해석  사이즈를 3으로 주면 3x3 사이즈로 그려진다

 * D3DRS_POINTSIZE

  - 포인트 스프라이트 크기 지정

  - Device->SetRenderState(D3DRS_POINTSIZE, FtoDw(2.5f));

    DWORD FtoDw(float f)

{

  return *((DWORD*)&f);

}

 * D3DRS_POINTSIZE_MIN : 0.2

 * D3DRS_POINTSIZE_MAX : 5.0

 * 거리에 따라 포인트 스프라이드의 크기가 변화하는 방법을 제어

 * D3DRS_POINTSIZE_A

 * D3DRS_POINTSIZE_B

 * D3DRS_POINTSIZE_C

[출처] 파티클|작성자 clous02

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

용책, 해골책  (0) 2013.01.31
간략한 파티클 시스템  (0) 2013.01.31
CommitChanges  (0) 2013.01.27
Effect::CommitChanges()  (0) 2013.01.25
모션 블러(Motion Blur)  (0) 2013.01.25
반응형

CommitChanges 




현재 테크닉에서 ID3DXEffect::BeginPass/ID3DXEffect::EndPass  가 매칭되는 내부에서  ID3DXEffect::Set~ 함수를 쓰지 않았다면


ID3DXEffect::CommitChanges 를 할필요가 없고 BeginPass,  EndPass 내부에서 ID3DXEffect::Set~ 함수가 쓰인다면 



ID3DXEffect::CommitChanges   ID3DXEffect::BeginPass/ID3DXEffect::EndPass 이 매칭되는 사이에 반드시 호출해야하는데

반드시 DrawxPrimitive 호출하기 전에 ID3DXEffect::CommitChanges 를 호출해야 한다


안에 쓰는것과 밖에 쓰는것은 좀 다른데 밖에쓰면 상관없지만 내부에다 쓰면 공유되는 상태가 되어 다음에까지 영향을 미친다



- 아래는 Direct SDK 에서 발췌한 내용이다






Remarks

If the application changes any effect state using any of the ID3DXEffect::Setx methods inside of an ID3DXEffect::BeginPass/ID3DXEffect::EndPass matching pair, the application must call ID3DXEffect::CommitChanges before any DrawxPrimitive call to propagate state changes to the device before rendering. If no state changes occur within a ID3DXEffect::BeginPass and ID3DXEffect::EndPass matching pair, it is not necessary to call ID3DXEffect::CommitChanges.


This is slightly different for any shared parameters in a cloned effect. When a technique is active on a cloned effect (that is, when ID3DXEffect::Begin has been called but and ID3DXEffect::End has not been called), ID3DXEffect::CommitChanges updates parameters that are not shared as expected. To update a shared parameter (only for a cloned effect whose technique is active), call ID3DXEffect::End to deactivate the technique and ID3DXEffect::Begin to reactivate the technique before calling ID3DXEffect::CommitChanges.





    // Using current technique

    // Begin           starts active technique

    // BeginPass       begins a pass

    // CommitChanges   updates changes to any set calls in the pass. This should be called before any DrawPrimitive call to d3d

    // EndPass         ends a pass

    // End             ends active technique


이건  에 대한 d3dx9effect.h 에 있는 설명 에 있다


반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

간략한 파티클 시스템  (0) 2013.01.31
파티클 간단한 렌더링  (0) 2013.01.31
Effect::CommitChanges()  (0) 2013.01.25
모션 블러(Motion Blur)  (0) 2013.01.25
인스턴싱 (Instancing)  (1) 2013.01.25
반응형


Effect::CommitChanges()  

2006/04/24 20:33

복사http://blog.naver.com/medrian5/20023521146


Effect::BeginPass(0);

.....

Effect::SetTexture(ha, paaaa);

Effect::SetTexture(hb, pbbbb);

....

Effect::EndPass();

 

만약, BeginPass(int)와 EndPass() 사이에서

한번의 Effect::SetTexture() 함수가 호출된 뒤, 또다시 Effect::SetTexture가 호출 되면

Effect::CommitChanges();

 

아래처럼  이녀석을 호출해야 제대로 먹힌다.

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

Effect::BeginPass(0);

.....

Effect::SetTexture(ha, paaaa);

Effect::SetTexture(hb, pbbbb);

Effect::CommitChanges();

....

Effect::EndPass();

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

파티클 간단한 렌더링  (0) 2013.01.31
CommitChanges  (0) 2013.01.27
모션 블러(Motion Blur)  (0) 2013.01.25
인스턴싱 (Instancing)  (1) 2013.01.25
D3DXCreateTextureFromFile 함수  (0) 2013.01.22
반응형


모션 블러(Motion Blur)  3D Programming / Programming 

2012/05/14 00:39

복사http://blog.naver.com/sorkelf/40158984437







즉 위 설명은 아래와 같다.

속도벡터 = 현재위치 이전위치

최종 위치 = dot법선,  속도벡터  ) > 0 ? 현재위치 이전위치

이걸 버텍스 셰이더에서 그대로 구현하면..

  //현재의 버텍스 좌표

   float4 NewPos = mul( Pos, m_WVPNew );

   //과거의 버텍스 좌표
   float4 OldPos = mul( Pos, m_WVPOld );

   //버텍스의 속도벡터
   float3 Dir = NewPos.xyz - OldPos.xyz;

   // 버텍스의 이동벡터와 법선을 내적
   float a = dot( normalize( Dir ), normalize( N ) );

   //최종 위치 계산
   if( a < 0.0f )
      Out.Pos = OldPos;
   else
      Out.Pos = NewPos;


이동궤적 볼륨이 반투명으로 렌더링 되므로 깊이 버퍼를 사용하면 볼륨의 다른 부분이 깊이테스트에서 실패하므로 렌더링되지 않는다

그리고 얼마나 이동했는지 계산한다
다음 텍스처 샘플링 위치를 옮기기 위해 투영공간에서의 속도벡터를 구하고 이를 텍스처 좌표계에 맞도록
스케일링 한 것을 출력한다 (투영공간의 범위가 ~1-1 이므로 스케일링에 0.5배가 필요하며 y좌표가 반대이므로 -1을 곱해줌)


현재위치 mul(현재위치,m_WVP);

이전위치 mul(이전위치, m_prevWVP);


속도 = 현재위치 이전위치 / w * 0.5f;

속도.y *= -1.0f


이걸 버텍스 셰이더에서 그대로 구현하면..

  //-1.0f 부터 1.0f 의 범위를 텍스처 좌표계의 0.0f ~ 1.0f의 텍셀 위치를 참조하기 위해 거리를 절반으로 한다

  float2  velocity =  NewPos.xy / NewPos.w - OldPos.xy / OldPos.w;

  Out.Dir.xy =  velocity  * 0.5f;

   //최종적으로 텍셀의 오프셋값이 되기 위해 y방향을 반대방향으로 한다
   Out.Dir.y *= -1.0f;

   //씬의 Z값을 계산하기 위한 파라미터
   Out.Dir.z = Out.Pos.z;
   Out.Dir.w = Out.Pos.w;

 

   return Out;


여기까지가 버텍스 셰이더가 하는 일이다




이동궤적 지오메트리와  깊이 정보

픽셀 셰이더에서는 이동궤적 볼륨에서의 각각 화면좌표위치(In.Tex/In.Tex.w)로부터 속도방향(In.Velocity)로 조금씩 옮기고
오브젝트만을 렌더링한 텍스처를 샘플링한다.
마지막으로 합계한 결과를 샘플 수로 나누어 평균 색을 구한다.

 float4 PS_Final( VS_Final_OUTPUT In ) : COLOR0

{

   //수치를 크게 하면 크게 할수록 부드러움
   int  NumBlurSample = 10;

   //속도 맵으로부터 속도벡터와 Z값을 얻어옴
   float4 Velocity = tex2D( tex1, In.Tex );

   Velocity.xy /= (float)Blur;

   int cnt = 1;
   float4 BColor;

   // 씬의 렌더링 이미지를 얻어옴, a 성분에 Z 값을 저장된다
   float4 Out = tex2D( tex0, In.Tex );

   for( int i=cnt; i NumBlurSample  ; i++ )
   {
      //속도 벡터의 방향 텍셀 위치를 참조하여, 씬의 렌더링 이미지의 색정보를 얻어온다
      BColor = tex2D( tex0, In.Tex + Velocity.xy * (float)i );

      //속도 맵의 Z 값과 속도 벡터 방향에 있는 텍셀 위치를 샘플링 한 씬의 렌더링 이미지의 Z값을 비교한다
      if( Velocity.a < BColor.a + 0.04f )
      {
         cnt++;
         Out += BColor;
      }
   }

   Out /= (float)cnt;

   return Out;
}





샘플 수를 늘리면 좀 더 부드러운 느낌을 낼 수 있지만 렌더링 속도가 느려지므로 샘플 수는 적당히 타협하는 것이 좋다.


이 때

  //속도 맵의 Z 값과 속도 벡터 방향에 있는 텍셀 위치를 샘플링 한 씬의 렌더링 이미지의 Z값을 비교한다
      if( Velocity.a < BColor.a + 0.04f )
      {
         cnt++;
         Out += BColor;
      }

이 부분에서 Z값을 비교해 블러처리를 할 것인가 말것인가를 하는데 
이는 모델 경계상 에서의 생기는 아티팩트를 없애기 위한 것으로

아래 그림 처럼 뒤의 물체가 모션 블러 될때 앞의 물체에 모션블러 결과가 묻어 나는 것을 방지하기 위한 처리로
Z값을 참조하여 앞의 물체인지 뒤의 물체인지 판단후 앞의 물체이면 샘플링 할때 제외 하는 것이다.




일반적인 샘플링 시..

Z값을 고려하여 처리 한 결과

그 외 2.5D 모션 블러의 단점으로 

이동궤적 볼륨이 파괴(같은 버텍스 좌표에서 법선방향이 다른 모델에서 발생)
같은 변을 공유하며 법선방향이 다른 변에 대해서 폴리곤을 미리 생성하여
폴리곤을 늘릴때(이동궤적 볼륨을 만들때) 추가로 렌더링 하는 방식으로 해결 하며




지오메트리 비용 증가(이동궤적볼륨 있음 + 없음 으로 인한 추가모델을 2번 렌더링)
씬은 정적이고 멀리 있는 오브젝트는 크게 영향을 받지 않으며 카메라에 의한 변화만 의존한다고 가정하고
Z버퍼와 스크린 좌표만을 가지고 Velocity를 계산하는 방식으로 해결한다 (알고리즘은 아래와 같음)

  1. 스크린 좌표와 Z버퍼의 값으로부터 픽셀의 월드 좌표를 역산
  2. 월드 좌표를 1 프레임전의 뷰 프로젝션 행렬로 변환하여 1프레임 전의 스크린 좌표를 계산
  3. 현재 스크린 좌표와 1프레임 전의 스크린 좌표 로부터 Velocity를 계산



DX10이상일 경우에는 지오메트리 셰이더에서 Velocity를 참조하여 폴리곤을 잡아 늘리거나 폴리곤을 생성하는 방식을 사용한다
더 자세한건 DX 10 Sample Browser에 있는 Motion Blur 10내용을 참고하길 바란다.


DX10에서의 모션블러시 생성되는 원리



Reference : 

DirectX9 쉐이더 프로그래밍(타카시 이마기레)
CEDEC 2006 차세대기에 대응하는 게임 엔진 설계 CapCom

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

CommitChanges  (0) 2013.01.27
Effect::CommitChanges()  (0) 2013.01.25
인스턴싱 (Instancing)  (1) 2013.01.25
D3DXCreateTextureFromFile 함수  (0) 2013.01.22
다중스트림 셰이더  (0) 2013.01.21
반응형

 

2012/05/30 13:28

복사http://blog.naver.com/sorkelf/40160183951


인스턴싱 (Instancing)

 : 동일한 객체(오브젝트)를 한 화면에 여러개를 렌더링 시킬 경우에 한번의 DP Call로 처리 하는 방식을 말한다.
   (나무, 풀, 스프라이트, 파티클 등등..)








즉 50개 메시 -> Dp Call 50번 이 아닌 
    50개 메시 -> DP Call 1번으로 처리한다는 것이며 이는 DpCall에 따른 오버헤드를 줄여준다



DirectX SDK에서는 4가지 방식의 인스턴싱 방식을 제시하고 있다
(이 외에 XBox에서는 VFetch 인스턴싱을 사용한다 )

1. 하드웨어 인스턴싱
 : VS_3_0이 필요하며 인스턴싱에 필요한 데이터를
세컨드 버텍스 버퍼에 저장하는 형식이다.

2. 셰이더 인스턴싱
 : 하드웨어인스턴싱이 불가능할 경우 사용하는 가장 효율적인 방식이다
인스턴싱 데이터는 시스템 메모리 배열에 저장된 후 렌더링시 버텍스 셰이더의
Constant에 카피 한다. VS_2_0일 경우 최대가 256개 vs_1_1에서는 최대 96개이다
그러므로 많은 수의 인스턴싱 데이터의 배열 전체를 한번에 처리하는것은 불가능하다

3. Contant 인스턴싱
  셰이더인스턴싱처리로 하지 않을 경우(배치사이즈=1)와 유사하다

4. 스트림 인스턴싱
 : 하드웨어 인스턴싱과 마찬가지로 세컨드 버텍스 버퍼를 사용한다
단, 버텍스 셰이더의 Constant를 설정해서 각 박스의 위치와 색을 갱신하는 것이 아닌
인스턴스 스트림 버퍼 내에 오프셋을 갱신해서 박스를 하나씩 렌더링한다



이 중에서 하드웨어 인스턴싱을 다룬다.. 
( 요샌 3.0 지원하는 카드 많으니까...ㅠㅠ 나중에 시간이 또 되면 셰이더 인스턴싱 설명도 넣어야지..-_-)


하드웨어 인스턴싱은 작업은 전적으로 GPU상에서 수행되며 CPU 사용량은 거의 없다

하드웨어 인스턴싱은 현재 데이터 구조를 변경하지 않는 대신
세컨드 버텍스 버퍼라고 불리는 또 다른 버텍스 버퍼를 추가한다



세컨드 버텍스 버퍼에는 변환행렬 정보등이 저장되어 있으며 인스턴스 하나당 하나씩 포함된다
또한 원래의 메인 버텍스 버퍼와는 다른 녀석이므로 버텍스버퍼 사이즈를 둘다 동일하게 유지할 필요도 없으며
한번에 DP Call로 얼마나 많은 인스턴싱을 할 것인가에 따라 최대 사이즈가 커지게 된다



소스 설명 주저리 주저리...

우선 메인 버텍스 버퍼와 세컨드 버텍스 버퍼에 들어갈 버텍스를 선언한다

 //메인 버텍스 버퍼에 들어갈 버텍스 선언

const D3DVERTEXELEMENT9 g_VBDecl_Geometry[] =
{
    {0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
    {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0},
    {0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
    {0, 48, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
    D3DDECL_END()
};

//세컨드 버텍스 버퍼에 들어갈 버텍스 선언
const D3DVERTEXELEMENT9 g_VBDecl_InstanceData[] =
{
    {1, 0,  D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
    {1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
    {1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3},
    {1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4},
    {1, 64, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0},
    D3DDECL_END()
};

첫번째 선언은 위치 법선, 탄젠트, 종법선, 및 텍스처 좌표 데이터들로 지오메트리 데이터 를 정의하며
2번째 선언은 오브젝트 인스턴스 별 데이터를 정의한다

2번째 선언에서를 보면 여기서는 각 인스턴스가 4개의 float4형 부동소수점 값 및 4성분 컬러에 의해 정의되고 있다.

처음의 4개의 값은 4x4 행렬의 초기화에 사용할 수 있으며 이 데이터는 각 지오메트리의 
인스턴스 사이즈, 위치, 방향등을 한번에 처리한다

렌더링 하기 전에 IDirect3DDevice9::SetStreamSourceFreq 를 호출하여 버텍스 버퍼의 스트림을 디바이스의 바인드해야 한다
바인드 하는 방법은 아래와 같다

//스트림 0으로 세팅 되어있는 메인 버텍스 버퍼 바인드

//g_NumBoxes 는 출력할 인스턴싱 데이터 개수
pd3dDevice->SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | g_NumBoxes );
pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof( BOX_VERTEX ) );

//스트림 1로 세팅 되어있는 세컨드 버텍스 버퍼 바인드
//버텍스당 하나의 인스턴싱 데이터를 가지므로 1과 바인드한다
pd3dDevice->SetStreamSourceFreq( 1, D3DSTREAMSOURCE_INSTANCEDATA | 1ul );
pd3dDevice->SetStreamSource( 1, g_pVBInstanceData, 0, sizeof( BOX_INSTANCEDATA_POS ) );

여기서 BOX_VERTEX 는 기존의 버텍스 구조이며 는 BOX_INSTANCEDATA_POS 는 인스턴싱데이터를 가진 구조체이다

IDirect3DDevice9::SetStreamSourceFreq 는 D3DSTREAMSOURCE_INDEXEDDATA를 가지고
인덱스에 따른 지오메트리 데이터를 식별한다

우선 첫번째로 스트림0에 설정된 버텍스 버퍼(메인 버텍스 버퍼)를 바인드 하는데
위와 같이 인스턴싱 데이터 개수만큼 D3DSTREAMSOURCE_INDEXEDDATA와 or 연산하여 설정하면 
렌더링하는 지오메트리의 인스턴스값이 논리적으로 결합된다

다음 스트림1에 설정된 버텍스 버퍼(세컨드 버텍스 버퍼)를 바인드 하는데
이번에는 IDirect3DDevice9::SetStreamSourceFreq 가 D3DSTREAMSOURCE_INSTANCEDATA를 가지고 
인스턴싱 데이터를 포함한 스트림을 식별한다.
이때에 각 버텍스는 하나의 인스턴스 데이터를 포함하므로 D3DSTREAMSOURCE_INSTANCEDATA  1과 결합한다

그리고 IDirect3DDevice9::SetStreamSource를 호출하여 버텍스버퍼 포인터를 디바이스에 바인드 후 렌더링한다


렌더링 종료후...

인스턴싱 데이터 렌더링이 종료되면 버텍스 스트림의 Frequency를 원래대로 돌려주어야 한다

pd3dDevice->SetStreamSourceFreq( 0, 1 );

pd3dDevice->SetStreamSourceFreq( 1, 1 );


즉 렌더의 로직은 아래와 같다

 void OnRenderHWInstancing( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )

{
    HRESULT hr;
    UINT iPass, cPasses;

    //버텍스 선언 세팅
    V( pd3dDevice->SetVertexDeclaration( g_pVertexDeclHardware ) );

    //스트림 0으로 세팅 되어있는 메인 버텍스 버퍼 바인드
    //g_NumBoxes 는 출력할 인스턴싱 데이터 개수
    V( pd3dDevice->SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | g_NumBoxes ) );
    V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof( BOX_VERTEX ) ) );

    //스트림 1로 세팅 되어있는 세컨드 버텍스 버퍼 바인드 
    //버텍스당 하나의 인스턴싱 데이터를 가지므로 1과 바인드한다
    V( pd3dDevice->SetStreamSourceFreq( 1, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
    V( pd3dDevice->SetStreamSource( 1, g_pVBInstanceData, 0, sizeof( BOX_INSTANCEDATA_POS ) ) );

    //인덱스 버퍼 설정
    V( pd3dDevice->SetIndices( g_pIBBox ) );

    // 테크닉 설정
    V( g_pEffect->SetTechnique( g_HandleTechnique ) );

    V( g_pEffect->Begin( &cPasses, 0 ) );
    for( iPass = 0; iPass < cPasses; iPass++ )
    {
        V( g_pEffect->BeginPass( iPass ) );

        V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );

        //BeginPass 와 EndPass 사이에서 호출 필요!
        V( g_pEffect->CommitChanges() );

        V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) );

        V( g_pEffect->EndPass() );
    }


    V( g_pEffect->End() );

    //스트림 설정 원래대로
    V( pd3dDevice->SetStreamSourceFreq( 0, 1 ) );
    V( pd3dDevice->SetStreamSourceFreq( 1, 1 ) );
}


이 때 BeginPass와 EndPass 사이에 연속적으로 SetTexture를 하거나 할 경우
CommitChanges()를 부르지 않으면 이펙트에 바로 적용되지 않는다

BeginPass 와 EndPass 하수 특성상 EndPass가 실행되기 전 까지
다음 스테이트로 넘어가지 않고 계속 호출하게 되어 
제일 마지막에 설정한 부분에 모두 출력하게 된다.

CommitChanges()는 렌더링함수 (DrawSubSetDrawPrimitive 계열등)을 부르기 전에 호출해야 한다

또한 위에서도 설명했듯이 버텍스버퍼의 사이즈가 커지면 더 느려질 수도 있으니
노가다를 통해 적절한 버텍스버퍼의 크기를 찾는것이 중요하다-..-



반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

Effect::CommitChanges()  (0) 2013.01.25
모션 블러(Motion Blur)  (0) 2013.01.25
D3DXCreateTextureFromFile 함수  (0) 2013.01.22
다중스트림 셰이더  (0) 2013.01.21
D3DVERTEXELEMENT9 사용법  (0) 2013.01.21

+ Recent posts