ما هي أفضل ممارسة لتقديم العفاريت في DirectX 11؟
-
28-09-2019 - |
سؤال
أحاول حاليًا التعود على API DirectX وأتساءل ما هو النهج المعتاد لتقديم العفريت في DirectX 11 (على سبيل المثال لاستنساخ Tetris).
هل هناك واجهة سيممير 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;
}
المحلول
لا ليس هناك ما يعادل. الطريقة المعتادة هي رسم شريط مثلث يشكل رباعية.
يمكنك الاستفادة من Instancing ، لذلك عليك فقط تحديث المخزن المؤقت مع بيانات العفريت (موضع الشاشة x ، y بالبكسل ، معرف الملمس لجلبه في صفيف نسيج ، تحجيم ، دوران ، طبقة ، إلخ). تقديم جميع العفاريت في مكالمة سحب واحدة.
إليك بعض الحكايات 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;
}
لا تنتمي إلى StackOverflow