SlimDX/DirectX9/C# - 如何访问纹理中的像素数据

2023-11-29

这是我在 StackOverflow 上遇到的第一个问题,万岁!我可以诚实地说,我每天都使用 StackOverflow 来处理我的工作和个人编程谜题。 99.9% 的情况下,我实际上也在这里找到了我需要的答案,这太棒了!

我当前的问题实际上让我有点困惑,因为我似乎找不到任何真正有效的东西。我已经阅读了 GameDev.net 上的几篇文章,并在网上找到了其他资源,但无法整理出来。

我正在将我为 XNA 编写的小型 2D 引擎移植到 SlimDX(目前只是 DirectX9),这是一个很好的举措,因为我在短短几天内就比我在几天内了解了更多有关 DirectX 内部工作原理的信息。与 XNA 合作六个月。我完成了大部分基本渲染功能,并且实际上成功地重新创建了具有大量附加功能的 XNA SpriteBatch(我在 XNA 中真的很怀念)。

我试图开始工作的最后一件事是从给定纹理中提取源矩形并将其用于平铺。原因:不平铺时,您可以随意使用 UV 来获取想要显示的源(例如:0.3;0.3 到 0.5;0.5),但是平铺时,您需要 UV 来平铺(0;0 到 2;2)意味着平铺图像两次),因此需要剪切纹理。

长话短说,我尝试使用以下内容:

DataRectangle dataRectangle = sprite.Texture.LockRectangle(0, LockFlags.None);
Format format = sprite.Texture.GetLevelDescription(0).Format;

byte[] buffer = new byte[4];
dataRectangle.Data.Read(buffer, ([y] * dataRectangle.Pitch) + ([x] * 4), buffer.Length);
texture.UnlockRectangle(0);

我尝试了不同的像素,但似乎都给出了虚假数据。例如,我实际上尝试使用当前的头像来查看从 DataRectangle 获取的缓冲区是否与图像中的实际像素匹配,但没有运气(甚至检查了格式是否正确,确实如此)。

我究竟做错了什么?有更好的方法吗?或者我的紫外线故事是错误的吗?可以解决吗? 比平铺之前切掉源矩形要简单得多吗?

感谢您的时间,

伦纳德·方泰因

更新#1

实际上,我设法使用以下字节数组转换将像素数据导出到位图:

int pixel = (buffer[0] & 0xFF) | ((buffer[1] & 0xFF) << 8) | ((buffer[2] & 0xFF) << 16) | ((255 - buffer[3] & 0xFF) << 24);

所以数据看起来并不像我想象的那么假。然而,我的下一个问题是抓取源矩形中指定的像素并将它们复制到新纹理。我试图剪切的图像是 150x150,但由于某种原因它被拉伸到 256x256 图像(2 的幂),但当实际尝试访问超过 150x150 的像素时,它会抛出 OutOfBounds 异常。另外,当我实际尝试创建第二个尺寸为 256x256 的空白纹理时,无论我放入什么,它都会变成全黑的。

这是我当前的代码:

//Texture texture = 150x150
DataRectangle dataRectangle = texture.LockRectangle(0, LockFlags.None);
SurfaceDescription surface = texture.GetLevelDescription(0);

Texture texture2 = new Texture(_graphicsDevice, surface.Width, surface.Height, 0, surface.Usage, surface.Format, surface.Pool);
DataRectangle dataRectangle2 = texture2.LockRectangle(0, LockFlags.None);

for (int k = sourceX; k < sourceHeight; k++)
{
    for (int l = sourceY; l < sourceWidth; l++)
    {
        byte[] buffer = new byte[4];
        dataRectangle.Data.Seek((k * dataRectangle.Pitch) + (l* 4), SeekOrigin.Begin);
        dataRectangle.Data.Read(buffer, 0, 4);

        dataRectangle2.Data.Seek(((k - sourceY) * dataRectangle2.Pitch) + ((l - sourceX) * 4), SeekOrigin.Begin);
        dataRectangle2.Data.Write(buffer, 0, 4);
    }
}

sprite.Texture.UnlockRectangle(0);
texture2.UnlockRectangle(0);

_graphicsDevice.SetTexture(0, texture2);

所以我的新(附加)问题是:如何将像素从一个纹理移动到另一个较小的纹理(包括 Alpha 通道)?当我的原始纹理是 150x150 时,为什么 SurfaceDescription 报告为 256x256?


