Наша игра использует «блочный атлас», сетку квадратных текстур, которые соответствуют определенным граням блоков в игре. Мы стремимся оптимизировать память данных вершин, сохраняя данные текстуры в вершине в виде шорт вместо float2s. Вот наше определение вершины (XNA, C #):
public struct BlockVertex : IVertexType
{
public Vector3 Position;
public Vector3 Normal;
/// <summary>
/// The texture coordinate of this block in reference to the top left corner of an ID's square on the atlas
/// </summary>
public short TextureID;
public short DecalID;
// Describe the layout of this vertex structure.
public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector3,
VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector3,
VertexElementUsage.Normal, 0),
new VertexElement(sizeof(float) * 6, VertexElementFormat.Short2,
VertexElementUsage.TextureCoordinate, 0)
);
public BlockVertex(Vector3 Position, Vector3 Normal, short TexID)
{
this.Position = Position;
this.Normal = Normal;
this.TextureID = TexID;
this.DecalID = TexID;
}
// Describe the size of this vertex structure.
public const int SizeInBytes = (sizeof(float) * 6) + (sizeof(short) * 2);
VertexDeclaration IVertexType.VertexDeclaration
{
get { return VertexDeclaration; }
}
}
У меня мало опыта в HLSL, но когда я попытался адаптировать наш текущий шейдер для использования этой вершины (в отличие от старого, в котором текстуры и декаль сохранялись как координаты Vector2), я получил только прозрачные синие модели, которые Я полагаю, означает, что координаты текстуры для лица все одинаковы?
Вот HLSL, где я пытаюсь интерпретировать данные вершин:
int AtlasWidth = 25;
int SquareSize = 32;
float TexturePercent = 0.04; //percent of the entire texture taken up by 1 pixel
[snipped]
struct VSInputTx
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
short2 BlockAndDecalID : TEXCOORD0;
};
struct VSOutputTx
{
float4 Position : POSITION0;
float3 Normal : TEXCOORD0;
float3 CameraView : TEXCOORD1;
short2 TexCoords : TEXCOORD2;
short2 DecalCoords : TEXCOORD3;
float FogAmt : TEXCOORD4;
};
[snipped]
VSOutputTx VSBasicTx( VSInputTx input )
{
VSOutputTx output;
float4 worldPosition = mul( input.Position, World );
float4 viewPosition = mul( worldPosition, View );
output.Position = mul( viewPosition, Projection );
output.Normal = mul( input.Normal, World );
output.CameraView = normalize( CameraPosition - worldPosition );
output.FogAmt = 1 - saturate((distance(worldPosition,CameraPosition)-FogBegin)/(FogEnd-FogBegin)); //This sets the fog amount (since it needs position data)
// Convert texture coordinates to short2 from blockID
// When they transfer to the pixel shader, they will be interpolated
// per pixel.
output.TexCoords = short2((short)(((input.BlockAndDecalID.x) % (AtlasWidth)) * TexturePercent), (short)(((input.BlockAndDecalID.x) / (AtlasWidth)) * TexturePercent));
output.DecalCoords = short2((short)(((input.BlockAndDecalID.y) % (AtlasWidth)) * TexturePercent), (short)(((input.BlockAndDecalID.y) / (AtlasWidth)) * TexturePercent));
return output;
}
Я ничего не изменил по сравнению с оригинальным шейдером, который отображал все нормально, но вы можете увидеть весь файл .fx здесь .
Если бы я мог просто отладить то, что смог бы получить, но ... в любом случае, я думаю, это связано с моим ограниченным знанием того, как работают шейдеры. Я полагаю, что моя попытка использовать целочисленную арифметику менее эффективна. Кроме того, это много бросков, я мог бы поверить, если бы значения были вынуждены равны 0 где-то там. В случае, если я далеко от цели, вот что я стремлюсь достичь:
- Шейдер получает вершину, в которой хранятся две шорты, а также другие данные. Шорты представляют собой идентификатор определенного угла сетки из квадратных текстур. Один для лицевой стороны блока, другой для декали, которая нарисована поверх этой грани.
- Шейдер использует эти идентификаторы, а также некоторые константы, которые определяют размер текстурной сетки (далее именуемой «Атлас»), для определения фактической координаты текстуры этого конкретного угла.
- X координаты текстуры - это (ID% AtlasWidth) * TexturePercent, где TexturePercent - это константа, представляющая процент всей текстуры, представленной 1 пикселем.
- Y координаты текстуры - это (ID / AtlasWidth) * TexturePercent.
Как мне это сделать?
Обновление: в какой-то момент я получил сообщение об ошибке "vs_1_1 не поддерживает 8- или 16-разрядные целые числа", может ли это быть частью проблемы?