如何操纵纹理内容?

我有一个iPad的应用程序,我正在考虑的一个可能的function是允许用户触摸图像和变形。

基本上,图像就像绘画,当用户在图像上拖动手指时,图像将变形,被触摸的像素将沿图像“拖动”。 对不起,如果这是很难理解,但底线是,我们要编辑的dynamic纹理内容随着用户交互。

有这样的一个有效的技术? 我试图弄清楚需要做些什么以及将会有多大的操作。

现在我唯一能想到的就是根据触摸的位置search纹理的内容,复制像素数据,并在手指移动时对现有像素数据进行一些混合。 然后定期用glTexImage2D重新加载纹理来获得这个效果。

至less有两种根本不同的方法:

1.更新像素 (我认为这是你在问题中的意思)

改变纹理中像素的最有效技术叫做渲染到纹理,可以通过FBO在OpenGL / OpenGL ES中完成。 在桌面OpenGL上,您可以使用像素缓冲区对象( PBO )来直接在GPU上操作像素数据(但OpenGL ES目前还不支持)。

在未使用OpenGL的情况下,您可以更改系统内存中的像素,然后使用glTexImage2D / glTexSubImage2D更新纹理 – 但是这是效率不高的最后解决scheme,应尽可能避免。 glTexSubImage2D通常要快得多,因为它只更新现有纹理中的像素,而glTexImage2D创build全新的纹理(作为一个好处,您可以更改纹理的大小和像素格式)。 另一方面,glTexSubImage2D允许仅更新纹理的一部分。

你说你想让它与OpenGL ES一起工作,所以我build议按照以下步骤操作:

  • 用glTexSubImage2D()replaceglTexImage2D() – 如果你获得了足够的性能,就让它成为;
  • 使用FBO和着色器实现渲染到纹理 – 要重写代码需要更多的工作,但会带来更好的性能。

对于FBO来说,代码可以像这样:

// setup FBO glGenFramebuffers( 1, &FFrameBuffer ); glBindFramebuffer( GL_FRAMEBUFFER, FFrameBuffer ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, YourTextureID, 0 ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); // render to FBO glBindFramebuffer( GL_FRAMEBUFFER, FFrameBuffer ); glViewport( 0, 0, YourTextureWidth, YourTextureHeight ); your rendering code goes here - it will draw directly into the texture glBindFramebuffer( GL_FRAMEBUFFER, 0 ); // cleanup glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glDeleteFramebuffers( 1, &FFrameBuffer ); 

请记住,不是所有的像素格式都可以渲染到。 RGB / RGBA通常很好。

2.更新几何

您也可以更改纹理映射的对象的几何形状。 几何graphics应该足够精确,以保证平滑的交互并防止出现伪像。 几何变形可以通过不同的方法完成:参数曲面,NURBS,补丁。

我已经尝试了两件事情可以解决你的问题。 方法是相当不同的,所以我想你的具体用例将决定哪一个是适当的(如果有的话)。

首先,我已经完成了几何图像变形。 也就是说,将我的纹理映射到一个细分网格,然后将这个网格与另一个贝塞尔控制点网格重叠。 然后用户将移动这些控制点,从而以平滑的方式使渲染的几何graphics的顶点变形。

第二种方法更类似于您在问题中概括的内容。 当创build你的纹理保持这些数据,所以你可以直接在那里操纵像素。 然后打电话来

 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); 

每次画画。 这可能是非常低效的,因为它可能涉及重新上传所有纹理数据的每一帧,我很想听听是否有更好的方法来做到这一点,如直接操纵GPU上的纹理数据。 就我而言,虽然performance足够。

我希望这有助于,即使它的细节很less。

使用FBO修改纹理渲染目标是棘手的,但非常直接。

所以,我们有:

  1. TW由TH离屏缓冲区(与纹理相关) – 我们称之为Dest
  2. 新的“像素arrays”,通过IH纹理的IW – 我们称之为Src
  3. 将(IW x IH)纹理放置在位置(TX,TY)到Dest纹理的愿望

把“Src”放到Dest的技巧是

  1. 绑定生成的FBO作为渲染目标
  2. (TX,TY),(TX + IW,Y),(TX + IW,TY + IH),(TX,TY + IH)和纹理坐标(0,0),使用虚拟4顶点四元组,(1,0),(1,1),(0,1)
  3. 绑定一个平凡的像素着色器,它读取绑定到第一个纹理单元的Src纹理,并将其输出到“屏幕”(又名渲染目标,Dest)
  4. 渲染四边形
  5. 解开FBO

要使Src正确渲染,必须使用正交投影和身份相机变换。

我的4步解决scheme中的(TX,TY)和(IW,IH)坐标必须分别被TW和TH分开,以正确映射到[0..1,0..1]帧缓冲区大小。 为了避免在着色器中出现这些分割,您可以使用[0..TW,0..TH]视口的适当的正交投影。

希望这可以解决FBO的问题。