Mar 21st, 2018 (edited)
- OptiFine's rendering pipeline:
- Shadows: (shadow.fsh/vsh)
- Shadows run first, and are responsible for
- generating the shadow map, which is effectively
- an image of how far away everything is from the sun.
- Other objects that render later can then compare their
- own distance to that of the shadow map to figure out
- if there's something between it and the sun or not.
- Gbuffers: (files starting with gbuffers_)
- These files are used to render terrain, entities,
- the sky, and almost everything else in the game.
- The specific name of the file tells you
- a bit more about what it's used to render.
- Skybasic runs first, and handles the main sky color.
- This is followed by skytextured, which handles the sun and moon.
- Up next comes terrain, which handles all opaque blocks.
- Wind effects for tallgrass are typically implemented here.
- Entities and block (tile entities) are next.
- Entities include everything from creepers to cows,
- and tile entities covers things like chests and banners.
- Textured and textured_lit handle particles.
- Deferred comes next, but we'll explain that later.
- Lastly, weather handles rain and snow, and water handles all translucent blocks.
- There are a few other gbuffer programs, but these are the main ones.
- For a full list, see: https://github.com/sp614x/optifine/blob/master/OptiFineDoc/doc/shaders.txt#L43
- GUIs, the F3 menu, and other overlays are not handled by any of these programs.
- Composites: (composite(N) or final)
- Composites run after all geometry in the world has
- finished rendering, and final runs after the composites.
- These render over the entire screen, so you can use them
- to apply post-processing effects, or anything else
- that has to be done after all the gbuffers.
- Many shader packs also use this for lighting, ambient
- occlusion, fancy clouds (not the square vanilla kind),
- reflections, refractions, and many other effects.
- Deferred: (deferred(N).fsh/vsh)
- This is similar to the composite programs, but runs in
- the middle of terrain rendering instead of after it.
- More specifically, they run after all opaque objects
- have rendered, and before any transparent objects.
- There is no real goal here, so what you do here is
- up to you. Some specific effects require it, others
- don't. Like the composites, you can write to as many
- buffer(s) as you want, with whatever data you want.
- So, what can you do with all of these programs?
- Well, that depends on what *stage* of the program it is.
- OptiFine allows 4 stages of shader programs:
- The vertex stage: (files that end in .vsh)
- The vertex stage applies logic to a single vertex.
- They have access to many properties of their vertex,
- such as position, color, light level, and a few other things.
- The primary purpose of vertex shaders is to place the
- provided vertex at the correct location on your screen.
- They can also output various pieces of information to
- the fragment stage using "varyings". (explained below)
- The geometry stage: (files that end in .gsh)
- The geometry stage applies logic to 3 vertexes at a time.
- More specifically, they have inputs for 3
- vertexes which are part of the same triangle.
- You might think things would be square instead,
- since this is Minecraft, but even in Minecraft
- squares are always made of 2 triangles because
- that's what the GPU was designed to handle.
- Anyway, the geometry stage can choose to modify
- vertex positions or change the varying data which
- is fed into the fragment stage (explained next),
- but the REAL power of the geometry stage is that it
- can change the *number* of vertexes (or triangles)
- that get drawn. The number still has to be a multiple of 3,
- and the GPU often has limits on the maximum number of
- vertexes which can be generated, but the geometry
- stage is still very powerful nevertheless.
- The fragment stage: (files that end in .fsh)
- After all the vertexes of a specific triangle
- have been positioned, the GPU determines which
- pixels are inside it, and which are outside it.
- This process is called "rasterization". Once
- rasterization is finished, the GPU will call
- upon the fragment stage to choose a color for
- all the pixels that were inside the triangle.
- They can output more than one color by using
- more than one "framebuffer attachment". (explained below)
- The compute stage: (files that end in .csh)
- The compute stage has no pre-defined job.
- It can still have the usual uniform inputs, but
- it does not know about any geometry in the world.
- It does have one powerful feature though: it can
- write *directly* to a buffer at any location.
- Normally when a fragment stage writes to a buffer,
- it is restricted to only writing at the
- location of the pixel it was assigned to.
- Compute shaders do not have this restriction.
- At the time of writing this, compute stages
- are still very new, experimental, and buggy.
- They have not yet been back-ported to any
- Minecraft versions earlier than 1.16.5.
- Everything in the pipeline mentioned above
- contains a vertex stage and a fragment stage.
- Geometry and compute are both optional.
- Methods of transferring data between stages and programs:
- Varyings can transfer data from a vertex
- stage to its associated fragment stage.
- A varying is a single value that gets interpolated
- between all vertexes that it's part of.
- For example, say you have a triangle
- which outputs a varying for "color".
- The first vertex outputs red, the second
- outputs green, and the third one outputs blue.
- A fragment in the middle of that triangle
- would read a gray-ish color from that varying.
- A fragment half way between the red vertex and
- the green vertex (on the edge of the triangle)
- would read a dark yellow-ish color.
- Framebuffer attachments: (or just buffers, for short)
- Buffers can transfer data between fragment
- programs and any other program that runs after it*
- *Some restrictions apply that prevent certain buffers
- from being read/written to from specific programs.
- A buffer holds a value for every pixel on the screen.
- Typically, each value will be an RGBA color.
- They can also be formatted to use a specific precision
- (number of bits) for each component of the color.
- When a fragment shader writes to a buffer, the previous
- value is typically either overwritten, or blended together
- with the new value using the alpha component of the new value.
- An example of what you can do with this pipeline:
- Create 2 buffers. one is a material buffer,
- the other is the translucent buffer.
- Make all transparent objects output their
- color to the translucent buffer, and a
- number representing their ID (passed in
- with varyings) to the material buffer.
- Composite can read the material buffer,
- and mix the translucent buffer with the opaque
- color buffer differently depending on the ID.
- This will allow effects such as fog behind water,
- or only applying reflections to glass and
- water but not slime blocks or nether portals.
- As you may have guessed though, the material
- buffer can only store one ID per pixel.
- In most cases, the ID will be that of the
- closest transparent object to the camera.
- Everything behind it will be ignored.
- This means that if you look at water
- through stained glass, suddenly it
- won't have thick blue fog anymore.
- A lot of shader packs have similar issues.
- Sadly, there's no easy way to fix this.
- Still, this should give you an idea of what is
- and isn't possible to do with OptiFine's pipeline.
Please, Sign In to add comment