我们的游戏使用“块图集”,这是一种方形纹理网格,对应于游戏中块的特定面。我们的目标是通过将顶点中的纹理数据存储为short而不是float2来简化顶点数据内存。这是我们的顶点定义(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没什么经验,但是当我尝试调整当前着色器来使用这个顶点时(而不是那个将Texture和Decal存储为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文件here。
如果我可以调试我可以得到它的东西,但是......好吧,不管怎样,我认为这与我对着色器如何工作的有限知识有关。我想我尝试使用整数运算效果不佳。此外,这是很多演员阵容,如果价值在某处被强制为0,我可以相信它。如果我不合时宜,这就是我的目标:
我该如何解决这个问题?
更新:我在某个时候收到错误“vs_1_1不支持8位或16位整数”这可能是问题的一部分吗?
答案 0 :(得分:1)
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));
这两行包含以下几个部分:
(input.BlockAndDecalID.x) / (AtlasWidth)
(input.BlockAndDecalID.y) / (AtlasWidth)
这些都是整数除法。整数除法会切断所有小数点。我假设AtlasWidth总是大于每个坐标,因此这两个分区总是会产生0.如果这个假设不正确,我假设你仍然想要某种十进制数据吗?
你可能想要一个浮点除法,它会返回一个十进制结果,因此你需要先将至少一个(或两个)操作数转换为float,例如:
((float)input.BlockAndDecalID.x) / ((float)AtlasWidth)
编辑:我会改用NormalizedShort2;它将您的值缩放最大短值(32767),允许使用短值的“十进制”(换句话说,“0.5”= 16383)。当然,如果您的意图只是将tex coord数据减半,则可以通过使用HalfVector2仍然使用浮点数来实现此目的。如果你仍然坚持Short2,你可能需要像NormalizedShort2那样在将它作为坐标提交之前进行缩放。
答案 1 :(得分:0)
好吧,在我尝试在其中一个着色器函数中创建一个short并面临编译器错误后,表明vs_1_1不支持8/16位整数(为什么你之前没告诉我?) ,我把功能改成了这样:
float texX = ((float)((int)input.BlockAndDecalID.x % AtlasWidth) * (float)TexturePercent);
float texY = ((float)((int)input.BlockAndDecalID.x / AtlasWidth) * (float)TexturePercent);
output.TexCoords = float2(texX, texY);
float decX = ((float)((int)input.BlockAndDecalID.y % AtlasWidth) * (float)TexturePercent);
float decY = ((float)((int)input.BlockAndDecalID.y / AtlasWidth) * (float)TexturePercent);
output.DecalCoords = float2(decX, decY);
这似乎工作得很好。我不确定它是在改变内部的东西还是在前面投射(浮动)。我认为这可能是浮动,这意味着斯科特肯定会有所作为。我的伙伴以某种方式编写了这个着色器,使用short2作为纹理坐标;他是怎么做的我不知道。