mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-07 12:56:31 +01:00
The manhattan batch
- Use atomics to determine buffer position for batches - Pass resultant vertex count to DrawBuffer once all transform calls have run - Refactor to use RunOnAllPlan within TransformCall - Make all vertex transform logic to operate per-instance instead of per-chunk - Cull instances based on bounding sphere transformations - Make BufferedMesh#mesh public to expose bounding sphere - Roll batching #plan() arguments into FrameContext record
This commit is contained in:
parent
1bd4c4f6cb
commit
5b84046c1d
11 changed files with 130 additions and 68 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
package com.jozufozu.flywheel.api.instance;
|
||||||
|
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
|
||||||
|
public interface InstanceBoundingSphereTransformer<I extends Instance> {
|
||||||
|
/**
|
||||||
|
* Transform the bounding sphere of a mesh to match the location of the instance.
|
||||||
|
*
|
||||||
|
* @param boundingSphere The bounding sphere of the mesh formatted as < x, y, z, radius >
|
||||||
|
* @param instance The instance to transform the bounding sphere for.
|
||||||
|
*/
|
||||||
|
void transform(Vector4f boundingSphere, I instance);
|
||||||
|
}
|
|
@ -30,4 +30,6 @@ public interface InstanceType<I extends Instance> {
|
||||||
ResourceLocation instanceShader();
|
ResourceLocation instanceShader();
|
||||||
|
|
||||||
InstanceVertexTransformer<I> getVertexTransformer();
|
InstanceVertexTransformer<I> getVertexTransformer();
|
||||||
|
|
||||||
|
InstanceBoundingSphereTransformer<I> getBoundingSphereTransformer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,7 @@ public class BatchedMeshPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BufferedMesh {
|
public class BufferedMesh {
|
||||||
private final Mesh mesh;
|
public final Mesh mesh;
|
||||||
private final int byteSize;
|
private final int byteSize;
|
||||||
private final int vertexCount;
|
private final int vertexCount;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.joml.FrustumIntersection;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
|
@ -17,6 +19,7 @@ import com.jozufozu.flywheel.api.task.Plan;
|
||||||
import com.jozufozu.flywheel.api.task.TaskExecutor;
|
import com.jozufozu.flywheel.api.task.TaskExecutor;
|
||||||
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
|
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
|
||||||
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
||||||
|
import com.jozufozu.flywheel.lib.math.MatrixUtil;
|
||||||
import com.jozufozu.flywheel.lib.task.NestedPlan;
|
import com.jozufozu.flywheel.lib.task.NestedPlan;
|
||||||
import com.jozufozu.flywheel.util.FlwUtil;
|
import com.jozufozu.flywheel.util.FlwUtil;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
@ -48,12 +51,22 @@ public class BatchingEngine extends AbstractEngine {
|
||||||
var stack = FlwUtil.copyPoseStack(context.stack());
|
var stack = FlwUtil.copyPoseStack(context.stack());
|
||||||
stack.translate(renderOrigin.getX() - cameraPos.x, renderOrigin.getY() - cameraPos.y, renderOrigin.getZ() - cameraPos.z);
|
stack.translate(renderOrigin.getX() - cameraPos.x, renderOrigin.getY() - cameraPos.y, renderOrigin.getZ() - cameraPos.z);
|
||||||
|
|
||||||
|
double cameraX = cameraPos.x;
|
||||||
|
double cameraY = cameraPos.y;
|
||||||
|
double cameraZ = cameraPos.z;
|
||||||
|
|
||||||
|
org.joml.Matrix4f proj = MatrixUtil.toJoml(context.viewProjection());
|
||||||
|
proj.translate((float) (renderOrigin.getX() - cameraX), (float) (renderOrigin.getY() - cameraY), (float) (renderOrigin.getZ() - cameraZ));
|
||||||
|
FrustumIntersection frustum = new FrustumIntersection(proj);
|
||||||
|
|
||||||
|
var ctx = new FrameContext(context.level(), stack.last(), frustum);
|
||||||
|
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
var plans = new ArrayList<Plan>();
|
var plans = new ArrayList<Plan>();
|
||||||
|
|
||||||
for (var transformSet : stages.values()) {
|
for (var transformSet : stages.values()) {
|
||||||
plans.add(transformSet.plan(stack.last(), context.level()));
|
plans.add(transformSet.plan(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NestedPlan(plans);
|
return new NestedPlan(plans);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||||
import com.jozufozu.flywheel.api.task.Plan;
|
import com.jozufozu.flywheel.api.task.Plan;
|
||||||
|
@ -11,9 +12,7 @@ import com.jozufozu.flywheel.api.task.TaskExecutor;
|
||||||
import com.jozufozu.flywheel.lib.task.NestedPlan;
|
import com.jozufozu.flywheel.lib.task.NestedPlan;
|
||||||
import com.jozufozu.flywheel.lib.task.Synchronizer;
|
import com.jozufozu.flywheel.lib.task.Synchronizer;
|
||||||
import com.jozufozu.flywheel.lib.task.UnitPlan;
|
import com.jozufozu.flywheel.lib.task.UnitPlan;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,11 +28,11 @@ public class BatchingStage {
|
||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plan plan(PoseStack.Pose matrices, ClientLevel level) {
|
public Plan plan(FrameContext ctx) {
|
||||||
var plans = new ArrayList<Plan>();
|
var plans = new ArrayList<Plan>();
|
||||||
|
|
||||||
for (var bufferPlan : buffers.values()) {
|
for (var bufferPlan : buffers.values()) {
|
||||||
plans.add(bufferPlan.update(matrices, level));
|
plans.add(bufferPlan.update(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NestedPlan(plans);
|
return new NestedPlan(plans);
|
||||||
|
@ -51,17 +50,15 @@ public class BatchingStage {
|
||||||
private class BufferPlan implements Plan {
|
private class BufferPlan implements Plan {
|
||||||
private final DrawBuffer buffer;
|
private final DrawBuffer buffer;
|
||||||
private final List<TransformCall<?>> transformCalls = new ArrayList<>();
|
private final List<TransformCall<?>> transformCalls = new ArrayList<>();
|
||||||
private PoseStack.Pose matrices;
|
private FrameContext ctx;
|
||||||
private ClientLevel level;
|
|
||||||
private int vertexCount;
|
private int vertexCount;
|
||||||
|
|
||||||
public BufferPlan(DrawBuffer drawBuffer) {
|
public BufferPlan(DrawBuffer drawBuffer) {
|
||||||
buffer = drawBuffer;
|
buffer = drawBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plan update(PoseStack.Pose matrices, ClientLevel level) {
|
public Plan update(FrameContext ctx) {
|
||||||
this.matrices = matrices;
|
this.ctx = ctx;
|
||||||
this.level = level;
|
|
||||||
|
|
||||||
vertexCount = setupAndCountVertices();
|
vertexCount = setupAndCountVertices();
|
||||||
if (vertexCount <= 0) {
|
if (vertexCount <= 0) {
|
||||||
|
@ -81,15 +78,17 @@ public class BatchingStage {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(TaskExecutor taskExecutor, Runnable onCompletion) {
|
public void execute(TaskExecutor taskExecutor, Runnable onCompletion) {
|
||||||
|
AtomicInteger vertexCounter = new AtomicInteger(0);
|
||||||
buffer.prepare(vertexCount);
|
buffer.prepare(vertexCount);
|
||||||
|
|
||||||
var synchronizer = new Synchronizer(transformCalls.size(), onCompletion);
|
var synchronizer = new Synchronizer(transformCalls.size(), () -> {
|
||||||
|
buffer.vertexCount(vertexCounter.get());
|
||||||
|
onCompletion.run();
|
||||||
|
});
|
||||||
|
|
||||||
int startVertex = 0;
|
|
||||||
for (var transformCall : transformCalls) {
|
for (var transformCall : transformCalls) {
|
||||||
transformCall.plan(buffer, startVertex, matrices, level)
|
transformCall.plan(ctx, buffer, vertexCounter)
|
||||||
.execute(taskExecutor, synchronizer::decrementAndEventuallyRun);
|
.execute(taskExecutor, synchronizer::decrementAndEventuallyRun);
|
||||||
startVertex += transformCall.getTotalVertexCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,19 +69,28 @@ public class DrawBuffer {
|
||||||
prepared = true;
|
prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void vertexCount(int vertexCount) {
|
||||||
|
this.vertexCount = vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
public ReusableVertexList slice(int startVertex, int vertexCount) {
|
public ReusableVertexList slice(int startVertex, int vertexCount) {
|
||||||
if (!prepared) {
|
if (!prepared) {
|
||||||
throw new IllegalStateException("Cannot slice DrawBuffer that is not prepared!");
|
throw new IllegalStateException("Cannot slice DrawBuffer that is not prepared!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ReusableVertexList vertexList = provider.createVertexList();
|
ReusableVertexList vertexList = provider.createVertexList();
|
||||||
vertexList.ptr(memory.ptr() + (long) startVertex * stride);
|
vertexList.ptr(ptrForVertex(startVertex));
|
||||||
vertexList.vertexCount(vertexCount);
|
vertexList.vertexCount(vertexCount);
|
||||||
return vertexList;
|
return vertexList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long ptrForVertex(long startVertex) {
|
||||||
|
return memory.ptr() + startVertex * stride;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects the backing buffer into the given builder and prepares it for rendering.
|
* Injects the backing buffer into the given builder and prepares it for rendering.
|
||||||
|
*
|
||||||
* @param bufferBuilder The buffer builder to inject into.
|
* @param bufferBuilder The buffer builder to inject into.
|
||||||
*/
|
*/
|
||||||
public void inject(BufferBuilderExtension bufferBuilder) {
|
public void inject(BufferBuilderExtension bufferBuilder) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.jozufozu.flywheel.backend.engine.batching;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
public record FrameContext(net.minecraft.client.multiplayer.ClientLevel level, PoseStack.Pose matrices,
|
||||||
|
org.joml.FrustumIntersection frustum) {
|
||||||
|
}
|
|
@ -1,23 +1,23 @@
|
||||||
package com.jozufozu.flywheel.backend.engine.batching;
|
package com.jozufozu.flywheel.backend.engine.batching;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.List;
|
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import org.joml.Vector4fc;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
|
import com.jozufozu.flywheel.api.instance.InstanceBoundingSphereTransformer;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceVertexTransformer;
|
import com.jozufozu.flywheel.api.instance.InstanceVertexTransformer;
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
import com.jozufozu.flywheel.api.material.MaterialVertexTransformer;
|
||||||
import com.jozufozu.flywheel.api.task.Plan;
|
import com.jozufozu.flywheel.api.task.Plan;
|
||||||
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||||
import com.jozufozu.flywheel.api.vertex.ReusableVertexList;
|
import com.jozufozu.flywheel.lib.task.RunOnAllPlan;
|
||||||
import com.jozufozu.flywheel.lib.math.MoreMath;
|
|
||||||
import com.jozufozu.flywheel.lib.task.SimplePlan;
|
|
||||||
import com.jozufozu.flywheel.lib.vertex.VertexTransformations;
|
import com.jozufozu.flywheel.lib.vertex.VertexTransformations;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Matrix3f;
|
import com.mojang.math.Matrix3f;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
|
||||||
|
|
||||||
public class TransformCall<I extends Instance> {
|
public class TransformCall<I extends Instance> {
|
||||||
private final CPUInstancer<I> instancer;
|
private final CPUInstancer<I> instancer;
|
||||||
private final Material material;
|
private final Material material;
|
||||||
|
@ -25,14 +25,23 @@ public class TransformCall<I extends Instance> {
|
||||||
|
|
||||||
private final int meshVertexCount;
|
private final int meshVertexCount;
|
||||||
private final int meshByteSize;
|
private final int meshByteSize;
|
||||||
|
private final InstanceVertexTransformer<I> instanceVertexTransformer;
|
||||||
|
private final MaterialVertexTransformer materialVertexTransformer;
|
||||||
|
private final InstanceBoundingSphereTransformer<I> boundingSphereTransformer;
|
||||||
|
private final Vector4fc boundingSphere;
|
||||||
|
|
||||||
public TransformCall(CPUInstancer<I> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
|
public TransformCall(CPUInstancer<I> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
|
||||||
this.instancer = instancer;
|
this.instancer = instancer;
|
||||||
this.material = material;
|
this.material = material;
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
|
|
||||||
|
instanceVertexTransformer = instancer.type.getVertexTransformer();
|
||||||
|
boundingSphereTransformer = instancer.type.getBoundingSphereTransformer();
|
||||||
|
materialVertexTransformer = material.getVertexTransformer();
|
||||||
|
|
||||||
meshVertexCount = mesh.getVertexCount();
|
meshVertexCount = mesh.getVertexCount();
|
||||||
meshByteSize = mesh.size();
|
meshByteSize = mesh.size();
|
||||||
|
boundingSphere = mesh.mesh.getBoundingSphere();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTotalVertexCount() {
|
public int getTotalVertexCount() {
|
||||||
|
@ -43,49 +52,28 @@ public class TransformCall<I extends Instance> {
|
||||||
instancer.update();
|
instancer.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plan plan(DrawBuffer buffer, int startVertex, PoseStack.Pose matrices, ClientLevel level) {
|
public Plan plan(FrameContext ctx, DrawBuffer buffer, final AtomicInteger vertexCount) {
|
||||||
final int totalCount = instancer.getInstanceCount();
|
return RunOnAllPlan.of(instancer::getAll, instance -> {
|
||||||
final int chunkSize = MoreMath.ceilingDiv(totalCount, 6 * 32);
|
var boundingSphere = new Vector4f(this.boundingSphere);
|
||||||
|
|
||||||
final var out = new ArrayList<Runnable>();
|
boundingSphereTransformer.transform(boundingSphere, instance);
|
||||||
int remaining = totalCount;
|
|
||||||
while (remaining > 0) {
|
|
||||||
int end = remaining;
|
|
||||||
remaining -= chunkSize;
|
|
||||||
int start = Math.max(remaining, 0);
|
|
||||||
|
|
||||||
int vertexCount = meshVertexCount * (end - start);
|
if (!ctx.frustum()
|
||||||
ReusableVertexList sub = buffer.slice(startVertex, vertexCount);
|
.testSphere(boundingSphere.x, boundingSphere.y, boundingSphere.z, boundingSphere.w)) {
|
||||||
startVertex += vertexCount;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
out.add(() -> transform(sub, matrices, level, instancer.getRange(start, end)));
|
final int baseVertex = vertexCount.getAndAdd(meshVertexCount);
|
||||||
}
|
|
||||||
return new SimplePlan(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void transform(ReusableVertexList vertexList, PoseStack.Pose matrices, ClientLevel level, List<I> instances) {
|
var sub = buffer.slice(baseVertex, meshVertexCount);
|
||||||
// save the total size of the slice for later.
|
|
||||||
final long anchorPtr = vertexList.ptr();
|
|
||||||
final int totalVertexCount = vertexList.vertexCount();
|
|
||||||
|
|
||||||
// while working on individual instances, the vertex list should expose just a single copy of the mesh.
|
mesh.copyTo(sub.ptr());
|
||||||
vertexList.vertexCount(meshVertexCount);
|
|
||||||
|
|
||||||
InstanceVertexTransformer<I> instanceVertexTransformer = instancer.type.getVertexTransformer();
|
instanceVertexTransformer.transform(sub, instance, ctx.level());
|
||||||
|
|
||||||
for (I instance : instances) {
|
materialVertexTransformer.transform(sub, ctx.level());
|
||||||
mesh.copyTo(vertexList.ptr());
|
applyMatrices(sub, ctx.matrices());
|
||||||
|
});
|
||||||
instanceVertexTransformer.transform(vertexList, instance, level);
|
|
||||||
|
|
||||||
vertexList.ptr(vertexList.ptr() + meshByteSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore the original size of the slice to apply per-vertex transformations.
|
|
||||||
vertexList.ptr(anchorPtr);
|
|
||||||
vertexList.vertexCount(totalVertexCount);
|
|
||||||
material.getVertexTransformer().transform(vertexList, level);
|
|
||||||
applyMatrices(vertexList, matrices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyMatrices(MutableVertexList vertexList, PoseStack.Pose matrices) {
|
private static void applyMatrices(MutableVertexList vertexList, PoseStack.Pose matrices) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package com.jozufozu.flywheel.lib.instance;
|
package com.jozufozu.flywheel.lib.instance;
|
||||||
|
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.api.instance.InstanceBoundingSphereTransformer;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceHandle;
|
import com.jozufozu.flywheel.api.instance.InstanceHandle;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceVertexTransformer;
|
import com.jozufozu.flywheel.api.instance.InstanceVertexTransformer;
|
||||||
|
@ -74,4 +77,13 @@ public class OrientedType implements InstanceType<OrientedInstance> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceBoundingSphereTransformer<OrientedInstance> getBoundingSphereTransformer() {
|
||||||
|
return (boundingSphere, instance) -> {
|
||||||
|
boundingSphere.sub(instance.pivotX, instance.pivotY, instance.pivotZ, 0);
|
||||||
|
boundingSphere.rotate(new Quaternionf(instance.qX, instance.qY, instance.qZ, instance.qW));
|
||||||
|
boundingSphere.add(instance.posX + instance.pivotX, instance.posY + instance.pivotY, instance.posZ + instance.pivotZ, 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package com.jozufozu.flywheel.lib.instance;
|
package com.jozufozu.flywheel.lib.instance;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.api.instance.InstanceBoundingSphereTransformer;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceHandle;
|
import com.jozufozu.flywheel.api.instance.InstanceHandle;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceVertexTransformer;
|
import com.jozufozu.flywheel.api.instance.InstanceVertexTransformer;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
||||||
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||||
import com.jozufozu.flywheel.lib.layout.CommonItems;
|
import com.jozufozu.flywheel.lib.layout.CommonItems;
|
||||||
|
import com.jozufozu.flywheel.lib.math.MatrixUtil;
|
||||||
import com.jozufozu.flywheel.lib.math.RenderMath;
|
import com.jozufozu.flywheel.lib.math.RenderMath;
|
||||||
import com.jozufozu.flywheel.lib.vertex.VertexTransformations;
|
import com.jozufozu.flywheel.lib.vertex.VertexTransformations;
|
||||||
|
|
||||||
|
@ -60,4 +62,14 @@ public class TransformedType implements InstanceType<TransformedInstance> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceBoundingSphereTransformer<TransformedInstance> getBoundingSphereTransformer() {
|
||||||
|
return (boundingSphere, instance) -> {
|
||||||
|
var radius = boundingSphere.w;
|
||||||
|
boundingSphere.w = 1;
|
||||||
|
boundingSphere.mul(MatrixUtil.toJoml(instance.model));
|
||||||
|
boundingSphere.w = radius * MatrixUtil.extractScale(instance.model);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,18 +129,25 @@ public final class MatrixUtil {
|
||||||
public static void store(Matrix3f matrix, org.joml.Matrix3f jomlMatrix) {
|
public static void store(Matrix3f matrix, org.joml.Matrix3f jomlMatrix) {
|
||||||
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
||||||
jomlMatrix.set(
|
jomlMatrix.set(
|
||||||
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(),
|
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22());
|
||||||
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(),
|
|
||||||
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static org.joml.Matrix3f toJoml(Matrix3f matrix) {
|
public static org.joml.Matrix3f toJoml(Matrix3f matrix) {
|
||||||
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
||||||
return new org.joml.Matrix3f(
|
return new org.joml.Matrix3f(m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22());
|
||||||
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(),
|
}
|
||||||
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(),
|
|
||||||
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22()
|
/**
|
||||||
);
|
* Extracts the greatest scale factor across all axes from the given matrix.
|
||||||
|
*
|
||||||
|
* @param matrix The matrix to extract the scale from.
|
||||||
|
* @return The greatest scale factor across all axes.
|
||||||
|
*/
|
||||||
|
public static float extractScale(Matrix4f matrix) {
|
||||||
|
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
|
||||||
|
float scaleSqrX = m.flywheel$m00() * m.flywheel$m00() + m.flywheel$m01() * m.flywheel$m01() + m.flywheel$m02() * m.flywheel$m02();
|
||||||
|
float scaleSqrY = m.flywheel$m10() * m.flywheel$m10() + m.flywheel$m11() * m.flywheel$m11() + m.flywheel$m12() * m.flywheel$m12();
|
||||||
|
float scaleSqrZ = m.flywheel$m20() * m.flywheel$m20() + m.flywheel$m21() * m.flywheel$m21() + m.flywheel$m22() * m.flywheel$m22();
|
||||||
|
return (float) Math.sqrt(Math.max(Math.max(scaleSqrX, scaleSqrY), scaleSqrZ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue