Draw Shadows using DisplayPipeline.PostDrawObjects()

@jeff,

I just discovered one more issue. PostDrawObjects in RhinoCommon’s conduits don’t show up in ghosted display mode when obscured by other geometry:

Shaded:

Ghosted:

Wireframe:

Is this something the new SC_CUSTOMRENDEROBJECTS channel would address as well?

Yes… but it still won’t get it 100% correct. Here’s why…

First, let me just say that there is no such thing as “transparency” (or shadows) to a computer or to any graphics library. A red pixel looks red because the hardware emits red when the proper value is stored in the proper memory location. There is no “transparent” or “shadow” value that you store or ask some API to create. Both of those are done through “trickery” to convince your brain that what you’re looking at is transparent or a shadow.

With that said… The transparency “effect” (the one Rhino implements, there are several other techniques, but Rhino tries to be the most realistic) is created by blending overlapping colors/pixels … which means that all non-transparent pixels must get drawn first, then all transparent overlapping pixels must get drawn last…and those pixels must get drawn in a back-to-front order (aka. The Painter’s Algorithm), since they also occupy and populate the depth buffer. But, it’s a little more complicated than that because of “open” and “closed” (i.e. solid) objects…which introduces backface vs. frontface issues…and is why I said that Rhino still can’t get it 100% correct with 3rd party objects that don’t exist in the document…

I basically need to be able to iterate through all of “your” objects one at a time…and iterate through all of some other plugin’s objects one at a time…but at the same time (if you know what I mean)…which currently is impossible. The reason… The backfaces of an object are drawn with a given buffer state, followed by its front faces with a different buffer state, based on whether it’s an “open” or “closed” object…and this must be done on a per-object per-iteration manner…and I don’t have any idea how many objects you’ll be drawing, much less get access to them one at a time (as well as know what Z-order they follow, or even if your objects contain transparent materials). We can certainly come up with an API set that provides for this, but right now, nothing even remotely close exists.

So… The best we can do right now is to interleave your drawing somewhere within this process. It won’t look as you’d expect (sometimes it might), due to ordering and backfaces overlapping frontfaces issues, etc… but it’s better than what’s getting done now… The same issues exist for producing shadow maps and shadow buffers.

I also believe I can get your objects to participate better in Technical modes now too…although I’m guessing that the “hidden line” feature will prove to be a headache…we’ll see.

Unfortunately, we’re too close to an SR13 release, so I’m not going to put any of this into 8.13…it’s all in 8.14 atm…sorry.

-J

Thanks for a detailed explanation @jeff!

I understand that there is a lot of heavy lifting you need to do on your end to figure this out. Consider my feedback as input for R9, where you can introduce more substantial changes.

In the meantime, I’m fine with hacking my way around the display pipeline. Would going directly to OpenGL help in any way? I’m doing this already in parts of my plugin to leverage some custom GLSL shader magic. For now, I’m mostly drawing meshes as shown below, but could intercept the image buffer Rhino generates and add my pixels there in between passes.

It’s a bit heavy-handed, but I’m feeling adventurous with this project :slight_smile:

        public static void DrawMeshes(ShaderProgram program, List<MeshGPUData> meshes, DisplayPipeline display)
        {
            OpenGL.glUseProgram(program.Id);
            BuiltIn.AddDefaultUniforms(program.Id, display);
            program.AddUserDefinedUniforms();

            foreach (var gpuMesh in meshes)
            {
                OpenGL.glBindVertexArray(gpuMesh.VertexArrayObject);
                OpenGL.glDrawElements(OpenGL.GL_TRIANGLES, gpuMesh.IndexCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero);
            }

            // Unbind the VAO and shader program after drawing
            OpenGL.glBindVertexArray(0);
            OpenGL.glUseProgram(0);
        }

You can draw the meshes however you want, either your own shader or use Rhino’s API…but it’s not going to solve any of the issues I mentioned.

The bottom line is that all of your objects/meshes need to be output at the same time all of the other objects/meshes are output… But I can’t iterate multiple object lists simultaneously, I can only iterate through Rhino’s objects, and then call into conduits to have them iterate through their own object list(s)…but by then it’s too late because Rhino has already drawn all of its objects and you’re coming in after (or before) that, not during.

We need some kind of object queueing mechanism where Rhino can queue up everyone’s objects (and materials) prior to drawing anything…where it can then include them in the main iteration… Something that’s going to require a lot of thought and planning…so it’s a V9 thing definitely.

-J

1 Like