Postprocessing: For real

Everything about development and the OpenMW source code.
User avatar
wazabear
Posts: 96
Joined: 13 May 2020, 19:31
Gitlab profile: https://gitlab.com/glassmancody.info

Re: Postprocessing: For real

Post by wazabear »

Weekend update. I've come a long way past few days, cleaned up the post processing framework and added paths for non desktop GL to deal with the different ping ponging techniques. Changes are still local.

Most importantly, I've begun work on `omwfx` format. The grammar is pretty simple and I've implemented a recursive descent parser that utilizes the variant/optional c++17 features. The parser is almost complete, but needs some polish.

Here is a small example of what an omwfx file will look like. Note, block order is not important! There are a couple restrictions on code blocks but they are not limiting at all, simply version and extension macros are handled by the technique block. The technique name is defined by the filename.

Code: Select all


technique {
    passes = pass1,pass2(vec2(1,0)), pass1, pass2(vec2(0,1));
    version = 150;
    extensions = GL_EXT_gpu_shader4, GL_EXT_gpu_shader5;
}

render_target {
   // render all statics and particles with rgb16g format as a forward pass, available as a sampler in all passes
    mask = statics,particles;
    color_format = rgb16f;
}

sampler_1D lutTex {
    source = "textures/lut.png";
    wrap_s = repeat;
}

uniform_Vec4 foo {
    default = vec2(1,2);
    min = vec2(1,2);
    max = vec2(10,20);
    description = "controls some random thing";
    static = true; // static ones are const, non-static onces are literal uniforms which can be set with something like a lua-interface
    widget = slider; // defining a widget automatically adds this to in-game configuration menu
}

vertex pass2 {
    // use forward pass we defined earlier as a sampler
    uniform sampler2D render_target;

    // arbitrary valid GLSL code
}

fragment pass2(vec2 blurDirection) {
    // arbitrary valid GLSL code
}

vertex pass1 {
    // arbitrary valid GLSL code
}

fragment pass1() {
    // arbitrary valid GLSL code

}
User avatar
AnyOldName3
Posts: 2668
Joined: 26 Nov 2015, 03:25

Re: Postprocessing: For real

Post by AnyOldName3 »

Do we want our own parser rather than just our own grammar? We're going to need BISON (or was it YACC?) in the future as the later BGS scripting languages use it.
User avatar
psi29a
Posts: 5356
Joined: 29 Sep 2011, 10:13
Location: Belgium
Gitlab profile: https://gitlab.com/psi29a/
Contact:

Re: Postprocessing: For real

Post by psi29a »

If we're going to need that later, then let's try to leverage those.
User avatar
wazabear
Posts: 96
Joined: 13 May 2020, 19:31
Gitlab profile: https://gitlab.com/glassmancody.info

Re: Postprocessing: For real

Post by wazabear »

