在 DirectX 11 中渲染精灵的最佳实践是什么?

发布于 2024-09-27 00:52:39 字数 1570 浏览 2 评论 0原文

我目前正在尝试适应 DirectX API,我想知道在 DirectX 11 中渲染精灵的常用方法是什么(例如,俄罗斯方块克隆)。

是否有类似于 ID3DX10Sprite 的接口?如果没有,在 DirectX 11 中绘制精灵的常用方法是什么?

编辑:这是对我有用的 HLSL 代码(投影坐标的计算可以做得更好):

struct SpriteData
{
    float2 position;
    float2 size;
    float4 color;
};

struct VSOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

cbuffer ScreenSize : register(b0)
{
    float2 screenSize;
    float2 padding; // cbuffer must have at least 16 bytes
}

StructuredBuffer<SpriteData> spriteData : register(t0);

float2 GetVertexPosition(uint VID)
{
    [branch] switch(VID)
    {
        case 0:
            return float2(0, 0); 
        case 1:
            return float2(1, 0); 
        case 2:
            return float2(0, 1); 
        default:
            return float2(1, 1);
    }
}

float4 ComputePosition(float2 positionInScreenSpace, float2 size, float2 vertexPosition)
{
    float2 origin = float2(-1, 1);
    float2 vertexPositionInScreenSpace = positionInScreenSpace + (size * vertexPosition);

    return float4(origin.x + (vertexPositionInScreenSpace.x / (screenSize.x / 2)), origin.y - (vertexPositionInScreenSpace.y / (screenSize.y / 2)), 1, 1);
}

VSOut VShader(uint VID : SV_VertexID, uint SIID : SV_InstanceID)
{
    VSOut output;

    output.color = spriteData[SIID].color;
    output.position = ComputePosition(spriteData[SIID].position, spriteData[SIID].size, GetVertexPosition(VID));

    return output;
}

float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

I am currently trying to get used to the DirectX API and I am wondering what is the usual approach to render a sprite in DirectX 11 (e.g. for a tetris clone).

Is there a simmilar interface as ID3DX10Sprite, and if not, which would be the usual method to draw sprites in DirectX 11?

Edit: Here is the HLSL code that worked for me (the computation of the projection coordinate could be done better):

struct SpriteData
{
    float2 position;
    float2 size;
    float4 color;
};

struct VSOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

cbuffer ScreenSize : register(b0)
{
    float2 screenSize;
    float2 padding; // cbuffer must have at least 16 bytes
}

StructuredBuffer<SpriteData> spriteData : register(t0);

float2 GetVertexPosition(uint VID)
{
    [branch] switch(VID)
    {
        case 0:
            return float2(0, 0); 
        case 1:
            return float2(1, 0); 
        case 2:
            return float2(0, 1); 
        default:
            return float2(1, 1);
    }
}

float4 ComputePosition(float2 positionInScreenSpace, float2 size, float2 vertexPosition)
{
    float2 origin = float2(-1, 1);
    float2 vertexPositionInScreenSpace = positionInScreenSpace + (size * vertexPosition);

    return float4(origin.x + (vertexPositionInScreenSpace.x / (screenSize.x / 2)), origin.y - (vertexPositionInScreenSpace.y / (screenSize.y / 2)), 1, 1);
}

VSOut VShader(uint VID : SV_VertexID, uint SIID : SV_InstanceID)
{
    VSOut output;

    output.color = spriteData[SIID].color;
    output.position = ComputePosition(spriteData[SIID].position, spriteData[SIID].size, GetVertexPosition(VID));

    return output;
}

float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

长安忆 2024-10-04 00:52:39

不,没有同等的东西。通常的方法是绘制形成四边形的三角形带。

您可以利用实例化,因此您只需使用精灵数据(以像素为单位的 x、y 屏幕位置、要在纹理数组中获取的纹理的 id、缩放、旋转、图层等)更新缓冲区,并使用着色器在一次绘制调用中渲染所有精灵。

以下是我脑海中浮现的一些 HLSL 花絮:

//--------------------------------------------------------------------------------------
// Shader code for Sprite Rendering
//--------------------------------------------------------------------------------------

struct Sprite {
    float2 position; // x, y world position
    float rotation;
    float scaling;

    float layer; // if you have multiple layers of sprites (e.g. background sprites)
    uint textureId;
};

StructuredBuffer<Sprite> SpritesRO : register( t0 );
Texture2DArray<float4> TextureSlices : register (t1);

cbuffer cbRenderConstants : register( b0 )
{
    matrix g_mViewProjection;
    // other constants
};

struct VSSpriteOut
{
    float3 position : SV_Position;
    uint textureId;
};

//-------------------------------------------------------------------------------------            
// Sprite Vertex Shader
//-------------------------------------------------------------------------------------

VSSpriteOut SpriteVS(uint VID : SV_VertexID, uint SIID : SV_InstanceID)
{
    VSSpriteOut Out = (VSSpriteOut)0;

    // VID is either 0, 1, 2 or 3
    // We can map 0 to position (0,0), 1 to (0,1), 2 to (1,0), 3 to (1,1)

    // We fetch the sprite instance data accord SIID
    Sprite sdata = SpritesRO[SIID];

    // function f computes screen space vertex position
    float3 pos = f (g_mViewProjection, VID, position, rotation, scaling, layer etc)

    Out.position = pos;
    Out.textureId = sdata.textureId;

    return Out;
}

//-------------------------------------------------------------------------------------
// Sprite Pixel Shader
//-------------------------------------------------------------------------------------

float4 SpritePS(VSSpriteOut In) : SV_Target
{
    // use In.textureId to fetch the right texture slice in texture array
    return color;
}

No there isn't an equivalent. Usual method would be to draw a triangle strip forming a quad.

You could make use of instancing, so you just have to update a buffer with sprite data (x, y screen position in pixels, id of the texture to fetch in a texture array, scaling, rotation, layer, etc) and use shaders for rendering all sprites in one single draw call.

Here's some HLSL tidbits off the top of my head:

//--------------------------------------------------------------------------------------
// Shader code for Sprite Rendering
//--------------------------------------------------------------------------------------

struct Sprite {
    float2 position; // x, y world position
    float rotation;
    float scaling;

    float layer; // if you have multiple layers of sprites (e.g. background sprites)
    uint textureId;
};

StructuredBuffer<Sprite> SpritesRO : register( t0 );
Texture2DArray<float4> TextureSlices : register (t1);

cbuffer cbRenderConstants : register( b0 )
{
    matrix g_mViewProjection;
    // other constants
};

struct VSSpriteOut
{
    float3 position : SV_Position;
    uint textureId;
};

//-------------------------------------------------------------------------------------            
// Sprite Vertex Shader
//-------------------------------------------------------------------------------------

VSSpriteOut SpriteVS(uint VID : SV_VertexID, uint SIID : SV_InstanceID)
{
    VSSpriteOut Out = (VSSpriteOut)0;

    // VID is either 0, 1, 2 or 3
    // We can map 0 to position (0,0), 1 to (0,1), 2 to (1,0), 3 to (1,1)

    // We fetch the sprite instance data accord SIID
    Sprite sdata = SpritesRO[SIID];

    // function f computes screen space vertex position
    float3 pos = f (g_mViewProjection, VID, position, rotation, scaling, layer etc)

    Out.position = pos;
    Out.textureId = sdata.textureId;

    return Out;
}

//-------------------------------------------------------------------------------------
// Sprite Pixel Shader
//-------------------------------------------------------------------------------------

float4 SpritePS(VSSpriteOut In) : SV_Target
{
    // use In.textureId to fetch the right texture slice in texture array
    return color;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文