如何设置Direct3D纹理中单个像素的颜色?

时间:2022-10-23 23:45:20

I'm attempting to draw a 2D image to the screen in Direct3D, which I'm assuming must be done by mapping a texture to a rectangular billboard polygon projected to fill the screen. (I'm not interested or cannot use Direct2D.) All the texture information I've found in the SDK describes loading a bitmap from a file and assigning a texture to use that bitmap, but I haven't yet found a way to manipulate a texture as a bitmap pixel by pixel.

我正在尝试在Direct3D中将2D图像绘制到屏幕上,我假设必须通过将纹理映射到投影到填充屏幕的矩形广告牌多边形来完成。 (我不感兴趣或者不能使用Direct2D。)我在SDK中找到的所有纹理信息都描述了从文件加载位图并指定纹理来使用该位图,但我还没有找到一种方法来操作纹理作为位图逐个像素。

What I'd really like is a function such as

我真正喜欢的是一个如...的功能

void TextureBitmap::SetBitmapPixel(int x, int y, DWORD color);

void TextureBitmap :: SetBitmapPixel(int x,int y,DWORD color);

If I can't set the pixels directly in the texture object, do I need to keep around a DWORD array that is the bitmap and then assign the texture to that every frame?

如果我不能直接在纹理对象中设置像素,我是否需要保留作为位图的DWORD数组,然后将纹理分配给每个帧?

Finally, while I'm initially assuming that I'll be doing this on the CPU, the per-pixel color calculations could probably also be done on the GPU. Is the HLSL code that sets the color of a single pixel in a texture, or are pixel shaders only useful for modifying the display pixels?

最后,虽然我最初假设我将在CPU上执行此操作,但每像素颜色计算也可能在GPU上完成。 HLSL代码是设置纹理中单个像素的颜色,还是像素着色器仅用于修改显示像素?

Thanks.

1 个解决方案

#1


First, your direct question:

首先,你的直接问题:

You can, technically, set pixels in a texture. That would require use of LockRect and UnlockRect API.

从技术上讲,您可以在纹理中设置像素。这需要使用LockRect和UnlockRect API。

In D3D context, 'locking' usually refers to transferring a resource from GPU memory to system memory (thereby disabling its participation in rendering operations). Once locked, you can modify the populated buffer as you wish, and then unlock - i.e., transfer the modified data back to the GPU. Generally locking was considered a very expensive operation, but since PCIe 2.0 that is probably not a major concern anymore. You can also specify a small (even 1-pixel) RECT as a 2nd argument to LockRect, thereby requiring the memory-transfer of a negligible data volume, and hope the driver is indeed smart enough to transfer just that (I know for a fact that in older nVidia drivers this was not the case).

在D3D上下文中,“锁定”通常是指将资源从GPU内存传输到系统内存(从而禁止其参与渲染操作)。锁定后,您可以根据需要修改填充的缓冲区,然后解锁 - 即将修改后的数据传输回GPU。通常锁定被认为是非常昂贵的操作,但是因为PCIe 2.0可能不再是主要关注点。你也可以指定一个小的(甚至1像素)RECT作为LockRect的第二个参数,从而要求内存传输一个可忽略不计的数据量,并希望驱动程序确实足够智能转移(我知道一个事实)在较旧的nVidia驱动程序中,情况并非如此)。

The more efficient (and code-intensive) way of achieving that, is indeed to never leave the GPU. If you create your texture as a RenderTarget (that is, specify D3DUSAGE_RENDERTARGET as its usage argument), you could then set it as the destination of the pipeline before making any draw calls, and write a shader (perhaps passing parameters) to paint your pixels. Such usage of render targets is considered standard, and you should be able to find many code samples around - but unless you're already facing performance issues, I'd say that's an overkill for a single 2D billboard.

实现这一目标的更有效(和代码密集)的方式确实永远不会离开GPU。如果您将纹理创建为RenderTarget(即,将D3DU​​SAGE_RENDERTARGET指定为其使用参数),则可以在进行任何绘制调用之前将其设置为管道的目标,并编写着色器(可能传递参数)以绘制像素。渲染目标的这种用法被认为是标准的,你应该能够找到许多代码样本 - 但除非你已经面临性能问题,否则我认为这对单个2D广告牌来说太过分了。

HTH.

#1


First, your direct question:

首先,你的直接问题:

You can, technically, set pixels in a texture. That would require use of LockRect and UnlockRect API.

从技术上讲,您可以在纹理中设置像素。这需要使用LockRect和UnlockRect API。

In D3D context, 'locking' usually refers to transferring a resource from GPU memory to system memory (thereby disabling its participation in rendering operations). Once locked, you can modify the populated buffer as you wish, and then unlock - i.e., transfer the modified data back to the GPU. Generally locking was considered a very expensive operation, but since PCIe 2.0 that is probably not a major concern anymore. You can also specify a small (even 1-pixel) RECT as a 2nd argument to LockRect, thereby requiring the memory-transfer of a negligible data volume, and hope the driver is indeed smart enough to transfer just that (I know for a fact that in older nVidia drivers this was not the case).

在D3D上下文中,“锁定”通常是指将资源从GPU内存传输到系统内存(从而禁止其参与渲染操作)。锁定后,您可以根据需要修改填充的缓冲区,然后解锁 - 即将修改后的数据传输回GPU。通常锁定被认为是非常昂贵的操作,但是因为PCIe 2.0可能不再是主要关注点。你也可以指定一个小的(甚至1像素)RECT作为LockRect的第二个参数,从而要求内存传输一个可忽略不计的数据量,并希望驱动程序确实足够智能转移(我知道一个事实)在较旧的nVidia驱动程序中,情况并非如此)。

The more efficient (and code-intensive) way of achieving that, is indeed to never leave the GPU. If you create your texture as a RenderTarget (that is, specify D3DUSAGE_RENDERTARGET as its usage argument), you could then set it as the destination of the pipeline before making any draw calls, and write a shader (perhaps passing parameters) to paint your pixels. Such usage of render targets is considered standard, and you should be able to find many code samples around - but unless you're already facing performance issues, I'd say that's an overkill for a single 2D billboard.

实现这一目标的更有效(和代码密集)的方式确实永远不会离开GPU。如果您将纹理创建为RenderTarget(即,将D3DU​​SAGE_RENDERTARGET指定为其使用参数),则可以在进行任何绘制调用之前将其设置为管道的目标,并编写着色器(可能传递参数)以绘制像素。渲染目标的这种用法被认为是标准的,你应该能够找到许多代码样本 - 但除非你已经面临性能问题,否则我认为这对单个2D广告牌来说太过分了。

HTH.