Skip to content

Conversation

@ada-tv
Copy link
Collaborator

@ada-tv ada-tv commented Sep 1, 2025

The biggest missing feature from the forward renderer, missing no more

Shaders to be modified:

  • model
  • sdf_text3D
  • simple - Opaque shape entities are unlit because the light buffers aren't set up during the instanced shape step
  • simple_procedural (maybe not necessary?)
  • polyvox

CPP stuff todo:

  • Local lights toggle for both renderers
  • Lighting on opaque shapes (the lighting buffers aren't set up for instanced drawing)

Fixes #1485
Fixes #1792

overte-snap-by-ada-tv-on-2025-09-02_10-16-17

@ada-tv ada-tv added enhancement New feature or request work in progress Do not merge yet labels Sep 1, 2025
@ada-tv ada-tv force-pushed the feature/forward-local-lights branch from c301c45 to ba9ba4f Compare September 5, 2025 04:11
@ada-tv ada-tv force-pushed the feature/forward-local-lights branch from ba9ba4f to 1e069f2 Compare October 11, 2025 11:42
Copy link
Member

@HifiExperiments HifiExperiments left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome work, this will be so cool!

to answer your questions:

  • simple_procedural doesn't currently have a true forward variant (and there's a FIXME for this in Procedural.cpp). maybe we can leave that for a separate PR since not many people use them anyways. you could try adding local light support to the existing transparent path if you wanted?
  • for the toggle:
    • replace the toggle in GraphicsSettings with the commented out one:
      SettingBoolean {
      settingText: "Local Lights";
      settingEnabledCondition: () => { return Render.renderMethod === 0 }
      }
      // NOTE: Once local lights have a proper toggle, the SettingBoolean above can be replaced with this one below.
      // SettingBoolean {
      // settingText: "Local Lights";
      // settingEnabledCondition: () => { return Render.localLightsEnabled }
      // onSettingEnabledChanged: {
      // Render.localLightsEnabled = settingEnabled;
      // }
      // }
    • add the local lights setting to RenderScriptingInterface, following the existing examples there
    • then I think you have two options:
      • you could have forceLocalLightsEnabled call recursivelyUpdateLightingModel like some of the other settings, and have it set enablePointLight/enableSpotLight. then in fetchClusterInfo you could have it return 0 for numLights if those are both disabled. this is a little bit of a hack, because the clusters will still be getting updated with values, but the shader will just short circuit...but it's definitely simpler
      • more complicated but maybe more "correct", you could have forceLocalLightsEnabled configure the actual LightClusteringPass, more similar to how recursivelyUpdateAntialiasingMode works. this would be like an "enabled" setting in LightClusteringPassConfig and then in LightClusteringPass::run you'd have to figure out how actually clear the clusters + short-circuit everything else to truly disable everything


// TODO: The clustered lighting doesn't work on instanced shapes on the forward renderer.
// For now, skip instancing in that case.
// How common are opaque shapes without a material on them?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird - it would be great to figure this out because instancing is a big performance boost. when we do instancing, objects render at a different point in the frame, so maybe they need to have the light cluster buffers re-set up?

lightBatchSetter in RenderPipelinesInit sets up the directional light, but maybe it needs to also set the light clusters

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember diagnosing this with Renderdoc, and the lighting buffers are indeed unset in that instanced shape step.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think setting them in lightBatchSetter would re-set them though? in renderInstances we call pipeline->prepare(...) which should call the batch setter, and forward pipelines have forceLightBatchSetter = true


// Set the light
deferredLightingEffect->setupKeyLightBatch(args, batch);
deferredLightingEffect->setupLocalLightsBatch(batch, lightClusters);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar to the comment in RenderableShapeEntityItem, wonder if we could just do this in lightBatchSetter and then not have to do either of these here.

is it necessary to set the DeferredFrameTransform too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think DeferredFrameTransform's name is a bit misleading, it seems to just be generic frame transform info, and it's set up for both the layered (front and hud) rendering and the 2D overlay HUD too.

