UltravioletFramework / ultraviolet

The Ultraviolet Framework is a .NET game development framework written in C#.
https://github.com/UltravioletFramework/ultraviolet/wiki
MIT License
542 stars 46 forks source link

Shaders. #133

Closed Donaut closed 4 years ago

Donaut commented 4 years ago

Does anybody have a simple example of how to use them? I'm having a hard time understanding how to use multiple shaders in one texture. Thanks for every help.

fireball87 commented 4 years ago

I only use a single custom shader and don't use passes, but I'll try to help as much as i can. https://github.com/tlgkccampbell/ultraviolet/wiki/Creating-Effects talks about it if you missed that, and the effects file, which is what you're going to need.

Some of the ultraviolet samples load custom effects, but none of them seem to use multiple passes. https://github.com/tlgkccampbell/ultraviolet-samples/blob/4390170349cbbc4ff211e50b823753e9491ff3e5/Sample15_RenderTargetsAndBuffers/Sample15_RenderTargetsAndBuffers.Shared/Game.cs loads an effect and then uses it with their spritebatch.

and https://github.com/tlgkccampbell/ultraviolet-samples/blob/4390170349cbbc4ff211e50b823753e9491ff3e5/Sample3_RenderingGeometry/Sample3_RenderingGeometry.Shared/Game.cs applies a stock effect with a standard.

From prior conversations i don't believe you combine effects on a single object without setting them up as separate passes in the same effect chain, but perhaps I could be wrong, especially outside of sprite batch. Searching for shader on the gitter has a couple discussions about them.

--edit-- actually, i don't think passes really work for things that it doesn't make sense to draw multiple times (so they'd be useful for say, producing something that provides cell shading, and then adding an outline to that drawn over) I think the standard way to combine shader effects ends up being to write a single shader that contains code for all of your desired effects for the scene, and then toggle them on and off using properties

tlgkccampbell commented 4 years ago

@fireball87 is correct with his edit. Multiple passes require multiple Draw() calls. Conceptually, an EffectPass instance is basically equivalent to a single OpenGL shader program, which means that applying a new pass requires changing the device state. You either have to do all of your calculations in a single shader program, or draw the meshes multiple times.

If you could provide an example of what you're trying to do, I could probably give you more detailed advice.

The documentation around shaders should probably be improved, especially now that I'm working on more powerful 3D abstractions for which BasicEffect and SpriteBatchEffect aren't going to suffice. I'll leave this issue open until I can write that documentation.

tlgkccampbell commented 4 years ago

For sake of reference, if you want to create an Effect instance with multiple techniques or passes, you need to create an XML or JSON file that describes the effect and load that with ContentManager instead of directly loading a shader file.

Here's an example of such a JSON file:

{
  "parameters": [ "MatrixTransform", "TextureSize", "Texture", "ColorGradingLUT" ],
  "techniques": [
    {
      "name": "Technique0",
      "passes": [
        {
          "name": "Pass0",
          "stages": {
            "vert": "ColorGrading.vert",
            "frag": "ColorGrading.frag"
          }
        }
      ]
    }
  ]
}
tlgkccampbell commented 4 years ago

I've updated the documentation on shaders.

Donaut commented 4 years ago

Wow. Thank you so much.