回答我自己的问题有点尴尬,但经过更多的挖掘和简单的试验和错误,我找到了解决方案。

首先,我必须改变加载纹理的方式。为了防止它在内部调整为二次幂大小,我必须使用以下方法:

Texture texture = Texture.FromFile(_graphicsDevice, [filePath], D3DX.DefaultNonPowerOf2, D3DX.DefaultNonPowerOf2, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None, 0);

请注意我如何具体指定大小为非二的幂。

接下来,我的新纹理定义有一个错误。我必须指定 1 个级别,而不是指定 0 个级别(并使其自动生成 MipMap),如下所示:

Texture texture2 = new Texture(_graphicsDevice, [sourceWidth], [sourceHeight], 1, surface.Usage, surface.Format, surface.Pool);

完成此操作后,我在实际问题中的 for 循环工作正常:

DataRectangle dataRectangle = texture.LockRectangle(0, LockFlags.None);
SurfaceDescription surface = texture.GetLevelDescription(0);

DataRectangle dataRectangle2 = texture2.LockRectangle(0, LockFlags.None);

for (int y = [sourceX]; y < [sourceHeight]; k++)
{
    for (int x = [sourceY]; x < [sourceWidth]; l++)
    {
        byte[] buffer = new byte[4];
        dataRectangle.Data.Seek((y * dataRectangle.Pitch) + (x * 4), SeekOrigin.Begin);
        dataRectangle.Data.Read(buffer, 0, 4);

        dataRectangle2.Data.Seek(((y - [sourceY]) * dataRectangle2.Pitch) + ((x - [sourceX]) * 4), SeekOrigin.Begin);
        dataRectangle2.Data.Write(buffer, 0, 4);
    }
}

texture.UnlockRectangle(0);
texture2.UnlockRectangle(0);

_graphicsDevice.SetTexture(0, texture2);

括号中的所有内容都被视为此代码段外部的变量。我想 _graphicsDevice 已经足够清楚了。我知道 .Seek 可以简化,但我认为它对于示例目的来说效果很好。请注意,我不建议每帧都执行此类操作,因为如果使用错误,它会很快耗尽 FPS。

我花了很长时间才弄清楚,但结果是令人满意的。我要感谢所有看到这个问题并试图帮助我的人。

伦纳德·方泰因

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SlimDX/DirectX9/C# - 如何访问纹理中的像素数据 的相关文章

  • Spark Streaming DStream RDD 获取文件名

    火花流textFileStream and fileStream可以监视目录并处理 Dstream RDD 中的新文件 如何获取 DStream RDD 在特定时间间隔正在处理的文件名 fileStream产生UnionRDD of New

