반응형

http://magic-finger.tistory.com/28

[HLSL] DX9 Effect에서 pass함수 변경사항.

최근에 DX9가 업데이트되면서 HLSL Effect의 패스호출 함수인 ID3DXEffec::Pass(UINT* UPass)가
ID3DXEffect::BeginPass(UINT* UPass) ID3DXEffect::EndPass();로 변경되었습니다.
대부분 D3D9책에서는 
ID3DXEffec::Pass(UINT* UPass)로 나왔을거에요.(현재 사용하고 있는 2010버전엔 없더라구요.) 
위 두 함수사이에 렌더함수를 호출하면되는데 문제는 우리가 원하는 결과가 아니라는겁니다.
문제의 원인이 되는 부분은 바로 BeginPass와 EndPass함수로서 BeginPass함수의 특성상 EndPass가 실행되기 전까지 다음 스테이트로 넘어가지않고 계속 호출하게되어 나중엔 제일 마지막에 설정한 부분에 모두 출력하게된다는 것이죠.
그렇담 여기서 몇가지 해결방법을 생각해볼 수 있겠군요.

첫번쩨로 렌더링함수를 호출할 때마다 BeginPass와 EndPass를 호출하는방법입니다. 이렇게하면 네군데에 물체가 잘나옵니다만 물체가 출력되는 결과물을 보니 원하는 순서가 아니네요? 맨 마지막에 출력되야할 물체가 맨 첫번째로 가있고, 맨처음 출력해야할 물체가 맨마지막으로 가있다는 사실을 발견할 수가 있어요. 이 방법이 해결된다고해도 반복되는 코드가 많아서 코드가 쓸때없이 길어지고 수십번이상 반복되는 코드라면 골치가 아파집니다. ㅋㅋ 어휴 

[첫번째 방법 소스코드]
ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[0]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[0]);
                Mesh[0]->DrawSubset(0);  
  
ToonEffect->EndPass();

ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[1]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[1]);
                Mesh[1]->DrawSubset(0);  
  
ToonEffect->EndPass();

ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[2]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[2]);
                Mesh[2]->DrawSubset(0);  
  
ToonEffect->EndPass();

ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[3]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[3]);
                Mesh[3]->DrawSubset(0);  
  
ToonEffect->EndPass();



두번째 방법으로 반복되는 코드를 예전과 같이 루프로 묶고 루프 안에 Begin/End Pass를 넣는 방법으로 생각해봅니다.

[두번째 방법 소스코드]
Device->Begin();

UINT Pass;
        ToonEffect->Begin(&Pass, 0);
        for(int j = 0 ; j < Pass ; j++)
        {
            
            for(int i = 0 ; i < 4 ; i++)
            {        
                ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[i]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[i]);
                Mesh[i]->DrawSubset(0); 

                ToonEffect->EndPass();   
            }
            
        }
        ToonEffect->End();

Device->End();


이렇게하면 매 루프때마다 Begin/End Pass를 호출해서 매 스테이트마다 넘어가겠지만 결과는 첫번째 방법과 동일하다는 것을 알 수가 있습니다.  

이것도 안된다 저것도 안된다...
정녕 해결방법은 없는 것일까요?

아직 포기하기엔 이릅니다! 
DirectX를 만든 MS에서 위 두 함수를 새로 만들었으면 두 함수를 책임을 져야하는 함수를 따로 안만들었을리는 없겠지요.
그것이 바로 ID3DXEffect::CommitChanges()함수입니다. 이를 이용하는 겁니다. 이 문제점의 해결방법이기도하구요.
위 함수를 렌더링함수를 불러오기 전에 호출해봅니다. (꼭 렌더링함수 호출 전에 호출해야합니다. 안그러면 첫번째나 두번째처럼 순서가 뒤바뀝니다.)

[해결방법 소스코드]
//호출순서 : 디바이스의 Begin > 이펙트의 Begin(이펙트 내의 패스 수 리턴) > 이팩트의 BeginPass(패스 수만큼 루프를 돈다)
Device->Begin();

UINT Pass;
        ToonEffect->Begin(&Pass, 0);
        for(int j = 0 ; j < Pass ; j++)
        {
            ToonEffect->BeginPass(j);
            for(int i = 0 ; i < 4 ; i++)
            {        
                ToonEffect->SetMatrix(hWorldMatrix, &World[i]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[i]);
                ToonEffect->CommitChanges(); //BeginPass호출 시 그리기 전에 반드시 이 함수 호출
                Mesh[i]->DrawSubset(0);    
            }
            ToonEffect->EndPass();
        }
        ToonEffect->End();

Device->End();


결과가 어떤가요? 원하는 결과가 잘 출력되었나요?
BeginPass와 EndPass를 사용하게되면(특히 반복해서 렌더링하는 함수가 존재할 경우) CommitChanges함수도 같이 사용해야한다는 사실 잊지마세요.

ID3DXEffect::CommitChanges()호출 전

ID3DXEffect::CommitChanges()호출 후

샘플은 카툰렌더링기법입니다.

반응형

+ Recent posts