【问题标题】:Calculating texture coordinates from a grid position从网格位置计算纹理坐标
【发布时间】:2012-02-22 03:46:41
【问题描述】:

我们的游戏使用“方块图集”,即对应游戏中方块特定面的方形纹理网格。我们的目标是通过将纹理数据存储在顶点中作为 shorts 而不是 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 文件here。

如果我可以调试我可能能够得到它的东西,但是......好吧,无论如何,我认为这与我对着色器如何工作的知识有限有关。我想我尝试使用整数算术不太有效。此外,有很多演员表,如果值在某个地方被强制为 0,我可以相信它。万一我离题了,这就是我的目标:

  1. 着色器获取一个顶点,该顶点存储两个短裤以及其他数据。短裤表示正方形纹理网格的某个角的 ID。一个用于块面,另一个用于在该面上绘制的贴花。
  2. 着色器使用这些 ID 以及一些定义纹理网格(以下称为“Atlas”)大小的常量来确定该特定角的实际纹理坐标。
  3. 纹理坐标的 X 是 (ID % AtlasWidth) * TexturePercent,其中 TexturePercent 是一个常数,表示 1 个像素表示的整个纹理的百分比。
  4. 纹理坐标的 Y 是 (ID / AtlasWidth) * TexturePercent。

我该怎么办?

更新:我在某些时候遇到错误“vs_1_1 不支持 8 位或 16 位整数”这可能是问题的一部分吗?

【问题讨论】:

  • 嘿A-Type,我不知道你是否知道,但你应该看看Game Development。您可能会在游戏开发上找到比 SO 上更多的资源。

标签: c# xna shader hlsl


【解决方案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)input.BlockAndDecalID.x) / ((float)AtlasWidth)

编辑:我会改用NormalizedShort2;它通过最大短值(32767)缩放您的值,允许“类似十进制”使用短值(换句话说,“0.5”= 16383)。当然,如果您的意图只是将您的 tex 坐标数据减半,您可以通过使用 HalfVector2 来实现这一点,同时仍然使用浮点数。如果您仍然坚持使用 Short2,您可能需要像 NormalizedShort2 一样在将其作为坐标提交之前对其进行缩放。

【讨论】:

  • 其实整数除法才是想要的结果。 “x”和“y”是骗人的;这两个值都是描述网格上一个角的 ID。网格宽 25 个方格。如果我的 ID 是 58,那么 ID / GridSize = 2,也就是 Y 值……此时我意识到我是一个该死的白痴。我为每个纹理方块的像素宽度定义了一个常数,但我从未使用过它!我的坐标为 2。Y,这很愚蠢,它应该是 2 * 32。考虑到这一点,我将继续。感谢您强迫我考虑更多。
  • 啊,是的,我想说那里看起来有点少:P 我只是不完全知道你是如何设置它的
  • 没有解决我的问题,但我认为我现在走在正确的轨道上。
  • 好吧,经过实验,我实际上将正方形的大小烘焙成百分比。 0.04 = 32 / 800(即 1/25)。所以,这实际上没有帮助。不知何故,一切都归零了。我必须仔细检查我的演员表和操作员...
  • 好吧,短裤不能存储任何十进制信息。假设在上面的示例中,您得到 2 作为 y 值,然后将其乘以 0.04,得到 0.08。当你施放时,它会变成 0。
【解决方案2】:

好吧,在我尝试在其中一个着色器函数中创建一个 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 作为纹理坐标;我不知道他是怎么做到的。

【讨论】:

  • 我不想在上面的帖子里放太多的 cmets,这就是我把它变成聊天的原因:)。但我要解释的是,你可以让 OUTPUT 仍然是一个浮点数,但如果你愿意,输入可以是一个 int。看来这就是你所做的。很抱歉对这个问题有误解。
  • 没问题。经过进一步测试后,我决定舍入错误会导致我不想修复此方法的问题,主要是将某些 ID 的角数减 1。刚刚恢复了最后一小时的工作,哦,好吧,就这样……
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 2014-05-12
  • 1970-01-01
  • 2020-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多