portal guns third pass
This commit is contained in:
1 parent
be9b18c4f5
commit
39688c70ad
13 files changed
+344
-115
No files matched your search
+16
-5
@@ -1,6 +1,7 @@
|
|||||||
package com.craisinlord.antarchy.content.client;
|
package com.craisinlord.antarchy.content.client;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunApertureCuller;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -12,6 +13,7 @@ public final class PortalGunPortalRenderState {
|
|||||||
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_DESTINATION_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
|
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_DESTINATION_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
|
||||||
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_SOURCE_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
|
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_SOURCE_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
|
||||||
private static final ThreadLocal<Deque<PortalRenderContext>> ACTIVE_CONTEXTS = ThreadLocal.withInitial(ArrayDeque::new);
|
private static final ThreadLocal<Deque<PortalRenderContext>> ACTIVE_CONTEXTS = ThreadLocal.withInitial(ArrayDeque::new);
|
||||||
|
private static final ThreadLocal<Deque<PortalGunApertureCuller>> ACTIVE_CULLERS = ThreadLocal.withInitial(ArrayDeque::new);
|
||||||
private static final ThreadLocal<Integer> RENDER_ALL_DEPTH = ThreadLocal.withInitial(() -> 0);
|
private static final ThreadLocal<Integer> RENDER_ALL_DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||||
|
|
||||||
private PortalGunPortalRenderState() {
|
private PortalGunPortalRenderState() {
|
||||||
@@ -27,6 +29,7 @@ public final class PortalGunPortalRenderState {
|
|||||||
|
|
||||||
public static void pushPortalView(PortalRenderContext context) {
|
public static void pushPortalView(PortalRenderContext context) {
|
||||||
ACTIVE_CONTEXTS.get().push(context);
|
ACTIVE_CONTEXTS.get().push(context);
|
||||||
|
ACTIVE_CULLERS.get().push(PortalGunApertureCuller.create(context.destinationShape(), context.cameraPos()));
|
||||||
pushPortalView(context.sourceShape(), context.destinationShape(), context.renderAll());
|
pushPortalView(context.sourceShape(), context.destinationShape(), context.renderAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +63,13 @@ public final class PortalGunPortalRenderState {
|
|||||||
if (contexts.isEmpty()) {
|
if (contexts.isEmpty()) {
|
||||||
ACTIVE_CONTEXTS.remove();
|
ACTIVE_CONTEXTS.remove();
|
||||||
}
|
}
|
||||||
|
Deque<PortalGunApertureCuller> cullers = ACTIVE_CULLERS.get();
|
||||||
|
if (!cullers.isEmpty()) {
|
||||||
|
cullers.pop();
|
||||||
|
}
|
||||||
|
if (cullers.isEmpty()) {
|
||||||
|
ACTIVE_CULLERS.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void pushDestinationShape(PortalGunWorldPortalShape shape) {
|
public static void pushDestinationShape(PortalGunWorldPortalShape shape) {
|
||||||
@@ -109,7 +119,11 @@ public final class PortalGunPortalRenderState {
|
|||||||
PortalGunWorldPortalShape sourceShape = getSourceShape();
|
PortalGunWorldPortalShape sourceShape = getSourceShape();
|
||||||
return destinationShape == null || shouldRenderBounds(bounds, sourceShape, destinationShape, false);
|
return destinationShape == null || shouldRenderBounds(bounds, sourceShape, destinationShape, false);
|
||||||
}
|
}
|
||||||
return shouldRenderBounds(bounds, context.sourceShape(), context.destinationShape(), context.renderAll());
|
if (!context.destinationShape().intersectsFront(bounds, 0.125D)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Deque<PortalGunApertureCuller> cullers = ACTIVE_CULLERS.get();
|
||||||
|
return cullers.isEmpty() || cullers.peek().intersects(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldRenderBounds(AABB bounds, PortalGunWorldPortalShape sourceShape, PortalGunWorldPortalShape destinationShape, boolean renderAll) {
|
private static boolean shouldRenderBounds(AABB bounds, PortalGunWorldPortalShape sourceShape, PortalGunWorldPortalShape destinationShape, boolean renderAll) {
|
||||||
@@ -119,10 +133,7 @@ public final class PortalGunPortalRenderState {
|
|||||||
if (!destinationShape.intersectsFront(bounds, 0.125D)) {
|
if (!destinationShape.intersectsFront(bounds, 0.125D)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!destinationShape.intersectsPortalColumn(bounds, 1.5D, 1.5D, destinationShape.halfDepth() + 96.0D)) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return sourceShape == null || !sourceShape.intersectsFront(bounds, -0.02D);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record PortalRenderContext(
|
public record PortalRenderContext(
|
||||||
|
|||||||
+35
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.client.renderer;
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.mixins.client.SectionRenderDispatcherPortalUploadsAccessor;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -17,12 +18,15 @@ import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
|||||||
public final class PortalGunPortalRendererPool {
|
public final class PortalGunPortalRendererPool {
|
||||||
private static final int MAX_RENDERERS = 8;
|
private static final int MAX_RENDERERS = 8;
|
||||||
private static final long PORTAL_SECTION_BUDGET_NANOS = 4_166_666L;
|
private static final long PORTAL_SECTION_BUDGET_NANOS = 4_166_666L;
|
||||||
|
private static final long PORTAL_UPLOAD_BUDGET_NANOS = 1_000_000L;
|
||||||
|
private static final int MAX_PORTAL_UPLOADS_PER_FRAME = 16;
|
||||||
private static final RenderBuffers PORTAL_RENDER_BUFFERS = new RenderBuffers(2);
|
private static final RenderBuffers PORTAL_RENDER_BUFFERS = new RenderBuffers(2);
|
||||||
private static final LinkedHashMap<UUID, PortalRenderer> RENDERERS = new LinkedHashMap<>(8, 0.75F, true);
|
private static final LinkedHashMap<UUID, PortalRenderer> RENDERERS = new LinkedHashMap<>(8, 0.75F, true);
|
||||||
private static final Set<LevelRenderer> PROXY_RENDERERS = java.util.Collections.newSetFromMap(new IdentityHashMap<>());
|
private static final Set<LevelRenderer> PROXY_RENDERERS = java.util.Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
private static final ThreadLocal<Long> SECTION_BUDGET_DEADLINE = ThreadLocal.withInitial(() -> 0L);
|
private static final ThreadLocal<Long> SECTION_BUDGET_DEADLINE = ThreadLocal.withInitial(() -> 0L);
|
||||||
private static final ThreadLocal<Integer> SCHEDULED_SECTION_REBUILDS = ThreadLocal.withInitial(() -> 0);
|
private static final ThreadLocal<Integer> SCHEDULED_SECTION_REBUILDS = ThreadLocal.withInitial(() -> 0);
|
||||||
private static final ThreadLocal<Boolean> SKIP_SET_NOT_DIRTY = ThreadLocal.withInitial(() -> false);
|
private static final ThreadLocal<Boolean> SKIP_SET_NOT_DIRTY = ThreadLocal.withInitial(() -> false);
|
||||||
|
private static final ThreadLocal<Integer> UPLOADED_THIS_FRAME = ThreadLocal.withInitial(() -> 0);
|
||||||
private static ClientLevel ownerLevel;
|
private static ClientLevel ownerLevel;
|
||||||
|
|
||||||
private PortalGunPortalRendererPool() {
|
private PortalGunPortalRendererPool() {
|
||||||
@@ -66,12 +70,39 @@ public final class PortalGunPortalRendererPool {
|
|||||||
SECTION_BUDGET_DEADLINE.set(System.nanoTime() + PORTAL_SECTION_BUDGET_NANOS);
|
SECTION_BUDGET_DEADLINE.set(System.nanoTime() + PORTAL_SECTION_BUDGET_NANOS);
|
||||||
SCHEDULED_SECTION_REBUILDS.set(0);
|
SCHEDULED_SECTION_REBUILDS.set(0);
|
||||||
SKIP_SET_NOT_DIRTY.set(false);
|
SKIP_SET_NOT_DIRTY.set(false);
|
||||||
|
UPLOADED_THIS_FRAME.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void uploadPending(LevelRenderer renderer, SectionRenderDispatcher dispatcher) {
|
||||||
|
if (!isProxy(renderer)) {
|
||||||
|
dispatcher.uploadAllPendingUploads();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
java.util.Queue<Runnable> uploads = ((SectionRenderDispatcherPortalUploadsAccessor) dispatcher).antarchy$getToUpload();
|
||||||
|
long deadline = System.nanoTime() + PORTAL_UPLOAD_BUDGET_NANOS;
|
||||||
|
int uploaded = UPLOADED_THIS_FRAME.get();
|
||||||
|
while (uploaded < MAX_PORTAL_UPLOADS_PER_FRAME) {
|
||||||
|
if (uploaded > 0 && System.nanoTime() >= deadline) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Runnable upload = uploads.poll();
|
||||||
|
if (upload == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
upload.run();
|
||||||
|
uploaded++;
|
||||||
|
}
|
||||||
|
UPLOADED_THIS_FRAME.set(uploaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int scheduledSectionRebuilds() {
|
public static int scheduledSectionRebuilds() {
|
||||||
return SCHEDULED_SECTION_REBUILDS.get();
|
return SCHEDULED_SECTION_REBUILDS.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int uploadedThisFrame() {
|
||||||
|
return UPLOADED_THIS_FRAME.get();
|
||||||
|
}
|
||||||
|
|
||||||
public static long remainingSectionBudgetNanos() {
|
public static long remainingSectionBudgetNanos() {
|
||||||
return Math.max(0L, SECTION_BUDGET_DEADLINE.get() - System.nanoTime());
|
return Math.max(0L, SECTION_BUDGET_DEADLINE.get() - System.nanoTime());
|
||||||
}
|
}
|
||||||
@@ -126,6 +157,10 @@ public final class PortalGunPortalRendererPool {
|
|||||||
}
|
}
|
||||||
RENDERERS.clear();
|
RENDERERS.clear();
|
||||||
ownerLevel = null;
|
ownerLevel = null;
|
||||||
|
SECTION_BUDGET_DEADLINE.remove();
|
||||||
|
SCHEDULED_SECTION_REBUILDS.remove();
|
||||||
|
SKIP_SET_NOT_DIRTY.remove();
|
||||||
|
UPLOADED_THIS_FRAME.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void trim() {
|
private static void trim() {
|
||||||
|
|||||||
+98
-95
@@ -8,6 +8,7 @@ import com.craisinlord.antarchy.mixins.client.MinecraftMainRenderTargetAccessor;
|
|||||||
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalTargetsAccessor;
|
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalTargetsAccessor;
|
||||||
import com.craisinlord.antarchy.mixins.client.PostChainTargetAccessor;
|
import com.craisinlord.antarchy.mixins.client.PostChainTargetAccessor;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunProjectionUtil;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
||||||
import com.craisinlord.antarchy.mixins.client.CameraBasisAccessor;
|
import com.craisinlord.antarchy.mixins.client.CameraBasisAccessor;
|
||||||
@@ -129,13 +130,6 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
if (portals.isEmpty()) {
|
if (portals.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (portalViewShader == null) {
|
|
||||||
if (!loggedMissingPortalViewShader) {
|
|
||||||
loggedMissingPortalViewShader = true;
|
|
||||||
Antarchy.LOGGER.error("Portal gun destination view shader is unavailable; skipping destination render");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vec3 effectiveCameraPos = cameraPos;
|
Vec3 effectiveCameraPos = cameraPos;
|
||||||
Matrix4f rootProjectionMatrix = new Matrix4f(projectionMatrix);
|
Matrix4f rootProjectionMatrix = new Matrix4f(projectionMatrix);
|
||||||
float partialTick = tickCounter.getGameTimeDeltaPartialTick(true);
|
float partialTick = tickCounter.getGameTimeDeltaPartialTick(true);
|
||||||
@@ -201,6 +195,13 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
}
|
}
|
||||||
RenderContext rootContext = new RenderContext(effectiveCameraPos, rootLook, rootUp, rootViewMatrix);
|
RenderContext rootContext = new RenderContext(effectiveCameraPos, rootLook, rootUp, rootViewMatrix);
|
||||||
boolean directStencil = PortalStencilTarget.supportsDirect(minecraft.getMainRenderTarget());
|
boolean directStencil = PortalStencilTarget.supportsDirect(minecraft.getMainRenderTarget());
|
||||||
|
if (!directStencil && portalViewShader == null) {
|
||||||
|
if (!loggedMissingPortalViewShader) {
|
||||||
|
loggedMissingPortalViewShader = true;
|
||||||
|
Antarchy.LOGGER.error("Portal gun destination view shader is unavailable; skipping offscreen portal rendering");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
PortalViewBudget fallbackBudget = directStencil ? null : new PortalViewBudget(MAX_PORTAL_VIEWS_PER_FRAME);
|
PortalViewBudget fallbackBudget = directStencil ? null : new PortalViewBudget(MAX_PORTAL_VIEWS_PER_FRAME);
|
||||||
renderingPortalView = true;
|
renderingPortalView = true;
|
||||||
boolean projectionBackedUp = false;
|
boolean projectionBackedUp = false;
|
||||||
@@ -212,18 +213,23 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
if (linkedPortal == null || !linkedPortal.isAlive()) {
|
if (linkedPortal == null || !linkedPortal.isAlive()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
String portalPairKey = portal.getUUID() + "->" + linkedPortal.getUUID();
|
||||||
boolean rendered;
|
boolean rendered;
|
||||||
try {
|
try {
|
||||||
if (directStencil) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey,
|
||||||
rendered = renderPortalSurfaceDirect(minecraft, cameraEntity, tickCounter, rootContext, rootProjectionMatrix, portal, linkedPortal, rootScreenClips.get(portal));
|
"root-view-dispatch", "backend=" + (directStencil ? "direct-stencil" : "offscreen")
|
||||||
} else {
|
+ " aperture=" + rootScreenClips.get(portal).width() + "x" + rootScreenClips.get(portal).height())) {
|
||||||
int textureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, fallbackBudget, rootContext,
|
if (directStencil) {
|
||||||
rootProjectionMatrix, portal, linkedPortal, 0, rootScreenClips.get(portal));
|
rendered = renderPortalSurfaceDirect(minecraft, cameraEntity, tickCounter, rootContext, rootProjectionMatrix, portal, linkedPortal, rootScreenClips.get(portal));
|
||||||
minecraft.gameRenderer.resetProjectionMatrix(rootProjectionMatrix);
|
} else {
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
int textureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, fallbackBudget, rootContext,
|
||||||
rendered = textureId >= 0 && drawPortalQuad(cameraPos, rootViewMatrix, rootProjectionMatrix,
|
rootProjectionMatrix, portal, linkedPortal, 0, rootScreenClips.get(portal));
|
||||||
minecraft.getMainRenderTarget().width, minecraft.getMainRenderTarget().height,
|
minecraft.gameRenderer.resetProjectionMatrix(rootProjectionMatrix);
|
||||||
portal, partialTick, textureId, rootScreenClips.get(portal));
|
minecraft.getMainRenderTarget().bindWrite(true);
|
||||||
|
rendered = textureId >= 0 && drawPortalQuad(cameraPos, rootViewMatrix, rootProjectionMatrix,
|
||||||
|
minecraft.getMainRenderTarget().width, minecraft.getMainRenderTarget().height,
|
||||||
|
portal, partialTick, textureId, rootScreenClips.get(portal));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (RuntimeException exception) {
|
} catch (RuntimeException exception) {
|
||||||
logRenderFailure(minecraft, exception);
|
logRenderFailure(minecraft, exception);
|
||||||
@@ -241,7 +247,6 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
RenderSystem.backupProjectionMatrix();
|
RenderSystem.backupProjectionMatrix();
|
||||||
projectionBackedUp = true;
|
projectionBackedUp = true;
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
minecraft.getMainRenderTarget().bindWrite(true);
|
||||||
String portalPairKey = portal.getUUID() + "->" + linkedPortal.getUUID();
|
|
||||||
if (loggedPortalViewComposites.add(portalPairKey)) {
|
if (loggedPortalViewComposites.add(portalPairKey)) {
|
||||||
Antarchy.LOGGER.info("Portal gun destination view rendered directly source={} destination={} target={}x{}", portal.getId(), linkedPortal.getId(), targetWidth, targetHeight);
|
Antarchy.LOGGER.info("Portal gun destination view rendered directly source={} destination={} target={}x{}", portal.getId(), linkedPortal.getId(), targetWidth, targetHeight);
|
||||||
}
|
}
|
||||||
@@ -358,7 +363,7 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
ScreenClip clip
|
ScreenClip clip
|
||||||
) {
|
) {
|
||||||
RenderTarget target = minecraft.getMainRenderTarget();
|
RenderTarget target = minecraft.getMainRenderTarget();
|
||||||
if (clip == null || portalViewShader == null) {
|
if (clip == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int width = target.width;
|
int width = target.width;
|
||||||
@@ -370,17 +375,18 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
PortalCamera portalCamera = new PortalCamera();
|
PortalCamera portalCamera = new PortalCamera();
|
||||||
portalCamera.setup(minecraft.level, cameraEntity, partialTick, transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
portalCamera.setup(minecraft.level, cameraEntity, partialTick, transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
||||||
String portalPairKey = sourcePortal.getUUID() + "->" + destinationPortal.getUUID();
|
String portalPairKey = sourcePortal.getUUID() + "->" + destinationPortal.getUUID();
|
||||||
LevelRenderer proxyRenderer = PortalGunPortalRendererPool.acquire(minecraft, destinationPortal.getUUID(), width, height);
|
boolean renderDestination = PortalGunPortalVisibilityQueries.shouldRender(sourcePortal.getUUID(), destinationPortal.getUUID());
|
||||||
LevelRendererPortalTargetsAccessor levelRendererTargets = (LevelRendererPortalTargetsAccessor) proxyRenderer;
|
LevelRenderer proxyRenderer = renderDestination
|
||||||
PostChain entityEffect = levelRendererTargets.antarchy$getEntityEffect();
|
? PortalGunPortalRendererPool.acquire(minecraft, destinationPortal.getUUID(), width, height) : null;
|
||||||
PostChain transparencyChain = levelRendererTargets.antarchy$getTransparencyChain();
|
LevelRendererPortalTargetsAccessor levelRendererTargets = proxyRenderer == null ? null : (LevelRendererPortalTargetsAccessor) proxyRenderer;
|
||||||
|
PostChain entityEffect = levelRendererTargets == null ? null : levelRendererTargets.antarchy$getEntityEffect();
|
||||||
|
PostChain transparencyChain = levelRendererTargets == null ? null : levelRendererTargets.antarchy$getTransparencyChain();
|
||||||
PostChainTargetAccessor entityEffectTarget = entityEffect == null ? null : (PostChainTargetAccessor) entityEffect;
|
PostChainTargetAccessor entityEffectTarget = entityEffect == null ? null : (PostChainTargetAccessor) entityEffect;
|
||||||
PostChainTargetAccessor transparencyTarget = transparencyChain == null ? null : (PostChainTargetAccessor) transparencyChain;
|
PostChainTargetAccessor transparencyTarget = transparencyChain == null ? null : (PostChainTargetAccessor) transparencyChain;
|
||||||
RenderTarget previousEntityEffectTarget = entityEffectTarget == null ? null : entityEffectTarget.antarchy$getScreenTarget();
|
RenderTarget previousEntityEffectTarget = entityEffectTarget == null ? null : entityEffectTarget.antarchy$getScreenTarget();
|
||||||
RenderTarget previousTransparencyTarget = transparencyTarget == null ? null : transparencyTarget.antarchy$getScreenTarget();
|
RenderTarget previousTransparencyTarget = transparencyTarget == null ? null : transparencyTarget.antarchy$getScreenTarget();
|
||||||
PortalStencilTarget.Scope stencilScope = null;
|
PortalStencilTarget.Scope stencilScope = null;
|
||||||
boolean contextPushed = false;
|
boolean contextPushed = false;
|
||||||
boolean renderDestination = PortalGunPortalVisibilityQueries.shouldRender(sourcePortal.getUUID(), destinationPortal.getUUID());
|
|
||||||
PortalSceneRenderTrace.event(portalPairKey, "destination-render-decision", "render=" + renderDestination + " clip=" + clip.width() + "x" + clip.height());
|
PortalSceneRenderTrace.event(portalPairKey, "destination-render-decision", "render=" + renderDestination + " clip=" + clip.width() + "x" + clip.height());
|
||||||
try {
|
try {
|
||||||
if (entityEffectTarget != null) {
|
if (entityEffectTarget != null) {
|
||||||
@@ -390,12 +396,12 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
transparencyTarget.antarchy$setScreenTarget(target);
|
transparencyTarget.antarchy$setScreenTarget(target);
|
||||||
}
|
}
|
||||||
minecraft.gameRenderer.resetProjectionMatrix(clippedProjection);
|
minecraft.gameRenderer.resetProjectionMatrix(clippedProjection);
|
||||||
int maskTexture = minecraft.getTextureManager().getTexture(BLUE_OVERLAY).getId();
|
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-stencil-mask", "clip=" + clip.width() + "x" + clip.height())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-stencil-mask", "clip=" + clip.width() + "x" + clip.height())) {
|
||||||
stencilScope = PortalStencilTarget.beginDirect(target, () -> {
|
stencilScope = PortalStencilTarget.beginDirect(target, () -> {
|
||||||
boolean queryStarted = PortalGunPortalVisibilityQueries.begin(sourcePortal.getUUID(), destinationPortal.getUUID());
|
boolean queryStarted = PortalGunPortalVisibilityQueries.begin(sourcePortal.getUUID(), destinationPortal.getUUID());
|
||||||
try {
|
try {
|
||||||
drawPortalQuad(currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, width, height, sourcePortal, partialTick, maskTexture, clip);
|
drawPortalMask(minecraft, currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix,
|
||||||
|
sourcePortal, partialTick);
|
||||||
} finally {
|
} finally {
|
||||||
PortalGunPortalVisibilityQueries.end(sourcePortal.getUUID(), destinationPortal.getUUID(), queryStarted);
|
PortalGunPortalVisibilityQueries.end(sourcePortal.getUUID(), destinationPortal.getUUID(), queryStarted);
|
||||||
}
|
}
|
||||||
@@ -430,22 +436,37 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (stencilScope != null) {
|
try {
|
||||||
stencilScope.close();
|
if (stencilScope != null) {
|
||||||
}
|
stencilScope.close();
|
||||||
if (contextPushed) {
|
}
|
||||||
PortalGunPortalRenderState.popPortalView(false);
|
} finally {
|
||||||
|
if (contextPushed) {
|
||||||
|
PortalGunPortalRenderState.popPortalView(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (transparencyTarget != null) {
|
try {
|
||||||
transparencyTarget.antarchy$setScreenTarget(previousTransparencyTarget);
|
if (transparencyTarget != null) {
|
||||||
|
transparencyTarget.antarchy$setScreenTarget(previousTransparencyTarget);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (entityEffectTarget != null) {
|
||||||
|
entityEffectTarget.antarchy$setScreenTarget(previousEntityEffectTarget);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
restorePortalDrawState();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
target.bindWrite(true);
|
||||||
|
} finally {
|
||||||
|
minecraft.gameRenderer.resetProjectionMatrix(baseProjectionMatrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (entityEffectTarget != null) {
|
|
||||||
entityEffectTarget.antarchy$setScreenTarget(previousEntityEffectTarget);
|
|
||||||
}
|
|
||||||
restorePortalDrawState();
|
|
||||||
target.bindWrite(true);
|
|
||||||
minecraft.gameRenderer.resetProjectionMatrix(baseProjectionMatrix);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,7 +503,9 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
}
|
}
|
||||||
Matrix4f clippedProjectionMatrix = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
Matrix4f clippedProjectionMatrix = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
||||||
Matrix4f apertureCullProjection = cropProjectionToScreenClip(clippedProjectionMatrix, clip, target.width, target.height);
|
Matrix4f apertureCullProjection = cropProjectionToScreenClip(clippedProjectionMatrix, clip, target.width, target.height);
|
||||||
boolean renderAll = true;
|
// The offscreen target is still composited only through this portal's aperture,
|
||||||
|
// so use the same conservative destination bounds filter as the direct path.
|
||||||
|
boolean renderAll = false;
|
||||||
PortalCamera portalCamera = new PortalCamera();
|
PortalCamera portalCamera = new PortalCamera();
|
||||||
portalCamera.setup(minecraft.level, cameraEntity, tickCounter.getGameTimeDeltaPartialTick(true), transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
portalCamera.setup(minecraft.level, cameraEntity, tickCounter.getGameTimeDeltaPartialTick(true), transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
||||||
RenderTarget previousMainTarget = minecraft.getMainRenderTarget();
|
RenderTarget previousMainTarget = minecraft.getMainRenderTarget();
|
||||||
@@ -603,11 +626,14 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
} finally {
|
} finally {
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "restore-render-state", "depth=" + depth)) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "restore-render-state", "depth=" + depth)) {
|
||||||
try {
|
try {
|
||||||
if (stencilScope != null) {
|
try {
|
||||||
stencilScope.close();
|
if (stencilScope != null) {
|
||||||
}
|
stencilScope.close();
|
||||||
if (portalRenderStatePushed) {
|
}
|
||||||
PortalGunPortalRenderState.popPortalView(renderAll);
|
} finally {
|
||||||
|
if (portalRenderStatePushed) {
|
||||||
|
PortalGunPortalRenderState.popPortalView(renderAll);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
@@ -635,11 +661,13 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static RenderContext transformContext(RenderContext currentContext, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) {
|
private static RenderContext transformContext(RenderContext currentContext, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) {
|
||||||
Vec3 relativeEye = currentContext.cameraPos().subtract(sourcePortal.position());
|
var sourceShape = sourcePortal.getWorldPortalShape();
|
||||||
Vec3 transformedEyeOffset = PortalGunTransformUtil.transformRelativePosition(sourcePortal, destinationPortal, relativeEye);
|
var destinationShape = destinationPortal.getWorldPortalShape();
|
||||||
Vec3 destinationEye = destinationPortal.position().add(transformedEyeOffset);
|
Vec3 relativeEye = currentContext.cameraPos().subtract(sourceShape.center());
|
||||||
Vec3 transformedLook = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, currentContext.look()).normalize();
|
Vec3 transformedEyeOffset = PortalGunTransformUtil.transformPosition(sourceShape, destinationShape, relativeEye);
|
||||||
Vec3 transformedUp = PortalGunTransformUtil.transformVector(sourcePortal, destinationPortal, currentContext.up()).normalize();
|
Vec3 destinationEye = destinationShape.center().add(transformedEyeOffset);
|
||||||
|
Vec3 transformedLook = PortalGunTransformUtil.transformVector(sourceShape, destinationShape, currentContext.look()).normalize();
|
||||||
|
Vec3 transformedUp = PortalGunTransformUtil.transformVector(sourceShape, destinationShape, currentContext.up()).normalize();
|
||||||
Matrix4f viewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(transformedLook, transformedUp).conjugate(new Quaternionf()));
|
Matrix4f viewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(transformedLook, transformedUp).conjugate(new Quaternionf()));
|
||||||
return new RenderContext(destinationEye, transformedLook, transformedUp, viewMatrix);
|
return new RenderContext(destinationEye, transformedLook, transformedUp, viewMatrix);
|
||||||
}
|
}
|
||||||
@@ -647,51 +675,8 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
private static Matrix4f applyPortalClipPlane(Matrix4f projectionMatrix, RenderContext renderContext, PortalGunPortalEntity destinationPortal) {
|
private static Matrix4f applyPortalClipPlane(Matrix4f projectionMatrix, RenderContext renderContext, PortalGunPortalEntity destinationPortal) {
|
||||||
Vec3 planePointWorld = destinationPortal.position().add(destinationPortal.getNormalVec().normalize().scale(0.01D));
|
Vec3 planePointWorld = destinationPortal.position().add(destinationPortal.getNormalVec().normalize().scale(0.01D));
|
||||||
Vec3 planeNormalWorld = destinationPortal.getNormalVec().normalize();
|
Vec3 planeNormalWorld = destinationPortal.getNormalVec().normalize();
|
||||||
Vector4f clipPlane = portalPlaneToCameraSpace(renderContext, planePointWorld, planeNormalWorld);
|
return PortalGunProjectionUtil.clipAtExit(projectionMatrix, renderContext.cameraPos(), renderContext.look(),
|
||||||
if (clipPlane.lengthSquared() <= 1.0E-6F) {
|
renderContext.up(), planePointWorld, planeNormalWorld);
|
||||||
return projectionMatrix;
|
|
||||||
}
|
|
||||||
Matrix4f clippedProjection = new Matrix4f(projectionMatrix);
|
|
||||||
Vector4f q = new Vector4f(signNonZero(clipPlane.x()), signNonZero(clipPlane.y()), 1.0F, 1.0F)
|
|
||||||
.mul(new Matrix4f(projectionMatrix).invert());
|
|
||||||
float planeCornerDot = clipPlane.dot(q);
|
|
||||||
if (!Float.isFinite(planeCornerDot) || Math.abs(planeCornerDot) <= 1.0E-6F) {
|
|
||||||
return projectionMatrix;
|
|
||||||
}
|
|
||||||
float scale = 2.0F / planeCornerDot;
|
|
||||||
Vector4f c = clipPlane.mul(scale, new Vector4f());
|
|
||||||
clippedProjection.m02(c.x());
|
|
||||||
clippedProjection.m12(c.y());
|
|
||||||
clippedProjection.m22(c.z() + 1.0F);
|
|
||||||
clippedProjection.m32(c.w());
|
|
||||||
return clippedProjection;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Vector4f portalPlaneToCameraSpace(RenderContext renderContext, Vec3 planePointWorld, Vec3 planeNormalWorld) {
|
|
||||||
Vec3 look = renderContext.look().normalize();
|
|
||||||
Vec3 up = renderContext.up().normalize();
|
|
||||||
Vec3 right = look.cross(up).normalize();
|
|
||||||
Vec3 relativePoint = planePointWorld.subtract(renderContext.cameraPos());
|
|
||||||
Vector4f point = new Vector4f(
|
|
||||||
(float) relativePoint.dot(right),
|
|
||||||
(float) relativePoint.dot(up),
|
|
||||||
(float) -relativePoint.dot(look),
|
|
||||||
1.0F
|
|
||||||
);
|
|
||||||
Vector4f normal = new Vector4f(
|
|
||||||
(float) planeNormalWorld.dot(right),
|
|
||||||
(float) planeNormalWorld.dot(up),
|
|
||||||
(float) -planeNormalWorld.dot(look),
|
|
||||||
0.0F
|
|
||||||
);
|
|
||||||
if (normal.z() > 0.0F) {
|
|
||||||
normal.mul(-1.0F);
|
|
||||||
}
|
|
||||||
return new Vector4f(normal.x(), normal.y(), normal.z(), -(normal.x() * point.x() + normal.y() * point.y() + normal.z() * point.z()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float signNonZero(float value) {
|
|
||||||
return value >= 0.0F ? 1.0F : -1.0F;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ScreenClip computeScreenClip(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, PortalGunPortalEntity portal, float partialTick, int width, int height) {
|
private static ScreenClip computeScreenClip(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, PortalGunPortalEntity portal, float partialTick, int width, int height) {
|
||||||
@@ -836,6 +821,24 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void drawPortalMask(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix,
|
||||||
|
PortalGunPortalEntity portal, float partialTick) {
|
||||||
|
PortalGunWorldPortalShape shape = portal.getWorldPortalShape()
|
||||||
|
.scaleAperture(portal.getPortalVisualScale(partialTick) * PORTAL_APERTURE_SCALE);
|
||||||
|
Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix);
|
||||||
|
List<Vector4f> polygon = projectPortalPolygon(combined, cameraPos, shape);
|
||||||
|
if (polygon.size() < 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION);
|
||||||
|
for (int index = 1; index + 1 < polygon.size(); index++) {
|
||||||
|
addDepthVertex(buffer, polygon.get(0));
|
||||||
|
addDepthVertex(buffer, polygon.get(index));
|
||||||
|
addDepthVertex(buffer, polygon.get(index + 1));
|
||||||
|
}
|
||||||
|
drawClipSpaceMesh(minecraft, buffer.build());
|
||||||
|
}
|
||||||
|
|
||||||
private static void clearDepthInPortalStencil(Minecraft minecraft) {
|
private static void clearDepthInPortalStencil(Minecraft minecraft) {
|
||||||
int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC);
|
int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC);
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
|
|||||||
+23
-2
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.client.renderer;
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState;
|
||||||
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalSceneInvoker;
|
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalSceneInvoker;
|
||||||
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor;
|
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
@@ -39,6 +40,7 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
outerModelViewStack.pushMatrix();
|
outerModelViewStack.pushMatrix();
|
||||||
outerModelViewStack.identity();
|
outerModelViewStack.identity();
|
||||||
RenderSystem.applyModelViewMatrix();
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
ObjectArrayList<SectionRenderDispatcher.RenderSection> originalVisibleSections = null;
|
||||||
try {
|
try {
|
||||||
Vec3 cameraPosition = camera.getPosition();
|
Vec3 cameraPosition = camera.getPosition();
|
||||||
double cameraX = cameraPosition.x;
|
double cameraX = cameraPosition.x;
|
||||||
@@ -71,8 +73,20 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
}
|
}
|
||||||
LevelRendererPortalViewAreaAccessor viewAreaAccessor = sodium ? null : (LevelRendererPortalViewAreaAccessor) renderer;
|
LevelRendererPortalViewAreaAccessor viewAreaAccessor = sodium ? null : (LevelRendererPortalViewAreaAccessor) renderer;
|
||||||
int visibleSectionCount = 0;
|
int visibleSectionCount = 0;
|
||||||
|
int candidateSectionCount = 0;
|
||||||
if (viewAreaAccessor != null) {
|
if (viewAreaAccessor != null) {
|
||||||
ObjectArrayList<SectionRenderDispatcher.RenderSection> fullVisibleSections = viewAreaAccessor.antarchy$getVisibleSections();
|
originalVisibleSections = viewAreaAccessor.antarchy$getVisibleSections();
|
||||||
|
candidateSectionCount = originalVisibleSections.size();
|
||||||
|
ObjectArrayList<SectionRenderDispatcher.RenderSection> apertureSections = new ObjectArrayList<>();
|
||||||
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "aperture-section-cull", "candidateSections=" + candidateSectionCount)) {
|
||||||
|
for (SectionRenderDispatcher.RenderSection section : originalVisibleSections) {
|
||||||
|
if (PortalGunPortalRenderState.shouldRenderBounds(section.getBoundingBox())) {
|
||||||
|
apertureSections.add(section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewAreaAccessor.antarchy$setVisibleSections(apertureSections);
|
||||||
|
ObjectArrayList<SectionRenderDispatcher.RenderSection> fullVisibleSections = apertureSections;
|
||||||
ObjectArrayList<SectionRenderDispatcher.RenderSection> budgetedVisibleSections = new ObjectArrayList<>();
|
ObjectArrayList<SectionRenderDispatcher.RenderSection> budgetedVisibleSections = new ObjectArrayList<>();
|
||||||
int scannedVisibleSections = 0;
|
int scannedVisibleSections = 0;
|
||||||
while (scannedVisibleSections < fullVisibleSections.size() && PortalGunPortalRendererPool.remainingSectionBudgetNanos() > 0L) {
|
while (scannedVisibleSections < fullVisibleSections.size() && PortalGunPortalRendererPool.remainingSectionBudgetNanos() > 0L) {
|
||||||
@@ -88,7 +102,11 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
}
|
}
|
||||||
visibleSectionCount = fullVisibleSections.size();
|
visibleSectionCount = fullVisibleSections.size();
|
||||||
}
|
}
|
||||||
PortalSceneRenderTrace.event(tracePair, "visible-sections-ready", "renderer=" + (sodium ? "sodium" : "vanilla") + " count=" + visibleSectionCount + " scheduledRebuilds=" + PortalGunPortalRendererPool.scheduledSectionRebuilds());
|
PortalSceneRenderTrace.event(tracePair, "visible-sections-ready", "renderer=" + (sodium ? "sodium" : "vanilla")
|
||||||
|
+ " count=" + visibleSectionCount + " candidates=" + candidateSectionCount
|
||||||
|
+ " scheduledRebuilds=" + PortalGunPortalRendererPool.scheduledSectionRebuilds()
|
||||||
|
+ " uploaded=" + PortalGunPortalRendererPool.uploadedThisFrame()
|
||||||
|
+ " pendingUploads=" + (sodium ? "sodium-managed" : viewAreaAccessor.antarchy$getSectionRenderDispatcher().getToUpload()));
|
||||||
|
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "opaque-terrain-layers", "sections=" + visibleSectionCount)) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "opaque-terrain-layers", "sections=" + visibleSectionCount)) {
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
@@ -195,6 +213,9 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
if (originalVisibleSections != null) {
|
||||||
|
((LevelRendererPortalViewAreaAccessor) renderer).antarchy$setVisibleSections(originalVisibleSections);
|
||||||
|
}
|
||||||
outerModelViewStack.popMatrix();
|
outerModelViewStack.popMatrix();
|
||||||
RenderSystem.applyModelViewMatrix();
|
RenderSystem.applyModelViewMatrix();
|
||||||
RenderSystem.setShaderFogStart(previousFogStart);
|
RenderSystem.setShaderFogStart(previousFogStart);
|
||||||
|
|||||||
+14
-13
@@ -6,8 +6,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
public final class PortalSceneRenderTrace {
|
public final class PortalSceneRenderTrace {
|
||||||
private static final String DEBUG_PROPERTY = "antarchy.portalGun.debugRender";
|
private static final String DEBUG_PROPERTY = "antarchy.portalGun.debugRender";
|
||||||
|
private static final long SLOW_PHASE_NANOS = 100_000_000L;
|
||||||
private static final Set<String> LOGGED_PHASES = new HashSet<>();
|
private static final Set<String> LOGGED_PHASES = new HashSet<>();
|
||||||
private static final Phase NOOP_PHASE = new Phase(0L, "", "", false, 0L);
|
|
||||||
private static long generation;
|
private static long generation;
|
||||||
private static String armedKey = "";
|
private static String armedKey = "";
|
||||||
|
|
||||||
@@ -29,19 +29,17 @@ public final class PortalSceneRenderTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Phase begin(String pair, String phase, String detail) {
|
public static Phase begin(String pair, String phase, String detail) {
|
||||||
if (!Boolean.getBoolean(DEBUG_PROPERTY)) {
|
boolean verbose = Boolean.getBoolean(DEBUG_PROPERTY);
|
||||||
return NOOP_PHASE;
|
|
||||||
}
|
|
||||||
long currentGeneration;
|
long currentGeneration;
|
||||||
boolean shouldLog;
|
boolean logStart;
|
||||||
synchronized (PortalSceneRenderTrace.class) {
|
synchronized (PortalSceneRenderTrace.class) {
|
||||||
currentGeneration = generation;
|
currentGeneration = generation;
|
||||||
shouldLog = LOGGED_PHASES.add(currentGeneration + ":" + pair + ":" + phase);
|
logStart = LOGGED_PHASES.add(currentGeneration + ":" + pair + ":" + phase);
|
||||||
}
|
}
|
||||||
if (shouldLog) {
|
if (logStart) {
|
||||||
Antarchy.LOGGER.info("Portal scene trace begin generation={} pair={} phase={} detail={}", currentGeneration, pair, phase, detail);
|
Antarchy.LOGGER.info("Portal scene trace begin generation={} pair={} phase={} detail={}", currentGeneration, pair, phase, detail);
|
||||||
}
|
}
|
||||||
return new Phase(currentGeneration, pair, phase, shouldLog, System.nanoTime());
|
return new Phase(currentGeneration, pair, phase, logStart, verbose, System.nanoTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void event(String pair, String event, String detail) {
|
public static void event(String pair, String event, String detail) {
|
||||||
@@ -63,15 +61,17 @@ public final class PortalSceneRenderTrace {
|
|||||||
private final long generation;
|
private final long generation;
|
||||||
private final String pair;
|
private final String pair;
|
||||||
private final String phase;
|
private final String phase;
|
||||||
private final boolean logCompletion;
|
private final boolean logStart;
|
||||||
|
private final boolean verbose;
|
||||||
private final long startNanos;
|
private final long startNanos;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
|
||||||
private Phase(long generation, String pair, String phase, boolean logCompletion, long startNanos) {
|
private Phase(long generation, String pair, String phase, boolean logStart, boolean verbose, long startNanos) {
|
||||||
this.generation = generation;
|
this.generation = generation;
|
||||||
this.pair = pair;
|
this.pair = pair;
|
||||||
this.phase = phase;
|
this.phase = phase;
|
||||||
this.logCompletion = logCompletion;
|
this.logStart = logStart;
|
||||||
|
this.verbose = verbose;
|
||||||
this.startNanos = startNanos;
|
this.startNanos = startNanos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,9 +81,10 @@ public final class PortalSceneRenderTrace {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.closed = true;
|
this.closed = true;
|
||||||
if (this.logCompletion) {
|
long durationNanos = System.nanoTime() - this.startNanos;
|
||||||
|
if (this.logStart && (this.verbose || durationNanos >= SLOW_PHASE_NANOS)) {
|
||||||
Antarchy.LOGGER.info("Portal scene trace complete generation={} pair={} phase={} durationMs={}",
|
Antarchy.LOGGER.info("Portal scene trace complete generation={} pair={} phase={} durationMs={}",
|
||||||
this.generation, this.pair, this.phase, (System.nanoTime() - this.startNanos) / 1_000_000.0D);
|
this.generation, this.pair, this.phase, durationNanos / 1_000_000.0D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conservative side planes through the destination opening and virtual eye.
|
||||||
|
* The exit plane itself is handled separately so bounds crossing it remain visible.
|
||||||
|
*/
|
||||||
|
public final class PortalGunApertureCuller {
|
||||||
|
private static final double MIN_EYE_DISTANCE = 0.05D;
|
||||||
|
private static final double PLANE_PADDING = 0.5D;
|
||||||
|
|
||||||
|
private final Vec3 eye;
|
||||||
|
private final Vec3[] inwardNormals;
|
||||||
|
|
||||||
|
private PortalGunApertureCuller(Vec3 eye, Vec3[] inwardNormals) {
|
||||||
|
this.eye = eye;
|
||||||
|
this.inwardNormals = inwardNormals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PortalGunApertureCuller create(PortalGunWorldPortalShape aperture, Vec3 eye) {
|
||||||
|
double eyeDepth = aperture.localCoords(eye).depth();
|
||||||
|
if (eyeDepth >= -MIN_EYE_DISTANCE) {
|
||||||
|
return new PortalGunApertureCuller(eye, null);
|
||||||
|
}
|
||||||
|
Vec3[] corners = aperture.getCorners(0.0D);
|
||||||
|
Vec3 centerRay = aperture.center().subtract(eye);
|
||||||
|
Vec3[] normals = new Vec3[corners.length];
|
||||||
|
for (int index = 0; index < corners.length; index++) {
|
||||||
|
Vec3 first = corners[index].subtract(eye);
|
||||||
|
Vec3 second = corners[(index + 1) % corners.length].subtract(eye);
|
||||||
|
Vec3 normal = first.cross(second);
|
||||||
|
if (normal.lengthSqr() < 1.0E-8D) {
|
||||||
|
return new PortalGunApertureCuller(eye, null);
|
||||||
|
}
|
||||||
|
normal = normal.normalize();
|
||||||
|
if (normal.dot(centerRay) < 0.0D) {
|
||||||
|
normal = normal.scale(-1.0D);
|
||||||
|
}
|
||||||
|
normals[index] = normal;
|
||||||
|
}
|
||||||
|
return new PortalGunApertureCuller(eye, normals);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean intersects(AABB bounds) {
|
||||||
|
if (inwardNormals == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (Vec3 normal : inwardNormals) {
|
||||||
|
double supportX = normal.x >= 0.0D ? bounds.maxX : bounds.minX;
|
||||||
|
double supportY = normal.y >= 0.0D ? bounds.maxY : bounds.minY;
|
||||||
|
double supportZ = normal.z >= 0.0D ? bounds.maxZ : bounds.minZ;
|
||||||
|
double maxDistance = (supportX - eye.x) * normal.x
|
||||||
|
+ (supportY - eye.y) * normal.y
|
||||||
|
+ (supportZ - eye.z) * normal.z;
|
||||||
|
if (maxDistance < -PLANE_PADDING) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
|
||||||
|
/** Applies the destination portal plane as the near plane of a camera projection. */
|
||||||
|
public final class PortalGunProjectionUtil {
|
||||||
|
private PortalGunProjectionUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matrix4f clipAtExit(Matrix4f projection, Vec3 eye, Vec3 look, Vec3 up,
|
||||||
|
Vec3 planePoint, Vec3 planeNormal) {
|
||||||
|
Vector4f clipPlane = planeInCameraSpace(eye, look, up, planePoint, planeNormal);
|
||||||
|
if (clipPlane.lengthSquared() <= 1.0E-6F) {
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
Vector4f q = new Vector4f(signNonZero(clipPlane.x()), signNonZero(clipPlane.y()), 1.0F, 1.0F)
|
||||||
|
.mul(new Matrix4f(projection).invert());
|
||||||
|
float planeCornerDot = clipPlane.dot(q);
|
||||||
|
if (!Float.isFinite(planeCornerDot) || Math.abs(planeCornerDot) <= 1.0E-6F) {
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
float scale = 2.0F / planeCornerDot;
|
||||||
|
Vector4f c = clipPlane.mul(scale, new Vector4f());
|
||||||
|
Matrix4f clipped = new Matrix4f(projection);
|
||||||
|
clipped.m02(c.x());
|
||||||
|
clipped.m12(c.y());
|
||||||
|
clipped.m22(c.z() + 1.0F);
|
||||||
|
clipped.m32(c.w());
|
||||||
|
return clipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector4f planeInCameraSpace(Vec3 eye, Vec3 look, Vec3 up, Vec3 planePoint, Vec3 planeNormal) {
|
||||||
|
Vec3 forward = look.normalize();
|
||||||
|
Vec3 correctedUp = up.subtract(forward.scale(up.dot(forward))).normalize();
|
||||||
|
Vec3 right = forward.cross(correctedUp).normalize();
|
||||||
|
Vec3 relativePoint = planePoint.subtract(eye);
|
||||||
|
Vector4f point = new Vector4f(
|
||||||
|
(float) relativePoint.dot(right),
|
||||||
|
(float) relativePoint.dot(correctedUp),
|
||||||
|
(float) -relativePoint.dot(forward),
|
||||||
|
1.0F
|
||||||
|
);
|
||||||
|
Vector4f normal = new Vector4f(
|
||||||
|
(float) planeNormal.dot(right),
|
||||||
|
(float) planeNormal.dot(correctedUp),
|
||||||
|
(float) -planeNormal.dot(forward),
|
||||||
|
0.0F
|
||||||
|
);
|
||||||
|
if (normal.z() > 0.0F) {
|
||||||
|
normal.mul(-1.0F);
|
||||||
|
}
|
||||||
|
return new Vector4f(normal.x(), normal.y(), normal.z(), -normal.dot(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float signNonZero(float value) {
|
||||||
|
return value >= 0.0F ? 1.0F : -1.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -65,6 +65,16 @@ public final class PortalGunTransformUtil {
|
|||||||
.add(destinationOut.scale(vector.dot(sourceInto)));
|
.add(destinationOut.scale(vector.dot(sourceInto)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vec3 transformPosition(PortalGunWorldPortalShape source, PortalGunWorldPortalShape destination, Vec3 relativePosition) {
|
||||||
|
return transformVector(source, destination, relativePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3 transformVector(PortalGunWorldPortalShape source, PortalGunWorldPortalShape destination, Vec3 vector) {
|
||||||
|
return destination.right().scale(-vector.dot(source.right()))
|
||||||
|
.add(destination.up().scale(vector.dot(source.up())))
|
||||||
|
.add(destination.normal().scale(-vector.dot(source.normal())));
|
||||||
|
}
|
||||||
|
|
||||||
public static float yawFromLook(Vec3 look) {
|
public static float yawFromLook(Vec3 look) {
|
||||||
return (float) Math.toDegrees(Math.atan2(-look.x, look.z));
|
return (float) Math.toDegrees(Math.atan2(-look.x, look.z));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public final class AntarchyMixinPlugin implements IMixinConfigPlugin {
|
|||||||
&& (mixinClassName.endsWith(".LevelRendererPortalViewAreaAccessor")
|
&& (mixinClassName.endsWith(".LevelRendererPortalViewAreaAccessor")
|
||||||
|| mixinClassName.endsWith(".LevelRendererPortalViewAreaMixin")
|
|| mixinClassName.endsWith(".LevelRendererPortalViewAreaMixin")
|
||||||
|| mixinClassName.endsWith(".LevelRendererPortalChunkBudgetMixin")
|
|| mixinClassName.endsWith(".LevelRendererPortalChunkBudgetMixin")
|
||||||
|
|| mixinClassName.endsWith(".SectionRenderDispatcherPortalUploadsAccessor")
|
||||||
|| mixinClassName.endsWith(".PortalViewChunkCacheMixin")
|
|| mixinClassName.endsWith(".PortalViewChunkCacheMixin")
|
||||||
|| mixinClassName.endsWith(".PortalViewSectionSortingMixin"))) {
|
|| mixinClassName.endsWith(".PortalViewSectionSortingMixin"))) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+8
@@ -12,6 +12,14 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
|||||||
|
|
||||||
@Mixin(LevelRenderer.class)
|
@Mixin(LevelRenderer.class)
|
||||||
public abstract class LevelRendererPortalChunkBudgetMixin {
|
public abstract class LevelRendererPortalChunkBudgetMixin {
|
||||||
|
@Redirect(
|
||||||
|
method = "compileSections",
|
||||||
|
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher;uploadAllPendingUploads()V")
|
||||||
|
)
|
||||||
|
private void antarchy$budgetPortalUploads(SectionRenderDispatcher dispatcher) {
|
||||||
|
PortalGunPortalRendererPool.uploadPending((LevelRenderer) (Object) this, dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "renderLevel",
|
method = "renderLevel",
|
||||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;pollLightUpdates()V")
|
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;pollLightUpdates()V")
|
||||||
|
|||||||
+3
@@ -16,6 +16,9 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
|||||||
|
|
||||||
@Mixin(LevelRenderer.class)
|
@Mixin(LevelRenderer.class)
|
||||||
public interface LevelRendererPortalViewAreaAccessor {
|
public interface LevelRendererPortalViewAreaAccessor {
|
||||||
|
@Accessor("sectionRenderDispatcher")
|
||||||
|
SectionRenderDispatcher antarchy$getSectionRenderDispatcher();
|
||||||
|
|
||||||
@Accessor("viewArea")
|
@Accessor("viewArea")
|
||||||
ViewArea antarchy$getViewArea();
|
ViewArea antarchy$getViewArea();
|
||||||
|
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.client;
|
||||||
|
|
||||||
|
import java.util.Queue;
|
||||||
|
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(SectionRenderDispatcher.class)
|
||||||
|
public interface SectionRenderDispatcherPortalUploadsAccessor {
|
||||||
|
@Accessor("toUpload")
|
||||||
|
Queue<Runnable> antarchy$getToUpload();
|
||||||
|
}
|
||||||
@@ -143,6 +143,7 @@
|
|||||||
"client.LevelRendererPortalViewAreaAccessor",
|
"client.LevelRendererPortalViewAreaAccessor",
|
||||||
"client.LevelRendererPortalViewAreaMixin",
|
"client.LevelRendererPortalViewAreaMixin",
|
||||||
"client.LevelRendererPortalChunkBudgetMixin",
|
"client.LevelRendererPortalChunkBudgetMixin",
|
||||||
|
"client.SectionRenderDispatcherPortalUploadsAccessor",
|
||||||
"client.LevelRendererPortalLifecycleMixin",
|
"client.LevelRendererPortalLifecycleMixin",
|
||||||
"client.PortalViewChunkCacheMixin",
|
"client.PortalViewChunkCacheMixin",
|
||||||
"client.PortalViewSectionSortingMixin",
|
"client.PortalViewSectionSortingMixin",
|
||||||
|
|||||||
Reference in new issue
Block a user