If anyone is more familiar with these tools they can correct me, but as far as I can tell the only way to use such parsers/lexers is to parse the entire input. It is a bit tricky here as I don't parse code blocks, so if we used these tools we'd need to parse the GLSL (and introduce a GLSL language dependency that doesn't exist with a hand-rolled parser).

The EBNF for omwfx cannot be represented without a set of rules which encapsulates the entire GLSL grammar. What you beed is a special "jump" function that is able to skip over an arbitrary block with some very specific rules which aren't natural to a grammar in of itself.
Ebonair
Posts: 25
Joined: 04 Dec 2018, 20:08

Re: Postprocessing: For real

Post by Ebonair »

I think this should be quite possible with Flex/Bison or similar. You could introduce a rule like so:

Code: Select all

VertexPass1:
    "VertexPass1" "{" GLSL "}" { Make your vertex_pass1 object here. };

GLSL:
    "GLSL" { Save the GLSL as a blob here. };
The lexer file would define a GLSL token as a regular expression that matches all valid characters in GLSL. This will work as long as GLSL doesn't use the } character. (I have no idea what GLSL looks like)

If GLSL uses curly brackets, you could try some character that is not in valid GLSL, or do something clunky like BEGIN_GLSL END_GLSL.
User avatar
wazabear
Posts: 96
Joined: 13 May 2020, 19:31
Gitlab profile: https://gitlab.com/glassmancody.info

Re: Postprocessing: For real

Post by wazabear »

I don't believe that would work gracefully, GLSL is a c-like language and makes heavy use of brackets. It also has c-style comments, so you also can't just search for an unused character, as that may be commented.

To "parse" a codeblock you need to match the next bracket at level 0 which is not part of a single or multiline comment. It's pretty easy to do with a simple iteration over the characters, I'm not sure that would work as a regex. Even if there were such a regex I'd imagine it would be an abomination :D

I should also note we need to support arbitrary GLSL versions, which all have different keywords and new layouts.


The only solution I see is to add special characters which absolutely mark end of a block, even if they are in a comment. Something like this, of course it would need to be made clear in the docs of this restriction.

Code: Select all

vertex mainPass --[[
    varying vec2 uv;
    uniform sampler2D lastPass;
    uniform sampler2D lastShader;
    uniform float osg_SimulationTime;

    void main()
    {
        // ...
    }
]]--
User avatar
AnyOldName3
Posts: 2668
Joined: 26 Nov 2015, 03:25

Re: Postprocessing: For real

Post by AnyOldName3 »

I don't remember everything about my module on parsers at uni, but I'm reasonably sure we can just have GLSL as a token with .* or its non-greedy equivalent as the regex defining it. I just checked and BISON & friends do context-free grammars, not context-sensitive ones like I thought, so this is maybe not actually possible, but I think it probably is. We're never going to see

Code: Select all

}

fragment pass2(vec2 blurDirection) {
or

Code: Select all

}
EOF
within the GLSL (if we do, it's fair enough that the parser gets confused as it's ambiguous or just a broken file) so the parser knows if it hits a brace followed by a vertex/fragment declaration or EOF, then the brace wasn't part of the .*? and was a brace token. I think the SLR parser I wrote at uni could handle that without even needing backtracking, and BISON is more powerful.

Ignoring all that, if the worst came to the worst, we could just grab someone else's GLSL grammar definition and plug it in to match it, and then not use the parsed GLSL.
User avatar
AnyOldName3
Posts: 2668
Joined: 26 Nov 2015, 03:25

Re: Postprocessing: For real

Post by AnyOldName3 »

Writing that post finally annoyed me into adding a new custom tag to the forum: [c]. It's for inline code, like you get with single backticks in markdown.
User avatar
FiftyTifty
Posts: 63
Joined: 15 Oct 2014, 21:02

Re: Postprocessing: For real

Post by FiftyTifty »

wazabear wrote: 08 Aug 2021, 16:22 Controlling shaders through a Lua interface, for example, is incredibly powerful. Per-weather effects or a skooma trip. Those are the obvious effects, but we've seen really awesome ones with MGE-XE like this https://www.nexusmods.com/morrowind/mods/47565. Point is, I'm keeping this primarily a postprocessing pipeline (with some exceptions), not a general purpose FX pipeline.
Not only is Lua access important, but we also need access to constantly changing variables. Things like the height of the sun/moon, the brightness of the stars, the time of day. This is done in ENB, where the software tracks the position of the sun as a proxy for the time of day. All the HLSL shader does, is just use a lerp with the variable that is made public to the HLSL code. Same with interior detection. For example:

float ToneMappingCurve=lerp(lerp(ToneMappingCurveNight, ToneMappingCurveDay, ENightDayFactor), ToneMappingCurveInterior, EInteriorFactor);

ENightDayFactor Is the global variable that goes between 0.0 and 1.0, tracking the time of day. EInteriorFactor is a boolean, which is for, as you guessed, interior/exterior detection.

Things like that would be great. Time of day, interior/exterior, weather, worldspace, underwater, player height, fog range, sky colour, horizon colour, etc., etc.

The more world data made available to HLSL code, that just needs a lerp() or two? The better.
User avatar
wazabear
Posts: 96
Joined: 13 May 2020, 19:31
Gitlab profile: https://gitlab.com/glassmancody.info

Re: Postprocessing: For real

Post by wazabear »

Indeed, this was one of the first things I thought about. These are called builtin uniforms, and they are passed as a UBO when supported (otherwise as standard uniforms). ToD, interior/exterior flag, sun direction, sun color, fog color, etc...
Post Reply