XNA의 SpriteBatch는 정확히 어떻게 작동합니까?


38

더 정확하게 말하면, 다른 API (예 : OpenGL)에서이 기능을 처음부터 다시 작성해야한다면 무엇을 할 수 있을까요?

직교 투영 행렬을 준비하고 각 그리기 호출에 대해 쿼드를 만드는 방법과 같은 일부 단계에 대한 일반적인 아이디어가 있습니다.

그러나 배치 프로세스 자체에는 익숙하지 않습니다. 모든 쿼드가 동일한 정점 버퍼에 저장됩니까? 인덱스 버퍼가 필요합니까? 다른 텍스처는 어떻게 처리됩니까?

가능하면 SpriteBatch.Begin ()이 호출 될 때부터 SpriteBatch.End ()까지, 적어도 기본 지연 모드를 사용할 때 프로세스를 안내해 주시면 감사하겠습니다.


OpenGL을 통해 MonoGame에서 어떻게 구현되는지 살펴보십시오 : github.com/mono/MonoGame/blob/master/MonoGame.Framework/…
Den

Microsoft.Xna.Graphics에서 DotPeek 또는 Reflector를 사용하려고 했습니까 (하지만 불법적 인 작업은 제안하지 않습니다).
Den

링크 주셔서 감사합니다. 그리고 그 생각이 저를 가로 지르고 있었지만 (여기에는 dotPeek도 있습니다), 이미 그 일을 이미하고 메모리로 절차를 알고있는 누군가에게 일반적인 설명을 요구하는 것이 더 좋은 아이디어라고 생각했습니다. 그런 식으로 대답은 여기에 보존되어 다른 사람들이 이용할 수있게됩니다. 아무도 그러한 설명을 제공하지 않는 경우, 나는 분석을 직접하고 내 자신의 질문에 대한 답변을 게시 할 것이지만, 조금 더 기다릴 것입니다.
David Gouveia

그래, 내가 댓글을 사용한 이유야. Andrew Russell이이 질문에 대답하기에 좋은 사람이라고 생각합니다. 그는이 커뮤니티에서 활발히 활동하고 있으며 MonoGame의 대안 인 andrewrussell.net/exen과 같은 ExEn에서 일하고 있습니다.
Den

예, 이것은 Andrew Russel (또는 Shawn Hargreaves가 XNA 포럼에서 다시 방문)이 일반적으로 많은 통찰력을 제공 할 수있는 질문입니다.
David Gouveia

답변:


42

나는 작업중 인 크로스 플랫폼 엔진에 대해 지연 모드에서 SpriteBatch의 동작을 복제 했으므로 지금까지 리버스 엔지니어링 된 단계는 다음과 같습니다.

  1. 생성자의 SpriteBatch : 생성 DynamicIndexBuffer, DynamicVertexBuffer및 배열 VertexPositionColorTexture고정 사이즈 (이 경우 최대 크기의 배치 - 대 정점 스프라이트 2048 및 8192).

    • 인덱스 버퍼는 그릴 쿼드의 정점 인덱스로 채워집니다 (0-1-2, 0-2-3, 4-5-6, 4-6-7 등).
    • 내부 SpriteInfo구조체 배열 도 생성됩니다. 배치 할 때 사용할 시간 스프라이트 설정이 저장됩니다.
  2. SpriteBatch.Begin은 : 내부 값 저장 BlendState, SamplerState그것이없이 두 번 호출되었는지 지정 등을 점검 SpriteBatch.End사이.

  3. SpriteBatch.Draw : 모든 스프라이트 정보 (텍스처, 위치, 색상)를 가져 와서에 복사합니다 SpriteInfo. 최대 배치 크기에 도달하면 새 스프라이트를위한 공간을 만들기 위해 전체 배치가 그려집니다.

    • SpriteBatch.DrawStringDraw커닝과 간격을 고려하여 문자열의 각 문자마다 a 를 발행합니다 .
  4. SpriteBatch.End : 다음 작업을 수행합니다.

    • 에 지정된 렌더링 상태를 설정합니다 Begin.
    • 직교 투영 행렬을 만듭니다.
    • SpriteBatch셰이더를 적용합니다 .
    • 바인딩 DynamicVertexBufferDynamicIndexBuffer.
    • 다음 배치 작업을 수행합니다.

      startingOffset = 0;
      currentTexture, oldTexture = null;
      
      // Iterate through all sprites
      foreach SpriteInfo in SpriteBuffer
      {
          // Store sprite index and texture
          spriteIndex = SpriteBuffer.IndexOf(SpriteInfo);
          currentTexture = SpriteInfo.Texture;
      
          // Issue draw call if batch count > 0 and there is a texture change
          if (currentTexture != oldTexture)
          {
              if (spriteIndex > startingOffset)
              {
                  RenderBatch(currentTexture, SpriteBuffer, startingOffset,
                              spriteIndex - startingOffset);
              }
              startingOffset = spriteIndex;
              oldTexture = currentTexture;
          }
      }
      
      // Draw remaining batch and clear the sprite data
      RenderBatch(currentTexture, SpriteBuffer, startingOffset,
                  SpriteBuffer.Count - startingOffset);
      SpriteBuffer.Clear();
      
  5. SpriteBatch.RenderBatch :SpriteInfo 배치에서 각각에 대해 다음 작업을 실행합니다 .

    • 스프라이트의 위치를 ​​취하고 원점과 크기에 따라 4 개의 정점의 최종 위치를 계산합니다. 기존 회전을 적용합니다.
    • UV 좌표를 계산하고 지정된 좌표에 적용합니다 SpriteEffects.
    • 스프라이트 색상을 복사합니다.
    • 그런 다음이 값은 VertexPositionColorTexture이전에 작성된 요소 배열에 저장됩니다 . 모든 스프라이트가 계산되었을 때, SetData온라고 DynamicVertexBuffer하고, DrawIndexedPrimitives전화가 발행됩니다.
    • 정점 셰이더는 변형 작업 만 수행하며 픽셀 셰이더는 텍스처에서 가져온 색상에 색조를 적용합니다.

