首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在DirectX 10中渲染精灵最有效的方法是什么?

在DirectX 10中渲染精灵最有效的方法是什么?
EN

Stack Overflow用户
提问于 2013-07-01 14:05:24
回答 2查看 2.9K关注 0票数 4

目前,我正在DirectX 10中尝试各种显示2D精灵的方法,我首先使用ID3DX10Sprite接口在一个调用中批量绘制我的精灵。然而,最终,我想要更多地控制我的精灵是如何呈现的,所以我决定研究基于四体的精灵渲染(即每个精灵都由一个纹理应用的四体表示)。

我一开始很简单:我创建了一个由4个顶点组成的单一顶点缓冲区,在绘制精灵之前应用了一次。然后,我循环通过我的精灵,设置适当的属性传递到着色器,并为每个雪碧进行抽签调用,如:d3dDevice->Draw( 4, 0);。尽管它奏效了,但对每一个精灵的抽签要求都让我心烦意乱,所以我想找一种更有效的方法。

在搜索之后,我了解了对象实例,并决定尝试它。一切进展顺利,直到我尝试实现精灵最重要的部分--纹理。简而言之,虽然我有一个纹理数组(在我的着色器顶部声明为so Texture2D textures[10];),可以使用文字/常量作为索引在我的像素着色器中成功地进行采样,但我无法知道如何通过纹理索引控制哪些纹理被应用到哪个实例。

我的想法是在每个实例中传递一个纹理索引,然后可以用来对像素着色器中数组中的适当纹理进行采样。然而,在搜索了更多之后,我找不到一个如何完成它的例子(并且发现许多事情表明,如果不迁移到DirectX 11,它是无法完成的)。

也就是说,通过DirectX 10中的对象实例成功地呈现精灵的唯一方法是基于纹理的批量呈现?因此,例如,如果我的场景包含有20个不同纹理的100个精灵(每个纹理由5个精灵引用),那么需要20个不同的抽签调用来显示场景,而我一次只发送5个精灵。

最后,我有点不知所措。我已经做了很多搜索,似乎想出了相互矛盾的信息。例如,在第6段的条款中,它指出:

使用DirectX 10,可以将数组中的不同纹理应用于同一对象的不同实例,从而使它们看起来不同。

此外,在白皮书第3页中,它提到了以下选项:

从纹理数组中读取每个实例的自定义纹理

但是,我似乎找不到一个具体的例子,说明如何设置着色器来使用每个实例的纹理索引来访问纹理数组。

最后,中心问题是:使用DirectX 10渲染精灵的最有效方法是什么?

如果答案是实例,那么是否有可能控制对着色器中的每个特定实例应用哪种纹理--从而使得只需一次抽签调用就可以发送更大批的精灵及其适当的纹理索引?或者我必须满足于一次只使用相同纹理的精灵?

如果答案是返回到使用提供的DX10雪碧接口,那么有一个方法,我有更多的控制它是如何呈现?

另外,我还研究了如何使用几何图形着色器来创建实际的四角体,所以我只需要传递一系列点,而不是管理顶点和实例缓冲区。尽管如此,除非有一种方法可以控制哪些纹理应用于生成的四角体,否则我将返回到只按纹理批处理精灵。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-11 17:02:10

有几种方法(和往常一样)来做你所描述的事情。

请注意,使用

代码语言:javascript
复制
Texture2D textures[10];

将不允许您使用一个可变的索引来查找像素阴影(因为技术上这个声明将为每个纹理分配一个槽)。

因此,您需要的是创建一个Texture2DArray。这有点像卷纹理,但是z组件是一个完整的数字,上面没有采样。

不过,您需要生成这个纹理数组。简单的方法是在启动时执行一个全屏四绘制调用,将每个纹理绘制到数组的一个切片中(您可以为一个特定的切片创建一个RenderTargetView )。在这里,阴影将是一种简单的消遣。

若要创建纹理数组(代码在SlimDX中,但选项类似):

代码语言:javascript
复制
 var texBufferDesc = new Texture2DDescription
  {
            ArraySize = TextureCount,
            BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
            CpuAccessFlags = CpuAccessFlags.None,
            Format = format,
            Height = h,
            Width = w,
            OptionFlags = ResourceOptionFlags.None,
            SampleDescription = new SampleDescription(1,0),
            Usage = ResourceUsage.Default,
 };

然后,着色器资源视图如下:

代码语言:javascript
复制
  ShaderResourceViewDescription srvd = new ShaderResourceViewDescription()
  {
      ArraySize = TextureCount,
      FirstArraySlice = 0,
      Dimension = ShaderResourceViewDimension.Texture2DArray,
      Format = format,
      MipLevels = 1,
      MostDetailedMip = 0
  };

最后,要获得特定切片的呈现目标:

代码语言:javascript
复制
 RenderTargetViewDescription rtd = new RenderTargetViewDescription()
 {
      ArraySize = 1,
      FirstArraySlice = SliceIndex,
      Dimension = RenderTargetViewDimension.Texture2DArray,
      Format = this.Format
 };

将其绑定到您的passtrough着色器,将所需的纹理设置为输入,切片作为输出,并绘制一个全屏四角(或全屏三角形)。

请注意,这个纹理也可以保存在dds格式(因此,它节省您重新生成每次您启动您的程序)。

查找你的纹理就像:

代码语言:javascript
复制
Texture2DArray myarray;

在像素阴影中:

代码语言:javascript
复制
myarray.Sample(mySampler, float2(uv,SliceIndex);

现在关于渲染精灵,你也可以选择扩展GS。

因此,您创建了一个顶点缓冲区,它只包含位置/大小/纹理索引/其他任何东西,每个sprite需要一个顶点。

发送一个带有n个精灵的抽签调用(拓扑需要设置为点列表)。

从顶点着色器到几何图形着色器。

将你的观点扩展到几何图形着色器中的四边形,你可以找到一个例子,即Microsoft中的ParticlesGS,它对你的情况有点过分,因为你只需要渲染部分,而不是动画。如果您需要一些干净的代码,请告诉我,我将快速制作一个与dx10兼容的示例(在我的例子中,我使用的是StructuredBuffers而不是VertexBuffer)

做一个预先制作的Quad并在每个实例VertexBuffer中传递上面的数据也是可能的,但是如果你有大量的精灵,它会很容易地炸掉你的显卡(我的意思是像300多万个粒子,按现在的标准来说不是很多,但是如果你少于50万个精灵,你就会完全没事;)

票数 4
EN

Stack Overflow用户

发布于 2013-07-09 11:42:58

在实例缓冲区中包含纹理索引,并使用它从每个实例的纹理数组中选择正确的纹理:

代码语言:javascript
复制
struct VS
{
    float3 Position: POSITION;
    float2 TexCoord: TEXCOORD0;
    float  TexIndex: TexIndex; // From the instance buffer not the vertex buffer
}

然后将此值传递到像素着色器。

代码语言:javascript
复制
struct PS
{
    float4 Positon: SV_POSITION;
    float3 TexCoord: TEXCOORD0;
}

..

vout.TexCoord = float3(vin.TexCoord, vin.TexIndex);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17406428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档