DeferredFrameTransform was already being used on the forward renderer (TransformCamera being used in web_browser.slf's haze blending is one example), but it wasn't set up, so its buffer was unset or uninitialised (which in OpenGL always returns zeros in shaders, afaik). Haze depends on it for calculating things like vertical depth fog, though even with DeferredFrameTransform set up it still doesn't seem to use the camera height when calculating the vertical depth fog color, so I might be missing something critical to setting it up properly. See #1648

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed the naming is confusing, I think it used to only be used for deferred but now we should probably change it

looking at it closer, both deferred and forward paths have GenerateDeferredFrameTransform, but the deferred task passed it to DrawStateSortDeferred, and the forward pass does not pass it to DrawForward, so that could be the problem

@ada-tv ada-tv force-pushed the feature/forward-local-lights branch from 179f050 to cffcb59 Compare December 7, 2025 12:11
@ada-tv ada-tv added needs CR This pull request needs to be code reviewed needs QA This pull request needs to be tested and removed work in progress Do not merge yet labels Dec 9, 2025
@ada-tv ada-tv marked this pull request as ready for review December 9, 2025 21:27
@ada-tv ada-tv force-pushed the feature/forward-local-lights branch from 1b3bff0 to c04cf96 Compare December 19, 2025 06:56
bool fading = ShapeKey(args->_itemShapeKey).isFaded();
if (geometryShape != GeometryCache::Shape::Torus) {
if (outColor.a >= 1.0f) {
// FIXME: How can we set up the lighting buffers on the instanced draw calls?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still love to get this working before we merge this.

looking at it again, renderInstances in GeometryCache calls pipeline->prepare which calls _batchSetter. the pipeline it should be using is from GeometryCache::getShapePipelinePointer, which uses the _shapePipelines, which are set up in GeometryCache::initializeShapePipelines.

it looks like GeometryCache::getShapePipeline and getFadingShapePipeline only set the keylight. maybe you just need to call setupLocalLightsBatch there too?

Copy link
Collaborator Author

@ada-tv ada-tv Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found the bits you've mentioned, but DeferredLightingEffect::setupLocalLightsBatch needs lightClusters and lightingModel (so it doesn't run when local lights are turned off), and I'm not sure how I'd get those here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could store a copy of lightClusters on the light stage itself (have the light cluster setup job set it on the light stage), and look at how the second setupKeyLightBatch that doesn’t accept the light stage looks it up. you could have a second version of setupLocalLightsBatch that does something similar to get the light stage and then the clusters from that. you might not even need the lightingModel; you only use it to conditionally set the buffer, but shouldn’t we always set the buffer, lest it has incorrect data in it from something binding there previously?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had a shot at keeping a shared_ptr reference of LightClusters to reuse in the pipeline lambdas where it's not easily available in 180ab8f, but it hasn't gotten local lights working on instanced shapes yet. I think I'm doing setupLocalLightsBatch everywhere setupKeyLightBatch is.

batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, deferredFrameTransform->getFrameTransformBuffer());

// Set the light
deferredLightingEffect->setupKeyLightBatch(args, batch);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I asked this before but I forget the answer - I remember you saying we need to set the frame transform here for the haze + lighting calculation, but why do we need to set the lighting? I think it should be handled by the individual pipelines

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was mostly copy-pasted from RenderDeferredTask. setupLocalLightsBatch probably could go into get*Pipeline next to their setupKeyLightBatch calls. If we can get LightClusteringPass and LightingModel from there then it'd be possible.

@ada-tv ada-tv force-pushed the feature/forward-local-lights branch from c04cf96 to 773aed0 Compare December 25, 2025 06:17
@ada-tv ada-tv force-pushed the feature/forward-local-lights branch from 180ab8f to 19ac54a Compare January 3, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs CR This pull request needs to be code reviewed needs QA This pull request needs to be tested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Simple transparent shader isn't lit in deferred Local lights in Forward renderer

2 participants