jdolan / quetoo

Quetoo ("Q2") is a free first person shooter based on id Tech2. GPL v2 license.
http://quetoo.org
204 stars 28 forks source link

Bring back underwater caustics effects #600

Closed jdolan closed 2 years ago

jdolan commented 3 years ago

BSP draw elements are broken up by contents, and draw elements that are underwater will have a contents that hits CONTENTS_MASK_LIQUID. I did this so that we can easily draw caustics on underwater faces without forfeiting draw elements batching.

We should add a function that draws a hard-coded caustics material stage on any r_bsp_draw_elements_t, and call this function after diffuse and materials passes on draw elements with `CONTENTS_MASK_LIQUID. I think the materials shader is the easiest place to do this.

  1. Add a STAGE_CAUSTICS flag in the engine code and materials.glsl.
  2. Load the caustics images in R_InitBspProgram, store references to them in r_bsp_program just like the warp image.
  3. Add a function that defines a hard-coded caustics stage, and call this function for draw elements with CONTENTS_MASK_LIQUID.

The stage can use a slower scroll effect for lava than water, etc.. if we want to get cute, but I'd like for this to essentially look and behave like the caustics that @kaadmy implemented years ago.

jdolan commented 3 years ago

This can / should also be done for mesh models. Just like we can use the lightmap to color caustics on BSP draw elements, we can use the lightgrid to modulate caustics on mesh models. The r_mesh_program struct will also need to hold a reference to any caustics images.

@SpineyPete I see that we have a ton of "caustics" sprites. I'm not sure if these are intended for underwater caustics. If they are, was the idea to have one for each liquid type (water, slime, lava)? Our old system had a single image for this, but still looked quite good.

Paril commented 3 years ago

Artist-controllable image?

jdolan-chwy commented 3 years ago

I'm not sure that's necessary or even desirable? Maybe allowing the artist to control the intensity of the effect with a simple scalar in the mat file?

caustics .6

SpineyPete commented 3 years ago

@jdolan The sprites are a 3d texture (stored as layers). They can animate if you scroll (add + modulo) the z-world-coordinate in the shader.

SpineyPete commented 3 years ago

Using 3d textures is a pretty expensive way of doing it though, there's an alternative trick described here: https://80.lv/articles/caustic-surface-production-guide/ Just uses one or two textures and looks pretty good. Could maybe even be part of the warp shader.

jdolan-chwy commented 3 years ago

That's more like what I was thinking. And warp is actually just a material stage, which is also how I was thinking about this....

jdolan commented 2 years ago

I'm tackling this next. If someone has an idea / opinion on the shader implementation, I can hand off with a uniform variable in place that activates a material stage. Otherwise I'll probably try to go back in time and dig up the old effect and just re-apply it in our current material stages.

jdolan commented 2 years ago

This is now implemented in https://github.com/jdolan/quetoo/pull/644

An additional static lighting pass is performed for both the lightmaps and lightgrid. It calculates proximity to translucent liquids, and authors a texture with RGB corresponding to lava, slime and water, respectively (kinda nice how that works out 😊). These textures are then used to additively blend caustic effects to diffuse lighting in both the BSP and mesh shaders. The BSP draw elements use the lightmap textures, while mesh models use the lightgrid. Inline BSP model entities receive a mix of lightmap and lightgrid caustic lighting, in case they move. This allows movers that interact with water to receive caustics while they are near or in water, and lose them if their proximity to water goes away.

Right now, we're not doing anything fancy or interesting with the different caustics channels. It's just one global effect. It would be cool if someone wanted to adjust the effect based on the presence of lava (r), slime (g) or water (b). The shadertoy that we borrowed our 3D noise function from actually shows how to do this:

https://www.shadertoy.com/view/4sc3z2