【问题标题】:Mixing different Program3Ds results in some objects not rendering混合不同的 Program3D 会导致某些对象无法渲染
【发布时间】:2012-04-07 11:41:39
【问题描述】:

我在使用 Stage3D 时遇到了一些意想不到的事情。我为我的对象制作了两个不同的着色器程序。其中一个程序用于使用纹理位图和 uv 数据。另一个只是使用颜色数据。这两个对象非常不同,因为最终,我将使用纯色和简单的渲染逻辑显示一些内容(如方向线、高光等),而其他内容(如实际对象、背景等)将使用 mipmap 等进行渲染向前。问题是当我使用这两个非常不同的着色器程序时,只有一个可以工作。所以要么出现我所有的纯颜色对象,要么出现我所有的纯纹理对象。显然,我希望两者都出现。

这是我的纹理对象的 agal 代码:

顶点着色器:

//4x4 matrix multiply to get camera angle
"m44 op, va0, vc0\n" + 
//tell fragment shader about xyz
"mov v0, va0\n" + 
//tell frament shader about uv
"mov v1, va1\n" + 
//tell fragment shader about RGBA
"mov v2, va2\n"

片段着色器:

//grab the texture color from texture 0 and
//the uv coordinates from varying register 1 and
//store the interpolated value in ft0
"tex ft0, v1, fs0 <2d,linear,repeat,miplinear>\n" + 
//move this value to the output color
"mov oc, ft0\n"

这些对象的渲染代码如下所示:

context3D.setProgram(_renderProgram);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, renderMatrix, true);
context3D.setTextureAt(0, texture);

// vertex position to attribute register 0
context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(1, uvBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context3D.setVertexBufferAt(2, colorsBuffer, 0, Context3DVertexBufferFormat.FLOAT_4);

这是我的纯色对象(即没有纹理)的 agal 代码:

顶点着色器:

"m44 op, va0, vc0\n" + // pos to clipspace
"mov v0, va1" // copy color

片段着色器:

"mov oc, v0 "

这些对象的渲染代码如下所示:

context3D.setProgram(_renderProgram); 
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, renderMatrix, true);
// vertex position to attribute register 0
context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
// color to attribute register 1
context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);

由于某种我无法弄清楚的原因,我将不同的数据分配给不同的不同寄存器索引 (va) 的事实导致其中一个渲染过程失败。如果我首先在纹理循环中渲染纹理对象,我所有的彩色对象都会消失,反之亦然。对象将在第一帧正确显示。但一旦渲染循环播放第二次,就会发生这种意外行为。

我发现如果我通过添加以下内容来修改颜色对象的渲染代码:

context3D.setTextureAt(0, null);
context3D.setVertexBufferAt(2, null);

它有效。但这确实不是一个好的解决方案。我不想知道在我的程序的某个地方,另一个对象正在使用 n 个不同的寄存器进行渲染,所以如果另一个 program3D 实例需要小于 n,我必须将所有那些未使用的 va 设置为 null。此外,如果我为现在需要第 4 个 va 的某个对象(例如发光对象)创建一个新的着色器程序,现在我必须返回并修改所有其他着色器程序以将 va4 设置为 null,以便一切都可以渲染。这是真的吗?当然,我在这里遗漏了一些东西。设置我所有的纹理寄存器 (ft) 也是如此。

我可以提供更多信息...

【问题讨论】:

  • 暂时不会添加这个作为答案,但我在以下链接中发现了一些有趣的东西:en.nicoptere.net/?p=2119#more-2119:“问题是这个顶点缓冲区在 drawTriangles() 调用之后将保留在内存中当你要绘制下一个对象时,GPU 会期望着色器使用它,如果不使用它就会崩溃。所以在渲染任何东西之前,最好实现一个 3 步渲染逻辑。”
  • 他接着说,在每次调用 drawTriangles() 后,他都会从 GPU 中取消分配资源。例如: context.setVertexBufferAt( 0, null );// ->va0 = null; context.setVertexBufferAt( 1, null );// ->va1 = null; context.setTextureAt( 0, null );// -> fs0 = null
  • 您是否遇到任何实际错误,或者您的代码无法正常工作?你能提供更多的源代码吗?最好看看你设置程序和 drawTriangles() 的顺序。

标签: flash fragment-shader vertex-shader stage3d molehill


【解决方案1】:

在这里挖掘一个旧帖子。我注意到你的 cmets 并认为我会提到(主要是为了未来的读者的利益)你偶然发现的实际上是为了纠正解决方案。准备在屏幕上绘制 3D 对象时,典型过程如下所示:

  • 定义/编译/上传程序
  • 上传顶点和纹理
  • 开始渲染循环
    • 开始对象循环
      • 设置程序
      • 设置常量
      • 设置输入缓冲区和纹理
      • 调用drawTriangles()
      • 将输入缓冲区和纹理设置为 null
    • 结束对象循环
    • 调用 present()
  • 结束渲染循环

【讨论】:

    【解决方案2】:

    不幸的是,您似乎是对的 - 至少这是我找到并实施的解决方案。必须“清除”以前传递的纹理...

    context3D.setTextureAt(<n>, null);
    

    ...否则您的无纹理着色器仍会期望纹理并且不会渲染。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-28
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 1970-01-01
      • 2021-01-17
      • 1970-01-01
      • 2012-04-04
      相关资源
      最近更新 更多