mirror of
https://github.com/MinecraftForge/MinecraftForge
synced 2026-08-22 04:26:10 -04:00
Add DeltaTracker (partialTick) context to PassDefinitions (#10848)
This commit is contained in:
parent
ee1e695124
commit
66d4d888eb
4 changed files with 73 additions and 14 deletions
|
|
@ -22,7 +22,7 @@
|
|||
}
|
||||
|
||||
this.addLateDebugPass(frame, this.levelRenderState.cameraRenderState, terrainFog, modelViewMatrix);
|
||||
+ net.minecraftforge.client.FramePassManager.insertForgePasses(frame, targets, this.levelRenderState); // Forge: Modded passes are inserted here.
|
||||
+ net.minecraftforge.client.FramePassManager.insertForgePasses(frame, targets, this.levelRenderState, deltaTracker); // Forge: Modded passes are inserted here.
|
||||
profiler.popPush("executeFrameGraph");
|
||||
frame.execute(resourceAllocator, new FrameGraphBuilder.Inspector() {
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,10 +7,14 @@ package net.minecraftforge.client;
|
|||
|
||||
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
|
||||
import com.mojang.blaze3d.framegraph.FramePass;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.renderer.LevelTargetBundle;
|
||||
import net.minecraft.client.renderer.state.level.LevelRenderState;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -27,25 +31,75 @@ public class FramePassManager {
|
|||
|
||||
// Note: Pass order is determined automatically within FrameGraphBuilder. It's unclear what must be done to guarantee ordering.
|
||||
@ApiStatus.Internal
|
||||
public static void insertForgePasses(FrameGraphBuilder graphBuilder, LevelTargetBundle bundle, LevelRenderState state) {
|
||||
public static void insertForgePasses(FrameGraphBuilder graphBuilder, LevelTargetBundle bundle, LevelRenderState state, DeltaTracker deltaTracker) {
|
||||
for (PassInfo info : addedPasses) {
|
||||
FramePass pass = graphBuilder.addPass(info.name);
|
||||
PassDefinition forgePass = info.pass;
|
||||
forgePass.extracts(bundle, pass);
|
||||
forgePass.extracts(bundle, pass, deltaTracker);
|
||||
pass.executes(() -> forgePass.executes(state));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// ### A PassDefinition must satisfy 3 things.
|
||||
///
|
||||
/// 1. The rendering order for the purpose of translucency sorting. Read further for specific details.
|
||||
/// 2. A render state definition supplier; "what" will be rendered.
|
||||
/// 3. A render state definition consumer; "how" it will be rendered.
|
||||
///
|
||||
///
|
||||
/// To satisfy #1, all FramePasses (and thus PassDefinitions) must bind against at least one target.
|
||||
/// The list of targets can be found in {@linkplain LevelTargetBundle}.
|
||||
/// HOWEVER!!! Only {@linkplain LevelTargetBundle#main} is used if the graphics mode is not set to Fabulous!
|
||||
/// So at minimum, all passes must guarantee a fallback binding to the main target, like the below.
|
||||
/// ```
|
||||
/// @Override
|
||||
/// void extracts(LevelTargetBundle bundle, FramePass pass, DeltaTracker deltaTracker) {
|
||||
/// if (bundle.clouds != null) { // Perhaps we want to bind to clouds if Fabulous! is on.
|
||||
/// bundle.clouds = pass.readsAndWrites(bundle.clouds);
|
||||
/// }
|
||||
/// // An else clause could be used, but is not mandatory. It is fine to bind to more than one target.
|
||||
/// bundle.main = pass.readsAndWrites(bundle.main);
|
||||
/// }
|
||||
/// ```
|
||||
/// </pre>
|
||||
///
|
||||
/// It is up to the user to decide how their pass should bind to targets, but it must always bind to at least one.
|
||||
/// Failure to satisfy this requirement will result in {@linkplain FrameGraphBuilder#resolvePassOrder} exploding.
|
||||
/// Custom render targets are possible but not documented, see the implementation of {@linkplain LevelTargetBundle}
|
||||
/// if you want to take a crack at it.
|
||||
///
|
||||
/// Satisfying #2 is simple. Any state information you need to extract
|
||||
/// should be done during {@linkplain PassDefinition#extracts(LevelTargetBundle, FramePass, DeltaTracker)}.
|
||||
/// No actual rendering should be done at this time. This can happen before or after binding to a target.
|
||||
/// The specific implementation of your render state is up to you, it can even be done with some instance variables.
|
||||
///
|
||||
/// Satisfying #3 is also simple, this is the actual rendering that will consume the state created
|
||||
/// during the extracts phase.
|
||||
@NullMarked
|
||||
public interface PassDefinition {
|
||||
/**
|
||||
* Use to define which targets your pass will bind against, see {@link FramePass#reads} and {@link FramePass#readsAndWrites}
|
||||
* A FramePass must bind to at least ONE target. Otherwise, you get freaky issues with >1 modded passes.
|
||||
* Additionally, this method should be used for extracting render states into instance variables if desired.
|
||||
*/
|
||||
void extracts(LevelTargetBundle bundle, FramePass pass);
|
||||
|
||||
/**
|
||||
* Use to define what your pass does during the render stage.
|
||||
* @deprecated Prefer {@linkplain PassDefinition#extracts(LevelTargetBundle, FramePass, DeltaTracker)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since="26.2")
|
||||
default void extracts(LevelTargetBundle bundle, FramePass pass) {};
|
||||
|
||||
/**
|
||||
* This method exists to do render state extraction. Your instance of a PassDefinition should have
|
||||
* locals or some filled record instance that represents the render state created.
|
||||
* The resulting render state should be consumed by {@linkplain PassDefinition#executes(LevelRenderState)}
|
||||
* You must also use this to define which targets your pass will bind against. See PassDefinition javadocs for details.
|
||||
*/
|
||||
|
||||
default void extracts(LevelTargetBundle bundle, FramePass pass, DeltaTracker deltaTracker) {
|
||||
extracts(bundle, pass);
|
||||
};
|
||||
|
||||
/**
|
||||
* Use to define what your pass does during the render stage. This should consume the render state created
|
||||
* during the extracts phase.
|
||||
*/
|
||||
void executes(LevelRenderState state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import net.minecraftforge.eventbus.api.event.RecordEvent;
|
|||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Fired after all vanilla frame passes are added into the pass list.
|
||||
* Fired during the construction of {@linkplain net.minecraft.client.renderer.LevelRenderer}.
|
||||
*
|
||||
* <p>This event is fired on the {@linkplain net.minecraftforge.common.MinecraftForge#EVENT_BUS main Forge event bus},
|
||||
* only on the {@linkplain net.minecraftforge.fml.LogicalSide#CLIENT logical client}.
|
||||
|
|
@ -24,8 +24,9 @@ public record AddFramePassEvent() implements RecordEvent {
|
|||
/**
|
||||
* Adds a frame pass to pass list.
|
||||
* Create a new {@linkplain FramePassManager.PassDefinition} to handle render targets and render code.
|
||||
* See javadocs for details on what creating a PassDefinition entails.
|
||||
*
|
||||
* @param rl Resource location for frame pass name. Use RLs to avoid duplicate names.
|
||||
* @param rl Identifier for frame pass name. Use RLs to avoid duplicate names.
|
||||
* @param definition see usages of {@linkplain com.mojang.blaze3d.framegraph.FramePass} in {@linkplain net.minecraft.client.renderer.LevelRenderer}
|
||||
* @throws IllegalArgumentException If the name is a duplicate.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package net.minecraftforge.debug.client;
|
||||
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.renderer.LevelTargetBundle;
|
||||
import net.minecraft.client.renderer.state.level.LevelRenderState;
|
||||
import net.minecraftforge.client.FramePassManager;
|
||||
|
|
@ -23,6 +24,8 @@ import net.minecraft.world.phys.AABB;
|
|||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.framegraph.FramePass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@GameTestNamespace("forge")
|
||||
@Mod(RenderFrameLayerTest.MODID)
|
||||
|
|
@ -48,10 +51,11 @@ public class RenderFrameLayerTest extends BaseTestMod {
|
|||
/**
|
||||
* If this is working, two white line box cubes will be rendered at ground level in a superflat world around (0,0)
|
||||
*/
|
||||
@NullMarked
|
||||
public static void renderTest(AddFramePassEvent event) {
|
||||
FramePassManager.PassDefinition def = new FramePassManager.PassDefinition() {
|
||||
@Override
|
||||
public void extracts(LevelTargetBundle bundle, FramePass pass) {
|
||||
public void extracts(LevelTargetBundle bundle, FramePass pass, DeltaTracker dt) {
|
||||
bundle.main = pass.readsAndWrites(bundle.main);
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +76,7 @@ public class RenderFrameLayerTest extends BaseTestMod {
|
|||
event.addPass(rl(MODID), def);
|
||||
FramePassManager.PassDefinition def2 = new FramePassManager.PassDefinition() {
|
||||
@Override
|
||||
public void extracts(LevelTargetBundle bundle, FramePass pass) {
|
||||
public void extracts(@NotNull LevelTargetBundle bundle, FramePass pass, DeltaTracker dt) {
|
||||
bundle.main = pass.readsAndWrites(bundle.main);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue