[C#] 텍스처를 평평한 3D 오브젝트로 그려서 깊이를 모방 할 때 검은 선이 무작위로 나타납니다.


Answers

그 마지막 이미지 하단의 바위를보세요. 모래 색깔의 선이 그곳을지나갑니다. 아마, 모래를 먼저 그 다음에 바위를 그립니다.

이는 텍스처를 통해 "검은 선이 그려지는"것이 아니라 텍스처의 일부가 그려지지 않고 있음을 나타냅니다. 수직으로 늘릴 때 발생하기 때문에 새로운 텍스처에서 값을 보간하지 않고 이전 픽셀에서 새 픽셀로 매핑을 만드는 것을 의미합니다.

예를 들어, 맵핑 (x,y) --> (x, 2y) 를 사용하면 포인트는 (0,0) --> (0,0) , (0,1) --> (0,2)(0,2) --> (0, 4) 이다. 원본 텍스처의 점은 (0,1) 또는 (0,3) 매핑되지 않습니다. 이로 인해 배경이 새어 나옵니다. 나는 당신이 수평으로 뻗기 위하여 그것을 바꾼 경우에, 당신은 수직선을 볼 것이다.

당신이해야 할 일은 다른 방법으로 매핑하는 것입니다 : 대상 텍스쳐의 각 픽셀에 대해 위의 변환의 역함수를 사용하여 소스 이미지에서 그 값을 찾으십시오. 아마도 분수 값 픽셀 좌표를 얻을 것이므로 값을 보간 할 것입니다.

나는 XNA에 전혀 익숙하지 않지만 아마도 이것을하기보다 손쉬운 방법이있을 것입니다.

Question

우리는 XNA를 사용하여 하향식 RPG를 개발 중입니다. 최근 우리지도를 표시하는 코드를 작성할 때 우리는 좌절에 부 닥쳤다. 지도를 그릴 때, 정상적인 변환 행렬을 가진 하향식 뷰는 모든 것이 잘된 것처럼 보입니다. 위 또는 아래를 흉내 내기 위해 비평 행 변환 행렬을 사용할 때 카메라가 위치를 바꿀 때 주위를 움직이는 검은 색 선 (위쪽 또는 아래쪽 열, 왼쪽 또는 오른쪽 열이 압착 될 때)이 나타납니다. 이동 및 배치는 무작위로 나타납니다. (이미지가 더 아래로 제공됩니다.)

배경 정보

맵은 타일로 구성됩니다. 원래 텍스처에는 32x32 픽셀로 구성된 타일이 있습니다. 이 삼각형에 2 개의 삼각형을 만들고 원래 텍스처의 일부를 표시하여 타일을 그립니다. 셰이더가 우리를 위해이 작업을 수행합니다. 삼각형의 세 가지 레이어가 있습니다. 먼저 모든 불투명 한 타일과 모든 반투명 및 부분 투명 타일의 모든 불투명 한 픽셀을 그리고 나서 모든 반투명 및 부분 투명 타일과 픽셀을 그립니다. 이것은 잘 동작합니다 (그러나 부동 소수점 인수로 확대 / 축소 할 때 색상 조합 된 선이 타일 행 및 / 또는 열 사이에 있음).

Renderstates

모든 타일에 동일한 래스터 라이저 상태를 사용하고 솔리드 또는 반투명 타일을 드로잉 할 때 두 개를 전환합니다.

_rasterizerState = new RasterizerState();
_rasterizerState.CullMode = CullMode.CullCounterClockwiseFace;

_solidDepthState = new DepthStencilState();
_solidDepthState.DepthBufferEnable = true;
_solidDepthState.DepthBufferWriteEnable = true;

_alphaDepthState = new DepthStencilState();
_alphaDepthState.DepthBufferEnable = true;
_alphaDepthState.DepthBufferWriteEnable = false;

그늘에서 다음과 같이 SpriteBlendMode를 설정합니다.

제 1의 고체 층 (1)은

AlphaBlendEnable = False; 
SrcBlend = One; 
DestBlend = Zero; 

다른 모든 단색 및 투명 레이어 (나중에 그려야 함)는

AlphaBlendEnable = True; 
SrcBlend = SrcAlpha;
DestBlend = InvSrcAlpha; 

다른 쉐이더도 이것을 사용합니다. 사용 된 SpriteFontsSpriteBatch 는 기본 설정을 사용합니다.

생성 된 텍스처

일부 타일은 즉석에서 생성되어 파일로 저장됩니다. 지도가로드되면 파일이로드됩니다. 이것은 다음과 같이 생성 된 RenderTarget 사용하여 수행됩니다 :

RenderTarget2D rt = new RenderTarget2D(sb.GraphicsDevice, 768, 1792, false, 
    SurfaceFormat.Color, DepthFormat.None);
    sb.GraphicsDevice.SetRenderTarget(rt);

파일이 생성되면 파일이 저장되고로드됩니다. 따라서 RenderTarget 에 더 이상 존재하지 않으므로 장치가 재설정 될 때 파일이 손실되지 않습니다. 밉 매핑을 사용하여 시도했지만 스프라이트 시트입니다. 타일 ​​배치 장소에 대한 정보가 없기 때문에 밉 매핑은 쓸모가 없으며 문제를 해결하지 못했습니다.

정점들

우리는 모든 위치를 순환합니다. 부동 소수점은 아직 없지만 위치는 Vector3 (Float3)입니다.

for (UInt16 x = 0; x < _width;  x++)
{
    for (UInt16 y = 0; y < _heigth; y++)
    {
        [...]
        position.z = priority; // this is a byte 0-5

타일을 배치하려면 다음 코드가 사용됩니다.

tilePosition.X = position.X;
tilePosition.Y = position.Y + position.Z;
tilePosition.Z = position.Z;

알다시피, 부동 소수점은 32 비트이고 정밀도는 24 비트입니다. z의 최대 비트 값은 8 비트 (5 = 00000101)입니다. X와 Y의 최대 값은 16 비트입니다. 24 비트. 나는 부동 소수점의 관점에서 잘못 될 수 없다고 생각했다.

this.Position = tilePosition;

정점이 설정되면 다음과 같이 정점이 설정됩니다 (모든 정점이 동일한 타일 위치를 공유 함)

Vector3[] offsets  = new Vector3[] { Vector3.Zero, Vector3.Right, 
    Vector3.Right + (this.IsVertical ? Vector3.Forward : Vector3.Up), 
    (this.IsVertical ? Vector3.Forward : Vector3.Up) };
Vector2[] texOffset = new Vector2[] { Vector2.Zero, Vector2.UnitX, 
    Vector2.One, Vector2.UnitY };

for (int i = 0; i < 4; i++)
{
    SetVertex(out arr[start + i]);
    arr[start + i].vertexPosition = Position + offsets[i];

    if (this.Tiles[0] != null)
        arr[start + i].texturePos1 += texOffset[i] * this.Tiles[0].TextureWidth;
    if (this.Tiles[1] != null)
        arr[start + i].texturePos2 += texOffset[i] * this.Tiles[1].TextureWidth;
    if (this.Tiles[2] != null)
        arr[start + i].texturePos3 += texOffset[i] * this.Tiles[2].TextureWidth;
}

쉐이더

셰이더는 애니메이션 타일과 정적 타일을 그릴 수 있습니다. 둘 다 다음 샘플러 상태를 사용합니다.

sampler2D staticTilesSampler = sampler_state { 
    texture = <staticTiles> ; magfilter = POINT; minfilter = POINT; 
    mipfilter = POINT; AddressU = clamp; AddressV = clamp;};

셰이더는 다른 샘플러 상태를 설정하지 않으며 코드에도 포함되지 않습니다.

매 회마다 다음 줄을 사용하여 알파 값으로 클립합니다 (검정 픽셀을 얻지 못합니다).

clip(color.a - alpha)

알파는 솔리드 레이어 1에서는 1이고 다른 레이어에서는 거의 0입니다. 즉, 알파의 일부가있는 경우 맨 아래의 레이어가 아니라면 그 레이어가 그려지는 것을 의미합니다 (우리는 그 레이어로 무엇을해야할지 모르기 때문입니다).

카메라

우리는 카메라를 사용하여 타일에서 위에서 아래로 룩업을 모방하여 z 값을 사용하여 외부 레이어 데이터 (3 개의 레이어가 항상 올바른 순서가 아님)로 레이어를 정렬하여 평면으로 표시합니다. 이것은 또한 잘 작동합니다. 카메라가 변환 행렬을 업데이트합니다. 왜 이것이 이상한 구조를 가지고 있는지 궁금해하신 다면요 .AddChange - 코드는 Double Buffered입니다 (이것도 가능합니다). 변환 행렬은 다음과 같이 형성됩니다.

// First get the position we will be looking at. Zoom is normally 32
Single x = (Single)Math.Round((newPosition.X + newShakeOffset.X) * 
    this.Zoom) / this.Zoom;
Single y = (Single)Math.Round((newPosition.Y + newShakeOffset.Y) * 
    this.Zoom) / this.Zoom;

// Translation
Matrix translation = Matrix.CreateTranslation(-x, -y, 0);

// Projection
Matrix obliqueProjection = new Matrix(1, 0, 0, 0,
                                      0, 1, 1, 0,
                                      0, -1, 0, 0,
                                      0, 0, 0, 1);

Matrix taper = Matrix.Identity; 

// Base it of center screen
Matrix orthographic = Matrix.CreateOrthographicOffCenter(
    -_resolution.X / this.Zoom / 2, 
     _resolution.X / this.Zoom / 2, 
     _resolution.Y / this.Zoom / 2, 
    -_resolution.Y / this.Zoom / 2, 
    -10000, 10000);

// Shake rotation. This works fine       
Matrix shakeRotation = Matrix.CreateRotationZ(
    newShakeOffset.Z > 0.01 ? newShakeOffset.Z / 20 : 0);

// Projection is used in Draw/Render
this.AddChange(() => { 
    this.Projection = translation * obliqueProjection * 
    orthographic * taper * shakeRotation; }); 

추론 및 흐름

타일 ​​데이터는 3 개의 레이어로 구성됩니다. 각 타일은 IsSemiTransparent 의해 정의됩니다. 타일이 IsSemiTransparent 인 경우 IsSemiTransparentIsSemiTransparent 타일 ​​뒤에 IsSemiTransparent 합니다. 타일 ​​데이터는 SplattedTile 인스턴스에로드 될 때 스택됩니다. 따라서 타일 데이터의 레이어 1이 비어 SplattedTile 의 레이어 1에는 첫 번째 레이어에 타일 데이터가 있습니다 (적어도 하나의 레이어에는 타일 데이터가 있음). 그 이유는 Z-buffer 가 그 뒤에 솔리드 픽셀이 없기 때문에 순서대로 그려지면 블렌딩 대상을 알지 못하기 때문입니다.

레이어에는 az 값이 없으며 개별 타일 데이터에 있습니다. 지상 타일 인 경우 Priority = 0 입니다. 따라서 Priority 가 동일한 타일을 레이어 (그리기 순서)와 불투명 (반투명, 불투명) 순서로 정렬합니다. 우선 순위가 다른 타일은 우선 순위에 따라 그려집니다.

첫 번째 단색 레이어에는 대상 픽셀이 없으므로 DestinationBlend.Zero 설정합니다. 또한 AlphaBlending 필요 없기 때문에 AlphaBlending 필요하지 않습니다. 이미 색 데이터가 있고 그에 따라 혼합해야하는 경우 다른 레이어 (5, 2 솔리드, 3 투명)가 그려 질 수 있습니다.

6 패스를 반복하기 전에, projection matrix 이 설정됩니다. 테이퍼를 사용하지 않으면이 기능이 작동합니다. 테이퍼를 사용할 때 그렇지 않습니다.

문제

우리는 테이퍼를 적용하여 약간의 행렬을 사용하여 좀 더 깊이를 모방하고 싶습니다. 몇 가지 값을 시도했지만 예제가 있습니다.

new Matrix(1, 0, 0, 0,
           0, 1, 0, 0.1f,
           0, 0, 1, 0,
           0, 0, 0, 1);

화면 (높이 값 0의 모든 항목, 모든 평면 항목)이 압착됩니다. y가 낮을수록 (화면에서 높을수록) 압착이 심합니다. 이것은 실제로 작동하지만 지금은 거의 모든 곳에서 임의의 검은 선이 나타납니다. 몇 개의 타일을 제외하는 것처럼 보이지만 상관 관계가 무엇인지 알지 못합니다. 보간이나 밉맵과 관련이 있다고 생각합니다.

그리고 내가 말하는 것에 대해 보여주는 이미지가 있습니다. .

영향을받지 않는 타일은 맨 아래 레이어에 정적 타일이 아닌 것처럼 보입니다. 그러나 그 위에있는 투명 타일은 다른 그래픽 인공물을 나타냅니다. 그들은 행을 놓치기 때문에 행이 삭제됩니다. 나는 그것이 일어나는 것에 대한 힌트라고 생각하기 때문에이 텍스트를 표시했다. mip mag and minfilterLinear 놓으면 수직선 이 나타납니다.

다음은 레이어 2 또는 3의 타일에 아티팩트가 표시되어 확대 된 이미지입니다 (게임 줌에서).

우리는 이미 시도했다.

  • Point 또는 Linear mipfilter
  • 원래 텍스처에 GenerateMipMaps 설정하기
  • GenerateMipMaps 된 텍스처에 GenerateMipMaps 설정 ( RenderTarget true 플래그 생성자)
  • 밉 매핑을 켜기 (필자가 스프라이트 시트를 밉맵으로 사용 하기 때문에 줌아웃 할 때 아티팩트가 더 많이 생겼다 .
  • 레이어 2와 레이어 3을 그리지 않음 (실제로 모든 타일에 검정색 선이 있음)
  • DepthBufferEnable = false
  • 모든 단색 레이어를 SrcBlend = One; DestBlend = Zero;
  • 모든 단색 레이어를 ScrBlend = SrcAlpha; 로 설정합니다 ScrBlend = SrcAlpha; DestBlend = InvSrcAlpha;
  • 투명 레이어를 그리지 않습니다 (선은 여전히 ​​있음).
  • shader 에서 clip(opacity) 제거 이 명령은 일부 줄만 제거합니다. 우리는 이것을 더 조사하고 있습니다.
  • msdn, 및 google (행운과 함께)을 사용하여 동일한 문제를 검색합니다.

누구든지이 문제를 인식합니까? 마지막으로, 우리는 타일을 그린 후에 SpriteBatch 호출하고, 아바타에 다른 Shader 를 사용합니다 (높이> 0이기 때문에 별다른 문제가 없음). sampler state 취소합니까? 또는...?




문제는 HLSL의 숫자 유형과 관련이 있습니다.

먼저, 그 쉐이더를 정리하자. 이것이 우리가 실제 문제를 발견 한 방법이기 때문에 그렇게 할 것입니다. 다음은 taperfix가 삽입되기 전의 SplattedTileShader.fx에 대한 통합 diff입니다.

@@ -37,76 +37,31 @@
    data.Position = mul(worldPosition, viewProjection);

-   
     return data;
 }

-float4 PixelLayer1(VertexShaderOutput input, uniform float alpha) : COLOR0
+float4 PixelLayer(VertexShaderOutput input, uniform uint layer, uniform float alpha) : COLOR0
 {
-   if(input.TextureInfo[0] < 1)
+   if(input.TextureInfo[0] < layer)
        discard;

-    float4 color;
+   float4 color;
+   float2 coord;
+   if(layer == 1)
+       coord = input.TexCoord1;
+   else if(layer == 2)
+       coord = input.TexCoord2;
+   else if(layer == 3)
+       coord = input.TexCoord3;

-   switch (input.TextureInfo[1])
+   switch (input.TextureInfo[layer])
    {
        case 0:
-           color = tex2D(staticTilesSampler, input.TexCoord1);
+           color = tex2D(staticTilesSampler, coord);
            break;
        case 1:
-           color = tex2D(autoTilesSampler, input.TexCoord1);
+           color = tex2D(autoTilesSampler, coord);
            break;
        case 2:
-           color = tex2D(autoTilesSampler, input.TexCoord1 + float2(frame, 0) * animOffset) * (1 - frameBlend) + tex2D(autoTilesSampler, input.TexCoord1 + float2(nextframe, 0) * animOffset) * frameBlend;
-           break;
-   }
-
-   clip(color.a - alpha);
-
-   return color;
-}
-
-float4 PixelLayer2(VertexShaderOutput input, uniform float alpha) : COLOR0
-{
-   if(input.TextureInfo[0] < 2)
-       discard;
-
-    float4 color;
-
-   switch (input.TextureInfo[2])
-   {
-       case 0:
-           color = tex2D(staticTilesSampler, input.TexCoord2);
-           break;
-       case 1:
-           color = tex2D(autoTilesSampler, input.TexCoord2);
-           break;
-       case 2: 
-           color = tex2D(autoTilesSampler, input.TexCoord2 + float2(frame, 0) * animOffset) * (1 - frameBlend) + tex2D(autoTilesSampler, input.TexCoord2 + float2(nextframe, 0) * animOffset) * frameBlend;
-           break;
-   }
-
-   clip(color.a - alpha);
-
-   return color;
-}
-
-float4 PixelLayer3(VertexShaderOutput input, uniform float alpha) : COLOR0
-{
-   if(input.TextureInfo[0] < 3)
-       discard;
-
-    float4 color;
-
-   switch (input.TextureInfo[3])
-   {
-       case 0:
-           color = tex2D(staticTilesSampler, input.TexCoord3);
-           break;
-       case 1:
-           color = tex2D(autoTilesSampler, input.TexCoord3);
-           //color = float4(0,1,0,1);
-           break;
-       case 2:
-           color = tex2D(autoTilesSampler, input.TexCoord3 + float2(frame, 0) * animOffset) * (1 - frameBlend) + tex2D(autoTilesSampler, input.TexCoord3 + float2(nextframe, 0) * animOffset) * frameBlend;
+           color = tex2D(autoTilesSampler, coord + float2(frame, 0) * animOffset) * (1 - frameBlend) + tex2D(autoTilesSampler, coord + float2(nextframe, 0) * animOffset) * frameBlend;
            break;
    }
@@ -125,5 +80,5 @@
        DestBlend = Zero;
         VertexShader = compile vs_3_0 VertexShaderFunction();
-        PixelShader = compile ps_3_0 PixelLayer1(1);
+        PixelShader = compile ps_3_0 PixelLayer(1,1);
     }

@@ -134,5 +89,5 @@
        DestBlend = InvSrcAlpha;
        VertexShader = compile vs_3_0 VertexShaderFunction();
-        PixelShader = compile ps_3_0 PixelLayer2(0.00001);
+        PixelShader = compile ps_3_0 PixelLayer(2,0.00001);
    }

@@ -143,5 +98,5 @@
        DestBlend = InvSrcAlpha;
        VertexShader = compile vs_3_0 VertexShaderFunction();
-        PixelShader = compile ps_3_0 PixelLayer3(0.00001);
+        PixelShader = compile ps_3_0 PixelLayer(3,0.00001);
    }
 }
