【问题标题】:Write to texture GLSL写入纹理 GLSL
【发布时间】:2015-01-22 19:00:33
【问题描述】:

我希望能够(在片段着色器中)将一个纹理添加到另一个纹理。现在我有投影纹理并想扩展它。

这是我目前所拥有的:

我还绘制了视锥体,蓝色/灰色测试图像沿着该视锥体投影到不断旋转的几何体上。

我的顶点着色器:

    ProjTexCoord = ProjectorMatrix * ModelTransform * raw_pos;

我的片段着色器:

vec4 diffuse = texture(texture1, vs_st);
vec4 projTexColor = textureProj(texture2, ProjTexCoord);
vec4 shaded = diffuse; // max(intensity * diffuse, ambient); -- no shadows for now
    if (ProjTexCoord[0] > 0.0 || 
        ProjTexCoord[1] > 0.0 ||
        ProjTexCoord[0] < ProjTexCoord[2] || 
        ProjTexCoord[1] < ProjTexCoord[2]){
        diffuse = shaded;
    }else if(dot(n, projector_aim) < 0 ){
        diffuse = projTexColor;
    }else{
        diffuse = shaded;
    }

我想要达到的目标:

例如,当用户按下按钮时,我希望将蓝色/灰色纹理写入球体上的灰色纹理并随其旋转。将其想象为“拍照”或在球体顶部绘画,以便在按下按钮后蓝色/灰色纹理随球体旋转。

由于片段着色器对每个像素进行操作,因此应该可以将一个像素一个像素地从一个纹理复制到另一个纹理,但我不知道怎么做,我可能在谷歌上搜索错误的东西。

我如何在技术上实现这一目标?什么方法最通用?非常感谢您的建议,如果需要更多代码,请告诉我。

【问题讨论】:

  • 帧缓冲对象是不是你想要的? songho.ca/opengl/gl_fbo.html
  • @MorphingDragon 我以前从未使用过 FBO。那么这个想法是FBO成为球体的最终输出纹理?有点像我不断修改的缓存纹理?
  • 差不多。无论如何,这将是唯一的 GPU 路线。
  • 对于从纹理到纹理的直接复制,您可以使用glBlitFramebuffer()。否则,将目标纹理设置为 FBO 附件,并对其进行渲染。

标签: c++ opengl glsl texture-mapping render-to-texture


【解决方案1】:

为了清楚起见,您想将贴花烘焙到球体的灰色纹理中。

在绘制另一个对象时写入灰色纹理的问题在于它不是一对一的。您可能会向同一个纹素写入两次或多次,或者单个片段可能需要写入灰色纹理中的许多纹素。这听起来很有吸引力,因为您已经在一个地方拥有了所有东西的坐标,但我不会这样做。

我首先创建一个纹理,其中包含灰色纹理中每个纹素的对象空间位置。这是关键,因此当您单击时,您可以渲染到灰色纹理(使用 FBO),并知道每个纹素在当前视图或投影纹理视图中的位置。可能存在边缘情况,即相同的纹理位出现在多个三角形上。您可以通过使用纹理坐标作为顶点位置将球体渲染到灰色纹理来做到这一点。你可能需要一个浮点纹理,下图可能不是球体的纹理映射,但它可以用于演示:P。

因此,当您单击时,您会在启用 Alpha 混合的情况下将全屏四边形渲染到灰色纹理。使用灰色纹理对象空间位置,每个片段计算蓝色纹理投影内的图像空间位置。丢弃纹理外部的片段,并在内部的片段中采样/混合。

【讨论】:

  • 我已经在 CPU 上实现了,结果如下:Link to results - 需要很长时间,所以我想在 GPU 上实现。 问题:我该怎么做呢?我的意思是:我以前从未使用过 FBO,并且发现很难理解这个概念 - 我是否为渲染到 FBO 创建了一个完全独立的垂直/片段着色器管道?我拥有的是标准 glUseProgram("myShader"); /*传递制服等*/ glUseProgram(0);图像项目()。我在代码中的哪里(如何)进行 FBO 渲染?
  • 哦,另外,由于我无法弄清楚 FBO 渲染,我尝试通过计算着色器(目前似乎也不起作用):Other Stack-question
【解决方案2】:

我认为你把事情复杂化了。

  • 经典着色器(即非计算着色器)内的纹理写入仅适用于最新的硬件和最新的 OpenGL 版本和扩展。
  • 如果使用不当可能会非常慢。引入管道停顿和 CPU-GPU 同步点非常容易
  • 像素着色器可能会变成非常缓慢且无法维护的混乱分支和纹理提取。
  • 所有这些乱七八糟的东西都会在每一帧的每一个像素上完成

解决方案:KISS

  • 只需在 CPU 端更新纹理即可。
  • 写入纹理,将部分内容替换为所需内容
  • 更新只需要在您需要时进行一次。数据会一直存在,直到您重写它(甚至不是每帧一次,而是每个更改请求仅一次)
  • 像素着色器很简单:没有分支,只有一个纹理
  • 要获取目标像素,请实施光线拾取(对于任何重要的交互式 3D 图形程序,无论如何您都需要它)

附: “一切都应该尽可能简单,但不能简单。”艾尔伯特爱因斯坦。

【讨论】:

  • 从 OpenGL3 开始就支持写入纹理,几乎不是最新版本和扩展。我建议更新您的答案以确保事实准确性。
  • @Drop:实际上我仅限于核心配置文件 440 及更高版本,所以我不太关心后向能力。但是,在 CPU 端这样做会有点乱,对吧?在我看来,我必须在 CPU 端进行投影才能更新纹理?我以前从未听说过光线拾取,我查一下。谢谢
  • @mike 你为什么不试试两者。熟悉混合 GPU 和 CPU 数据以及仅使用 GPU 编程对于 3D 程序员来说是一大优势。
  • @MorphingDragon 我们说的是Image load/store,而不是rendering to texture,对吧?
  • @mike 我认为如果您有“用户按下按钮”场景(如鼠标按钮?),那么您将需要使用任何渲染方法进行 CPU 非投影(获取 raw_pos)。
猜你喜欢
  • 1970-01-01
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多