随机推荐

  • Spacy:尝试设置冲突的文档:令牌只能是一个实体的一部分,因此请确保您设置的实体不重叠

    我尝试使用 spacy 从文本中提取所需的自定义实体 import spacy from spacy lookup import Entity data 0 count 1 unique count unique def processTe
  • Android:ADT无法识别Nougat logcat的格式

    我有一个 旧 ADT Eclipse IDE for Android Developers 23 0 2 1259578 adtproduct 连接到 Nougat Pixel C ADT 无法正确读取 logcat 的格式 如以下屏幕截图
  • Azure 定价 API

    azure 是否有类似于 AWS 用于产品列表和定价目录的定价 api 例如 要获取 EC2 定价和产品目录 AWS 提供了JSON CSV 文件 想知道Azure是否有类似的东西 https prices azure com api re
  • 如何在 awk 表达式中使用变量

    我正在尝试执行这个命令 sed bla bla filename awk printf s s entry 3f 3f 3f 3f 1 3 4 5 6 7 但问题是 我希望 3f 部分是可变的 因此 在一种情况下 它可能是 3f 在另一种情
  • 处理带参数的点击手势 iphone / ipad

    当我的点击手势触发时 我需要发送一个额外的参数 但我一定做了一些非常愚蠢的事情 我在这里做错了什么 这是我正在创建和添加的手势 UITapGestureRecognizer tapGesture UITapGestureRecognizer
  • ProcessBuilder 不会停止

    我正在尝试使用 Linux 下的 ProcessBuilder 类将 mp3 文件解码为 wav 文件 由于某种原因 该过程不会停止 因此我必须手动取消它 有人可以给我一个提示吗 我认为引用的代码很容易重现 import java io p
  • 验证数学方程 C++ [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我目前正在尝试构建一个非常简单的编译器 我创建了一个函数 使用调车场算法将中缀表示法的数学方程转换为 RPN 但是我遇到了问题 我没有在转换函数中包含错误检查 因此我想知道是否有
  • 在 PHP 中的嵌套关​​联数组中搜索值并返回其路径

    我正在尝试在 PHP 中的嵌套关 联数组中搜索值 很像 array search 但嵌套 我需要导致该特定值的所有键 我没有看到任何关于此特定功能的帮助 所以现在我要问 其他示例似乎返回数组中的所有值 而不仅仅是单个键 值对的路径 func
  • MonoTouch Enterprise - 部署

    我们公司已开始构建用于企业部署的 MonoTouch iPad iPhone 应用程序 如何使用该应用程序并创建 ipa 文件以上传到我们的 MDM 服务器 ipa 文件基本上是一个美化的 zip 文件 您可以选择以下几条路线 将项目导出到
  • 带路径的 PHP 数组中的递归搜索

    我有这个干草堆数组 array name gt Intro id gt 123 children gt name gt foo id gt 234 children gt name gt mur id gt 445 name gt chap
  • 无法找到可安装的 ISAM 错误疑难解答

    我安装了 32 位 MS Office 2013 以及 32 位 Office 可再发行组件和一个设置为编译为 32 位的小型 C 控制台应用程序 以下代码会导致OleDbException提示 找不到可安装的 ISAM public vo
  • mysql_query 仅返回 int/fload 数据库类型的字符串类型

    我正在尝试处理 MySQL 选择结果 我的问题是下面的示例代码仅返回一个包含所有值的数组string 甚至对于包含整数和浮点数的列也要键入 sth mysql query selectstr rows array while r mysql
  • Rcpparmadillo :将 fastLM 对象转换为“lm”类型

    首先感谢您提供这么好的包裹 我希望对 fastLM 的输出运行 anova 但是 anova 只接受 lm 类型的对象 有没有办法将 fastLM 对象转换为 lm 对象 谢谢 S 首先 fastLM 存在是为了提供比lm 使其更快的方法之
  • “你好,世界!”遇到了意想不到的困难

    我想学习 Clojure 我已经下载并设置了以下小工具 Clojure 1 6 0 来自官方网站 莱宁根2 4 3 来自 GitHub 的苹果酒 0 6 0 我已经成功了 现在我正在尝试打印消息 Hello World 同时从 Emacs
  • Google 日历 API - 创建活动时邀请电子邮件不会发送给与会者

    我想使用 google api 将事件添加到 google 日历 但活动创建后 邀请电子邮件不会发送到与会者电子邮件列表 这是我的代码
  • python 正则表达式仅匹配第一个实例

    我有一个 python 代码 我正在读取证书并仅匹配根证书 例如 我的证书如下 begin certificate CZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk IasdasdassZAEZFgp2aXJ0dW
  • Android:多个警报不起作用

    在我的应用程序中 我设置了两个闹钟 在 ToogleButton 上 我将使用以下代码将其设置为打开 case R id toggleButtonTwoMonth myPrefs this getSharedPreferences myPr
  • 如何在内核中放置微秒延迟?

    我想放置微秒延迟Linux kernel 哪些函数支持它 需要添加什么头文件 你最好读书Documentation timers timers howto txt在linux内核源代码中 简而言之 您可以使用msleep unsigned
  • 为什么PWA提倡添加到主屏幕但只是创建chrome快捷方式而不是安装为apk?

    我检查所有添加到主屏幕条件 我想我在我的 PWA 中提供了所有这些 当用户访问我的 PWA 迷你信息栏时 当用户单击 添加到主屏幕 时 仅将 PWA 的快捷方式添加到主屏幕 但未安装 PWA 不在应用程序列表中 并且深层链接不起作用 UPD
  • SlimDX/DirectX9/C# - 如何访问纹理中的像素数据

    这是我在 StackOverflow 上遇到的第一个问题 万岁 我可以诚实地说 我每天都使用 StackOverflow 来处理我的工作和个人编程谜题 99 9 的情况下 我实际上也在这里找到了我需要的答案 这太棒了 我当前的问题实际上让我