@@ -155,5 +110,5 @@
        DestBlend = InvSrcAlpha;
         VertexShader = compile vs_3_0 VertexShaderFunction();
-        PixelShader = compile ps_3_0 PixelLayer1(0.000001);
+        PixelShader = compile ps_3_0 PixelLayer(1,0.000001);
     }

@@ -164,5 +119,5 @@
        DestBlend = InvSrcAlpha;
        VertexShader = compile vs_3_0 VertexShaderFunction();
-        PixelShader = compile ps_3_0 PixelLayer2(0.000001);
+        PixelShader = compile ps_3_0 PixelLayer(2,0.000001);
    }

@@ -173,5 +128,5 @@
        DestBlend = InvSrcAlpha;
        VertexShader = compile vs_3_0 VertexShaderFunction();
-        PixelShader = compile ps_3_0 PixelLayer3(0.00001);
+        PixelShader = compile ps_3_0 PixelLayer(3,0.00001);
    }
 }

`

보시다시피 layer (type = uint)라는 새로운 입력 변수가 있습니다. 그리고 이제 3 대신 PixelLayer 함수 하나가 있습니다.

다음은 SplattedTileVertex.cs에 대한 통합 된 diff입니다.

@@ -11,5 +11,5 @@
     {
         internal Vector3 vertexPosition;
-        internal byte textures;
+        internal float textures;
         /// <summary>
         /// Texture 0 is static tiles
@@ -17,7 +17,7 @@
         /// Texture 2 is animated autotiles
         /// </summary>
-        internal byte texture1;
-        internal byte texture2;
-        internal byte texture3;
+        internal float texture1;
+        internal float texture2;
+        internal float texture3;
         internal Vector2 texturePos1;
         internal Vector2 texturePos2;
@@ -27,8 +27,8 @@
         (
             new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
-            new VertexElement(12, VertexElementFormat.Byte4, VertexElementUsage.PointSize, 0),
-            new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
-            new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 1),
-            new VertexElement(32, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 2)
+            new VertexElement(12, VertexElementFormat.Vector4, VertexElementUsage.PointSize, 0),
+            new VertexElement(28, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
+            new VertexElement(36, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 1),
+            new VertexElement(44, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 2)
         );

예, 유형을 변경했습니다.

그리고 이제 문제가 드러납니다. 입력이 처리되는 방식 때문에 부동 소수점은 절대 정수 값과 완전히 같지 않을 것입니다. 이것의 뒤에있는 추론은이 쓰레드를 넘어서지만, 어쩌면 나는 그것에 커뮤니티 위키를 만들어야 할 것이다.

그래서, 무슨 일이 일어 났습니까?

Ok. 그래서 우리는 레이어에없는 값을 (if input.TextureInfo[0] < layer -> discard) . 내부 input.TextInfo [layer]에는 플로트가 있습니다. 이제 우리는 float을 우리의 uint 레이어 값과 비교합니다. 그리고 여기서 마술이 일어납니다. 일부 픽셀은 정확히 일치 (또는 해당 레이어 값 바로 위에있을 수 있습니다.) 유형이 (u) int 인 경우에는 코드별로 좋지만 그렇지는 않습니다.

어떻게 해결할 수 있을까요? 그곳에는 아마도 규칙이있을 것입니다. 움직이는 코드는 타일이 반쯤있는 경우 타일에 픽셀을 렌더링합니다. 우리는 레이어와 동일한 작업을 수행합니다.

다음은 SplattedTileShader.fx의 수정 사항 (통합 된 diff)입니다.

@@ -42,28 +42,24 @@
 float4 PixelLayer(VertexShaderOutput input, uniform uint layer, uniform float alpha) : COLOR0
 {
-   if(input.TextureInfo[0] < layer)
+   if(input.TextureInfo[0] < (float)layer - 0.5)
        discard;

    float4 color;
    float2 coord;
-   if(layer == 1)
+   if(layer < 1.5)
        coord = input.TexCoord1;
-   else if(layer == 2)
+   else if(layer < 2.5)
        coord = input.TexCoord2;
-   else if(layer == 3)
+   else
        coord = input.TexCoord3;

-   switch (input.TextureInfo[layer])
-   {
-       case 0:
-           color = tex2D(staticTilesSampler, coord);
-           break;
-       case 1:
-           color = tex2D(autoTilesSampler, coord);
-           break;
-       case 2:
-           color = tex2D(autoTilesSampler, coord + float2(frame, 0) * animOffset) * (1 - frameBlend) + tex2D(autoTilesSampler, coord + float2(nextframe, 0) * animOffset) * frameBlend;
-           break;
-   }
+   float type = input.TextureInfo[layer];
+
+   if (type < 0.5)
+       color = tex2D(staticTilesSampler, coord);
+   else if (type < 1.5)
+       color = tex2D(autoTilesSampler, coord);
+   else
+       color = tex2D(autoTilesSampler, coord + float2(frame, 0) * animOffset) * (1 - frameBlend) + tex2D(autoTilesSampler, coord + float2(nextframe, 0) * animOffset) * frameBlend;

    clip(color.a - alpha);

이제 모든 유형이 정확합니다. 코드가 정상적으로 작동하고 문제가 해결되었습니다. 그것은 처음에 내가 지적한 discard(...) 코드로 할 일이 없었습니다.

이 문제를 해결하는 데 참여해 주신 모든 분들께 감사드립니다.




왜 검은 선이 나타나는지 알 수는 없지만 정확한 결과를 얻을 수있는 경치를 렌더링 할 수있는 다른 방법을 제공 할 수 있습니다. (그리고 희망 사항으로 약간의 속도 향상을 줄 수 있습니다.)

스프라이트

이 작업을 위해서는 텍스처 맵 (스프라이트 시트라고도 함)이 필요합니다. 알타를 여러 개의 아틀라스로 나눌 수 있고 멀티 텍스처링을 사용할 수 있습니다.

버텍스 버퍼

SpriteBatch를 스크래치하는 것입니다. 스프라이트가 어디에 위치하는지 항상 알 수 있습니다. 시작시 VertexBuffer 를 만들고 (레이어 당 하나씩) 레이어를 그리는 데 사용할 수 있습니다. 이것과 같은 것 ( 이것은 2D 버퍼입니다. 당신의 3D처럼 보입니다 ) :

정점 정의는 아마도 다음과 같이 구성됩니다.

  • 위치 ( Vector2 )
  • 텍스처 좌표 ( Vector2 )
  • 색상 ( Vector4/Color )

풍경을 '순환'해야 할 때마다 (나중에 자세히 설명) 카메라 아래의 맵을 통해 VertexBufferVertexBuffer 좌표 및 / 또는 색상을 업데이트합니다. 각 프레임 버퍼를 새로 고치지 마십시오. 텍스처 좌표를 [0, 1] 범위의 GPU에 보내지 않고 [0, Number of Sprites] - 버텍스 쉐이더에서 [0, 1] 을 계산합니다.

중요 : 두 개 이상의면이 공유하는 꼭지점이 별개의 것으로 유지되어야하기 때문에 ( IndexBuffer 사용하는 IndexBuffer ) 정점을 공유하지 마십시오 (별도의 텍스처 좌표를 가짐) - IndexBuffer 가 존재하지 않는 것처럼 버퍼를 구축합니다 . 이 시나리오에서는 IndexBuffer 사용하는 것이 낭비이므로 VertexBuffer 만 사용하십시오.

표현

사용하는 월드 매트릭스는 [0, 1] 을 화면의 크기와 타일의 크기 (즉 간단한 축척 x = Viewport.Width + 32y = Viewport.Height + 32 )로 매핑합니다. 투영 행렬은 항등 행렬입니다.

뷰 매트릭스는 까다 롭습니다. 지도가 {0,0} 타일의 현재 블록을보고 있다고 가정하면 카메라가보고있는 위치에서 오프셋 (픽셀 단위)을 알아낼 수 있습니다. 따라서 본질적으로 x = Camera.X - LeftTile.X * (Viewport.Width / NumTiles.X)y 와 유사한 오프셋 행렬이됩니다.

행렬은 유일한 까다로운 비트입니다. 일단 간단한 DrawUserPrimitives() 호출을 설정하면 완료됩니다.

이것은 당신의 풍경을 다루기 만하면, 오늘처럼 다른 스프라이트도 그려줍니다.

조경 사이클링

카메라의 위치가 바뀌면 기본적으로 새로운 타일 블록을보고 VertexBuffer 적절하게 업데이트할지 결정해야합니다 (텍스처 좌표 및 색상 - 위치를 그대로두고 다시 계산하지 않아도됩니다).

또는

또 다른 옵션은 각 레이어를 RenderTarget2D 로 렌더링하고 전체 레이어에 대해 현재 변환을 한 번 사용하는 것입니다. 이것은 당신의 문제를 해결하거나, 진짜 이유를 아주 현명하게 만들 것입니다.

참고 사항 : 00h40이 아니라면 샘플 코드를 제공 하겠지만이 질문에 답할 가치가 있습니다. 나는 내일 밤에 얼마나 많은 시간을 볼 수있을거야.




문제는 SplattedTileShader.fx 셰이더에 있습니다.

버려진 픽셀 때문에 검은 선이 나타납니다.

더 많은 정보없이 쉐이더 코드를 따라 가기는 어렵지만 문제가 있습니다.

나는 당신이 멀티 텍스쳐를하는 방식이 너무 복잡하다고 생각한다.

한 번에 다중 텍스처를 지원하는 셰이더를 만드는 것이 더 쉬울 수도 있습니다.

버텍스에서 각 텍스처에 대해 4 개의 가중치 값을 전달하고 쉐이더에서 직접 믹스를 수행 할 수 있습니다.

http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series4/Multitexturing.php




당신이 우리에게 준 것과 함께, 나는 당신의 코드 레이어링에 대해 매우 의심스러워 할 것입니다. 이것은 실제로 맨 아래 레이어가 부동 소수점 반올림에 따라 맨 위에 있고 숨겨져있는 레이어를 뚫고 지나가는 것처럼 보입니다. 보기 각도에 수직 인 줄무늬는 정확히 동일 평면 상에 있어야하는 두 개의 삼각형을 가지고 있지만 어떤 이유로 든 정확히 동일한 꼭지점 좌표가없는 경우 (예 : 다른 하나가 더 큼) 매우 일반적인 효과입니다. 서로 다른 층을 매우 작게 그린다면 어떻게 될까요? 마찬가지로 아래쪽 솔리드 레이어는 -0.00002에 그리고 그 다음은 -0.00001에 그리고 위쪽 레이어는 0에 그려야합니다 (3 개가 모두 0으로 그려진다는 가정하에).

특히 XNA에 대해서는 잘 모르겠지만 레이어링 문제는 항상 부동 소수점을 사용하여 기하학을 표현하는 근본적인 문제이며 XNA가 "마법처럼"당신을 피할 경우 놀라실 것입니다. 왜 일부 타일들은 괜찮지 만 대부분은 망가 졌는지 확실하지 않습니다. 아마도 그 타일들은 단지 운이 좋았을 것입니다. 부동 소수점 오류로 인한 문제는 종종 이와 같이 매우 이상하게 작용합니다.

레이어를 약간 분리해도 도움이되지 않는다면 표준 주석 기반 디버깅으로 축소 될 것입니다. 투명 레이어가없는 애니메이션 타일이없는 스프라이트없이 시도해보십시오. & c. 그것이 일어날 때 멈추었을 때, 당신이 방금 논평 한 것은 무엇이든 그것을 깨뜨리는 것입니다 : P