정확히 내가 필요한 것입니다. 고마워요! 그 모든 것을 흡수하기 위해 조금 나왔지만 마침내 모든 세부 사항을 얻었습니다. 내 관심을 끌었고 이전에 완전히 알지 못했던 것 중 하나는 지연 모드에서도 SpriteBatch를 어떻게 든 정렬 할 수 있다면 Texture에 의해 정렬됩니다 (즉, 이러한 호출 순서에 관심이 없다면). RenderBatch 작업 수를 줄이고 렌더링 속도를 높일 수 있습니다.
David Gouveia

그건 그렇고, 나는 문서에서 찾을 수없는 것 같습니다-버퍼가 가득 차기 전에 할 수있는 Draw 호출의 한계는 무엇입니까? 그리고 DrawText를 호출하면 해당 버퍼가 문자열의 전체 문자 수만큼 채워 집니까?
David Gouveia

감동적인! 엔진을 ExEn 및 MonoGame과 비교하면 어떻습니까? MonoTouch 및 MonoAndroid도 필요합니까? 감사.
Den

@DavidGouveia : 2048 스프라이트는 최대 배치 크기입니다-답변을 편집하고 편의를 위해 추가했습니다. 예, 텍스처별로 정렬하고 z- 버퍼가 스프라이트 순서를 처리하게하려면 최소 드로우 콜을 사용합니다. 필요한 경우 SpriteSortMode.Texture원하는 순서대로 그림을 그려서 SpriteBatch정렬 하도록하십시오 .
r2d2rigo

1
@Den : ExEn 및 MonoGame은 Windows 이외의 플랫폼에서 XNA 코드를 실행할 수있는 하위 수준의 API입니다. 내가 작업중 인 프로젝트는 C #으로 작성된 구성 요소 기반 엔진이지만 시스템 API에 대한 액세스를 제공하려면 매우 얇은 계층이 필요합니다. 우리는 SpriteBatch편의 를 위해 다시 구현 하기로 결정했습니다 . 그렇습니다. 모두 C #이므로 MonoTouch / MonoDroid가 필요합니다!
r2d2rigo

13

XNA SpriteBatch 코드가 DirectX로 포팅되었고 XNA 팀의 이전 멤버에 의해 OSS로 릴리스되었음을 지적하고 싶습니다. XNA 에서 어떻게 작동하는지 정확히 보려면 여기로 가십시오.


"나는 사용하지하지만 재미 없을거야 코드는 대충 다룬"에 대한 한
카일 바란

네이티브 C ++ 인 XNA SpriteBatch의 최신 버전은 GitHub h / cpp 에서 찾을 수 있습니다 . 보너스로 DirectX12 버전도 이용할 수 있습니다. h / cpp
Chuck Walbourn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.