1
\$\begingroup\$

I'm porting a game from iOS / Obj-C / OpenGL ES 2.0 to Unity.

I have a procedural mesh script that generates a batch of quads that need to blend together to create a game board. Some of the quads add a highlight effect, others on top of those darken the scene. This is handled with the blend mode and the color of the object.

In the old version I did things inefficiently and just drew each quad individually, as needed setting the blend mode (glBlendFunc) and a color uniform. I batched similar things as I could.

In Unity3D rather than having 500 sprite gameObjects which IMO would be difficult to manage. I have one gameObject with a mesh = one draw call. I use per vertex color attribute instead of a uniform to set colors for each quad/sprite. But I want to also set the blend mode per quad by using vertex data. I'm sending the blend mode as uv2 data.

I found this question. See the second answer: http://answers.unity3d.com/questions/399074/change-blend-mode-from-outside-shader.html

Which says you can do this:

Pass {
    Blend [MySrcMode] [MyDstMode]
}

But in the example MySrcMode and MyDstMode are shader properties (uniforms) and again would set the blend mode for the entire draw call. I want to change it per quad which would have to be done per fragment.

I understand GLSL shaders. They make sense to me. But Unity shaders are still a bit mysterious. The unity docs aren't getting through to me and I can't find any good tutorials on really how they work and what gets called in what order. I tried:

Blend [texcoord1.x] [texcoord1.y]

But that didn't work. (Meaning that it's not getting a value for texcoord1 there.) My Blend is above the Pass{}. Moving it inside the Pass either is the same or produces an error depending where it goes.

My other option would be to do something like a gl_LastFragData to fetch the current fragment and do my own per fragment blending.

Or do I have to pull out the quads that use a different blending into another game object. Which would mean having geometry sorted into game objects based on their blending mode and not their behavior or the script that creates and manages them.

\$\endgroup\$
2
\$\begingroup\$

If I have understood your approach, instead of drawing let's say a grid on nxn quads, you are building a mesh from all that quads and trying to render it with a single draw call, right?

Storing sprite colors into vertex color attributes it's fine, and that's a rather common approach.

For what concern blending (and not considering gl_LastFragData), you can't specify a different blend mode without using an additional drawcall neither on plain OpenGL, am I wrong?

In other words, you should setup different blend modes using glBlend in between drawing indexed primitives(glDrawElements), if all vertices are store inside the same VBO or VAO. Am I wrong?

But Unity shaders are still a bit mysterious. The unity docs aren't getting through to me and I can't find any good tutorials on really how they work and what gets called in what order. I tried:

Even if blend options (and lot of other stuff such as stencil test, depth test,..) are stored inside unity .shader files, their aren't compiled into shader code. AFAIK are just "meta data", used by the engine to setup blend modes just before the drawcall with the real compiled shader(that under the hood is just Cg or GLSL).

I guess the minimum number of draw call correspond to the different blend mode you need to support.

When you generate it and set the indices you can specify the submesh index they belong to. At each submesh you can (maybe must), assign a different material (that can have a different shader accordingly to the required blend mode).

Assuming you are using a single pass shader, you can have one draw call for each material. If you have multiple static meshes with the same materials, then unity can batch them together.

If you have multiple dynamic meshes, than you can consider using Graphics.DrawMesh with MaterialPropertyBlock in order to minimize state changes. (More drawcall, but cheaper due to less GPU state changes)

hope this helps

\$\endgroup\$
  • \$\begingroup\$ Yes. I have a 9x9 grid. I'm porting Big Bad Sudoku Book (iTunes) to Unity. Each cell can hold a highlight, plus a number or a bunch of small numbers. Also in this version the grid lines are also Quads. I don't know about submeshes. That sounds like the solution. What do you mean by static? The contents of the game board are changing and animating quite often. So probably not static? \$\endgroup\$ – badweasel Feb 1 '15 at 0:30
  • \$\begingroup\$ By static I mean transform of the mesh won't change over time (pos, rot,scale). If that's true and you mark the static checkbox on the relative GO, than Unity can batch several objects with the same material using a single draw call (pretransforming models into world space).. I just realize you have a single mesh so I'm going to fix the answer. \$\endgroup\$ – Heisenbug Feb 1 '15 at 0:35
  • \$\begingroup\$ @badweasel: I just had a quick look to your game's screenshot. I don't know if the dynamic mesh generation with multiple submesh will be the best approach.. take my answer as an hint on how drawing a mesh with multiple materials. Maybe you find some simpler and most efficient way for your specific use case scenario. \$\endgroup\$ – Heisenbug Feb 1 '15 at 0:50
  • \$\begingroup\$ One of those two will work. Things do animate as the game is first drawn and then played. Most is UV animation where the numbers "draw" on the screen like someone is writing them with a pen. This is multiple cells of a grid of sprites easily achieved via UV animation. Also the highlights turn on and off quite often. And sometimes I have things appear with opacity animation. I had it set up so that I could rotate the entire game board if the device orientation changes (rather than using autorotate). But this points me in the right direction thanks. \$\endgroup\$ – badweasel Feb 1 '15 at 1:20
  • 1
    \$\begingroup\$ I did the sub mesh approach and it's working great! Thanks. \$\endgroup\$ – badweasel Feb 1 '15 at 7:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.