Mixing different Program3Ds results in some objects not rendering

348 Views Asked by At

I have encountered something unexpected working with Stage3D. I have made two different shader programs for my objects. One of the programs is for using textured bitmaps and uv data. The other simply uses color data. The two objects are very different because eventually, I will display some things (like directional lines, highlights, etc) using solid colors and simple rendering logic while other things (like actual objects, background, etc.) will be rendered with mipmaps and so forth. The problem is that when I use these two very different shader programs, only one or the other works. So either all my color-only objects appear or all my texture-only objects appear. Obviously, I want both to appear.

Here is my agal code for the textured objects:

vertex shader:

//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"

fragment shader:

//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"

The rendering code for these objects looks like this:

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);

Here is my agal code for plainly colored objects (ie no texture):

vertex shader:

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

fragment shader:

"mov oc, v0 "

The rendering code for these objects looks like this:

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);

For some reason that I cannot figure out, the fact that I am assigning different data to different varying register indices (va) is causing one of the render procedures to fail. If I render a texture object first in my texture loop, all my colored objects disappear and vice-versa. The objects will appear correctly for the very first frame. But as soon as the render loop plays a second time, this unexpected behavior occurs.

I discovered that if I modify the color object's rendering code by adding the following:

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

It works. But this is really not a good solution. I don't want to have to know that somewhere in my program another object is rendering with n varying registers so if another program3D instance needs less than n, I have to set all those unused va to null. Also, if I make a new shader program for some object (for example a glowing object) that now needs a 4th va, now I have to go back and modify all my other shader programs to set va4 to null so that everything will render. Is this for real? Surely I am missing something here. Same thing goes for setting all my texture registers (ft).

I can supply much more information...

2

There are 2 best solutions below

0
On

digging up an old post here. I noticed your comments and thought I'd mention (mostly for the benefit of future readers) that what you stumbled on is, in fact, to correct solution. When preparing to draw a 3D object to the screen, the typical process looks like this:

  • define/compile/upload program
  • upload vertices and textures
  • begin render loop
    • begin object loop
      • set program
      • set constants
      • set input buffers and textures
      • call drawTriangles()
      • set input buffers and textures to null
    • end object loop
    • call present()
  • end render loop
0
On

Unfortunately, it seems like you are correct - at least this has been the solution I found and implemented. Previously passed textures have to be 'cleared'...

context3D.setTextureAt(<n>, null);

...otherwise your texture-less shader will still expect the texture and will not render.