Texture Operation

SlimDX로 텍스쳐 작업하는 샘플 코드입니다.


텍스쳐를 합성하는 경우 검색해보면, texture stage를 통해 레이어 간의 작업을 지정하는 예제가 대부분입니다. 그러나 갱신이 자주 되지않는 텍스쳐의 경우, 합성된 텍스쳐 자체를 가지고 있으면 텍스쳐 간의 컨텍스트 스위칭이라든지의 비용이 적게 들 것이므로 유리하다고 생각됩니다.

색이 잘못된 것은 아니고, 테스트해보면서 구분을 위해 
일부러 색이 다른 텍스쳐를 로딩한 것입니다.
안면은 PasteSurface함수, 수염과 머리카락은 
PasteAlphaTexture를 사용했습니다.

alpha값이 들어있지 않은 일반적인 텍스쳐의 경우 D3DX의 함수를 내부적으로 호출해주기 때문에 상당히 간단하게 처리됩니다.

 void PasteSurface(Device^ device, String^ blpFilepath, Surface^ targetSurface, Rectangle targetRect)
 {
  Texture^ tempTexture = GoblinBlpFile::FromFile(device, blpFilepath);
  Surface^ tempSurface = tempTexture->GetSurfaceLevel(0);

  Surface::FromSurface(targetSurface, tempSurface, Filter::Linear, 0, Rectangle(0, 0, tempSurface->Description.Width, tempSurface->Description.Height), targetRect);

  delete tempSurface;
  delete tempTexture;
 }

alpha값이 들어있는 경우, 테스트를 해보니 위의 방식으로는 alpha값이 날아가버립니다. 일단은 무식하게 lock걸고 alpha값까지 일일이 복사해버리지만, 그래도 생성시에 한번만 돌아가므로 생각보다 부하가 크진 않을 것 같습니다.

 void PasteAlphaTexture(Texture^ sourceTexture, Texture^ targetTexture, Rectangle targetRect)
 {  
  DataRectangle^ srcRect = sourceTexture->LockRectangle(0, LockFlags::Discard);
  DataRectangle^ tgtRect = targetTexture->LockRectangle(0, LockFlags::Discard);
  int tgtRectWidth = tgtRect->Pitch / 4;

  unsigned int pixel;
  for (int j = 0; j < targetRect.Height; j++)
   for (int i = 0; i < targetRect.Width; i++) {
    //pixel = srcRect->Data->Read<unsigned int>();
    Byte b = srcRect->Data->ReadByte();
    Byte g = srcRect->Data->ReadByte();
    Byte r = srcRect->Data->ReadByte();
    Byte a = srcRect->Data->ReadByte();
    Byte tb = tgtRect->Data->ReadByte();
    Byte tg = tgtRect->Data->ReadByte();
    Byte tr = tgtRect->Data->ReadByte();
    Byte ta = tgtRect->Data->ReadByte();
    float alpha = a / 255.0f;
    float invAlpha = 1.0f - alpha;

    r = (Byte)((r * alpha) + (tr * invAlpha));
    g = (Byte)((g * alpha) + (tg * invAlpha));
    b = (Byte)((b * alpha) + (tb * invAlpha));
    a = 0xff;
    pixel = (a << 24) + (r << 16) + (g << 8) + b;

    tgtRect->Data->Position = (tgtRectWidth * (j + targetRect.Y) + i + targetRect.X) * 4;
    tgtRect->Data->Write<unsigned int>(pixel);    
   }

  sourceTexture->UnlockRectangle(0);
  targetTexture->UnlockRectangle(0);
 }

0 개의 댓글:

댓글 쓰기