Direct3D 12——计算着色器——利用索引对纹理进行采样

利用索引对纹理进行采样

纹理元素可以借助2D索引加以访问。在计算着色器中,我们基于分派的线程ID来索引 纹理。而每个线程都要被指定一个唯一的调度ID (调度标识符)。

[numthreads(16, 16, 1]
void CS(int3 dispatchThreadID : SV_DispatchThreadID)
{
//对两个纹理中横纵坐标分别为x、y处的纹素求和,并将结果存至相应的gOutput纹素中
gOutput[dispatchThreadID.xy] = glnputA[dispatchThreadID.xy] + glnputB[dispatchThreadID.xy];
}

假设我们为处理纹理而分发了足够多的线程组(即利用一个线程来处理一个单独的纹素),那么这段 代码会将两个纹理图像的对应数据进行累加,再将结果存于纹理gOutput中。

系统对计算着色器中的索引越界行为有着明确的定义。越界的读操作总是返回0,而向越 界处写入数据时却不会实际执行任何操作。

由于计算着色器运行在GPU上,因此便可以将它作为访问GPU的一般工具,特别是在通过纹理过 滤来对纹理进行采样的时候。但是,这个过程中还存在两点问题。

第一个问题是,我们不能使用Sample 方法,而必须采用SampleLevel方法。与Sample相比,SampleLevel需要获取第三个额外的参数, 以指定纹理的mipmap层级。0表示mipmap的最高级别,1是第二级,并以此类推。若此参数存在小数 部分,则该小数将用于在开启mipmap线性过滤的两个mipmap层级之间进行插值。至于Sample方法, 它会根据屏幕上纹理所覆的像素数量而自动选择最佳的mipmap层级。因为计算着色器不可直接参与渲 染,它便无法知道Sample方法自行选择的mipmap层级,所以我们必须在计算着色器中以 SampleLevel方法来显式(手动)指定mipmap的层级。

第二个问题是,当我们对纹理进行釆样时, 会使用范围为[0,1]2的归一化纹理坐标,而非整数索引。此时,我们便可以将纹理的大小(width, height) (即纹理的宽度与高度)设置为一个常量缓冲区变量,再利用整数索引(x,y)来求取归一化纹理坐标:

u=x/width
v=y/height

下列代码展示了一个使用整数索引的计算着色器,而第二个功能相同的版本则釆用了纹理坐标与 SampleLevel函数。这里我们假设纹理的大小为512x512,且仅使用最高的mipmap层级:

版本1:使用整数索引
cbuffer cbUpdateSettings
 {
    float gWaveConstantO; 
    float gWaveConstantl;
    float gWaveConstant2;
    float gDisturbMag; 
    int2 gDisturblndex; 
};

RWTexture2D<float> gPrevSolInput : register(u0); 
RWTexture2D<float> gCurrSolInput : register(ul); 
RWTexture2D<float> gOutput	: register(u2);

[numthreads(16, 16, 1)]
void CS(int3 dispatchThreadlD : SV_DispatchThreadID)
{
    int x = dispatchThreadlD.x;
    int y = dispatchThreadlD.y;

    gOutput[int2(xz y)] =
         gWaveConstantO * gPrevSolInput[int2(x,y)].r + 
         gWaveConstantl * gCurrSolInput[int2(x,y)].r + 
         gWaveConstant2 * (
               gCurrSolInput[int2(x, y+1) ] .r + 
               gCurrSolInput[int2(x, y-1)] .r + 
               gCurrSolInput[int2(x+1, y)].r +
               gCurrSolInput[int2(x-1,y)].r);
}
版本2:使用函数SampleLevel与纹理坐标
cbuffer cbUpdateSettings
(
     float gWaveConstantO;
     float gWaveConstantl;
     float gWaveConstant2;
     
     float gDisturbMag;
     int2 gDisturblndex;
};
SamplerState samPoint : register(s0);

RWTexture2D<float> gPrevSolInput : register(u0);
RWTexture2D<float> gCurrSolInput : register(ul);

RWTexture2D<float> gOutput	: register(u2);

[numthreads(16, 16, 1)]
void CS(int3 dispatchThreadID : SV_DispatchThreadID)
 {
     //相当于以SampleLevel()取代运算符[]
      int x = dispatchThreadID.x;
      int y = dispatchThreadID.y;
      
      float2 c = float2(x,y)/512.0f; 
      float2 t = float2(x,y-l)/512.0;
      float2 b = float2(x,y+l)/512.0; 
      float2 l = float2(x-1,y)/512.0; 
      float2 r = float2(x+1,y)/512.0;

     gNextSolOutput[int2(x,y)]=        
          gWaveConstantsO*gPrevSolInput.SampleLevel(samPoint, c,0.0f).r+
          gWaveConstantsl*gCurrSolInput.SampleLevel(samPoint, c,0.0f).r+
          gWaveConstants2*( 
               gCurrSolInput.SampleLevel(samPoint,b,0.0f).r+ 
               gCurrSolInput.SampleLevel(samPoint,t,0.0f).r+ 
               gCurrSolInput.SampleLevel(samPoint,r,0.0f).r+ 
               gCurrSolInput.SampleLevel(samPoint,l,0.0f).r+ 

 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值