Lines aren't too bad

- Add LineModelBuilder and use that instead of the manual mesh creation
  in HitboxComponent.
- Clone mojang's line shader, adapted as a flywheel material.
  - Do not scale the view.
  - Set flw_vertexPos by multiplying by the inverse view projection.
- Remove centerline material.
- Use #define make padded vec3 uniforms available as actual vec3s.
- Add flw_viewProjectionInverse to uniforms.
- Minecarts actually delete the stuff from SimpleEntityVisual.
This commit is contained in:
Jozufozu 2024-02-02 14:15:36 -08:00
parent 31148ae9b5
commit e7d7602941
12 changed files with 371 additions and 227 deletions

View File

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.engine.uniform;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryUtil;
@ -7,16 +8,19 @@ import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.lib.math.MatrixMath;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Vec3i;
import net.minecraft.world.phys.Vec3;
public class FrameUniforms implements UniformProvider {
public static final int SIZE = 232;
public static final int SIZE = 304;
@Nullable
private RenderContext context;
private final Matrix4f viewProjection = new Matrix4f();
private final Matrix4f viewProjectionInverse = new Matrix4f();
public int byteSize() {
return SIZE;
@ -28,6 +32,10 @@ public class FrameUniforms implements UniformProvider {
@Override
public void write(long ptr) {
if (context == null) {
return;
}
Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level())
.getRenderOrigin();
var camera = context.camera();
@ -45,27 +53,43 @@ public class FrameUniforms implements UniformProvider {
Uniforms.frustumCapture = false;
}
MatrixMath.writeUnsafe(viewProjection, ptr + 96);
writeVec3(ptr + 160, camX, camY, camZ);
ptr += 96;
var lookVector = camera.getLookVector();
writeVec3(ptr + 176, lookVector.x, lookVector.y, lookVector.z);
ptr = writeMatrices(ptr);
ptr = writeCamera(ptr, camX, camY, camZ, camera);
writeVec2(ptr + 192, camera.getXRot(), camera.getYRot());
var window = Minecraft.getInstance()
.getWindow();
writeVec2(ptr + 200, window.getWidth(), window.getHeight());
ptr = writeVec2(ptr, window.getWidth(), window.getHeight());
// default line width: net.minecraft.client.renderer.RenderStateShard.LineStateShard
MemoryUtil.memPutFloat(ptr + 208, Math.max(2.5F, (float) window.getWidth() / 1920.0F * 2.5F));
MemoryUtil.memPutFloat(ptr, Math.max(2.5F, (float) window.getWidth() / 1920.0F * 2.5F));
ptr += 4;
MemoryUtil.memPutInt(ptr + 212, getConstantAmbientLightFlag(context));
MemoryUtil.memPutInt(ptr, getConstantAmbientLightFlag(context));
ptr += 4;
writeTime(ptr + 216);
writeTime(ptr);
}
private void writeTime(long ptr) {
private long writeMatrices(long ptr) {
MatrixMath.writeUnsafe(viewProjection, ptr);
MatrixMath.writeUnsafe(viewProjection.invert(viewProjectionInverse), ptr + 64);
return ptr + 128;
}
private static long writeCamera(long ptr, float camX, float camY, float camZ, Camera camera) {
ptr = writeVec3(ptr, camX, camY, camZ);
var lookVector = camera.getLookVector();
ptr = writeVec3(ptr, lookVector.x, lookVector.y, lookVector.z);
ptr = writeVec2(ptr, camera.getXRot(), camera.getYRot());
return ptr;
}
private long writeTime(long ptr) {
int ticks = context.renderer()
.getTicks();
float partialTick = context.partialTick();
@ -76,18 +100,21 @@ public class FrameUniforms implements UniformProvider {
MemoryUtil.memPutFloat(ptr + 4, partialTick);
MemoryUtil.memPutFloat(ptr + 8, renderTicks);
MemoryUtil.memPutFloat(ptr + 12, renderSeconds);
return ptr + 16;
}
private static void writeVec3(long ptr, float camX, float camY, float camZ) {
private static long writeVec3(long ptr, float camX, float camY, float camZ) {
MemoryUtil.memPutFloat(ptr, camX);
MemoryUtil.memPutFloat(ptr + 4, camY);
MemoryUtil.memPutFloat(ptr + 8, camZ);
MemoryUtil.memPutFloat(ptr + 12, 0f); // empty component of vec4 because we don't trust std140
return ptr + 16;
}
private static void writeVec2(long ptr, float camX, float camY) {
private static long writeVec2(long ptr, float camX, float camY) {
MemoryUtil.memPutFloat(ptr, camX);
MemoryUtil.memPutFloat(ptr + 4, camY);
return ptr + 8;
}
private static int getConstantAmbientLightFlag(RenderContext context) {

View File

@ -12,7 +12,7 @@ public final class StandardMaterialShaders {
public static final MaterialShaders WIREFRAME = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag")));
public static final MaterialShaders CENTERLINE = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/centerline.vert"), Flywheel.rl("material/centerline.frag")));
public static final MaterialShaders LINE = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/lines.vert"), Flywheel.rl("material/lines.frag")));
private StandardMaterialShaders() {
}

View File

@ -0,0 +1,159 @@
package com.jozufozu.flywheel.lib.model;
import org.joml.Vector4f;
import org.joml.Vector4fc;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.IndexSequence;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.material.SimpleMaterial;
import com.jozufozu.flywheel.lib.material.StandardMaterialShaders;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.vertex.FullVertexView;
import net.minecraft.client.renderer.LightTexture;
public class LineModelBuilder {
public static final Material MATERIAL = SimpleMaterial.builder()
.shaders(StandardMaterialShaders.LINE)
.backfaceCulling(false)
.diffuse(false)
.build();
private final VertexView vertices;
private MemoryBlock block;
private int vertexCount = 0;
private LineModelBuilder(int segmentCount) {
this.vertices = new FullVertexView();
this.block = MemoryBlock.malloc(segmentCount * 4 * FullVertexView.STRIDE);
vertices.ptr(block.ptr());
}
public static LineModelBuilder withCapacity(int segmentCount) {
return new LineModelBuilder(segmentCount);
}
public LineModelBuilder line(float x1, float y1, float z1, float x2, float y2, float z2) {
ensureCapacity(vertexCount + 4);
// We'll use the normal to figure out the orientation of the line in the vertex shader.
float dx = x2 - x1;
float dy = y2 - y1;
float dz = z2 - z1;
float length = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
float normalX = dx / length;
float normalY = dy / length;
float normalZ = dz / length;
for (int i = 0; i < 2; i++) {
vertices.x(vertexCount + i, x1);
vertices.y(vertexCount + i, y1);
vertices.z(vertexCount + i, z1);
vertices.x(vertexCount + 2 + i, x2);
vertices.y(vertexCount + 2 + i, y2);
vertices.z(vertexCount + 2 + i, z2);
}
for (int i = 0; i < 4; i++) {
vertices.r(vertexCount + i, 1);
vertices.g(vertexCount + i, 1);
vertices.b(vertexCount + i, 1);
vertices.a(vertexCount + i, 1);
vertices.u(vertexCount + i, 0);
vertices.v(vertexCount + i, 0);
vertices.light(vertexCount + i, LightTexture.FULL_BRIGHT);
vertices.normalX(vertexCount + i, normalX);
vertices.normalY(vertexCount + i, normalY);
vertices.normalZ(vertexCount + i, normalZ);
}
vertexCount += 4;
return this;
}
public Model build() {
vertices.vertexCount(vertexCount);
var boundingSphere = ModelUtil.computeBoundingSphere(vertices);
boundingSphere.w += 0.1f; // make the bounding sphere a little bigger to account for line width
var mesh = new LineMesh(vertexCount, vertices, block, boundingSphere);
return new SingleMeshModel(mesh, MATERIAL);
}
private void ensureCapacity(int vertexCount) {
if (vertexCount * FullVertexView.STRIDE > block.size()) {
this.block = block.realloc(vertexCount * FullVertexView.STRIDE);
vertices.ptr(block.ptr());
}
}
public static class LineMesh implements Mesh {
public static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> {
int numVertices = 4 * (count / 6);
int baseVertex = 0;
while (baseVertex < numVertices) {
// triangle a
MemoryUtil.memPutInt(ptr, baseVertex);
MemoryUtil.memPutInt(ptr + 4, baseVertex + 1);
MemoryUtil.memPutInt(ptr + 8, baseVertex + 2);
// triangle b
MemoryUtil.memPutInt(ptr + 12, baseVertex + 3);
MemoryUtil.memPutInt(ptr + 16, baseVertex + 2);
MemoryUtil.memPutInt(ptr + 20, baseVertex + 1);
baseVertex += 4;
ptr += 24;
}
};
private final int vertexCount;
private final VertexView vertexView;
private final MemoryBlock data;
private final Vector4f boundingSphere;
public LineMesh(int vertexCount, VertexView vertexView, MemoryBlock data, Vector4f boundingSphere) {
this.vertexCount = vertexCount;
this.vertexView = vertexView;
this.data = data;
this.boundingSphere = boundingSphere;
}
@Override
public int vertexCount() {
return vertexCount;
}
@Override
public void write(MutableVertexList vertexList) {
vertexView.writeAll(vertexList);
}
@Override
public IndexSequence indexSequence() {
return INDEX_SEQUENCE;
}
@Override
public int indexCount() {
return vertexCount / 2 * 3;
}
@Override
public Vector4fc boundingSphere() {
return boundingSphere;
}
@Override
public void delete() {
data.free();
}
}
}

View File

@ -1,195 +0,0 @@
package com.jozufozu.flywheel.lib.visual.components;
import org.joml.Quaternionf;
import org.joml.Vector4f;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
import com.jozufozu.flywheel.lib.instance.TransformedInstance;
import com.jozufozu.flywheel.lib.material.SimpleMaterial;
import com.jozufozu.flywheel.lib.material.StandardMaterialShaders;
import com.jozufozu.flywheel.lib.math.MoreMath;
import com.jozufozu.flywheel.lib.model.QuadMesh;
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.visual.EntityComponent;
import com.jozufozu.flywheel.lib.visual.SmartRecycler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
public class BoundingBoxComponent implements EntityComponent {
private static final Material WIREFRAME = SimpleMaterial.builder()
.shaders(StandardMaterialShaders.WIREFRAME)
.backfaceCulling(false)
.build();
private static final Material CENTERLINE = SimpleMaterial.builder()
.shaders(StandardMaterialShaders.CENTERLINE)
.backfaceCulling(false)
.build();
private static final Model BOX = new SingleMeshModel(BoundingBoxMesh.INSTANCE, WIREFRAME);
// Should we try a single quad oriented to face the camera instead?
private static final Model LINE = new SingleMeshModel(BoundingBoxMesh.INSTANCE, CENTERLINE);
private final VisualizationContext context;
private final Entity entity;
private boolean showEyeBox;
private final SmartRecycler<Model, TransformedInstance> recycler;
public BoundingBoxComponent(VisualizationContext context, Entity entity) {
this.context = context;
this.entity = entity;
this.showEyeBox = entity instanceof LivingEntity;
this.recycler = new SmartRecycler<>(this::createInstance);
}
private TransformedInstance createInstance(Model model) {
TransformedInstance instance = context.instancerProvider()
.instancer(InstanceTypes.TRANSFORMED, model)
.createInstance();
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK));
instance.setChanged();
return instance;
}
public BoundingBoxComponent showEyeBox(boolean renderEyeBox) {
this.showEyeBox = renderEyeBox;
return this;
}
@Override
public void beginFrame(VisualFrameContext context) {
recycler.resetCount();
var shouldRenderHitBoxes = Minecraft.getInstance()
.getEntityRenderDispatcher()
.shouldRenderHitBoxes();
if (shouldRenderHitBoxes && !entity.isInvisible() && !Minecraft.getInstance()
.showOnlyReducedInfo()) {
double entityX = Mth.lerp(context.partialTick(), entity.xOld, entity.getX());
double entityY = Mth.lerp(context.partialTick(), entity.yOld, entity.getY());
double entityZ = Mth.lerp(context.partialTick(), entity.zOld, entity.getZ());
var bbWidth = entity.getBbWidth();
var bbHeight = entity.getBbHeight();
var bbWidthHalf = bbWidth * 0.5;
recycler.get(BOX)
.loadIdentity()
.translate(entityX - bbWidthHalf, entityY, entityZ - bbWidthHalf)
.scale(bbWidth, bbHeight, bbWidth)
.setChanged();
// TODO: multipart entities, but forge seems to have an
// injection for them so we'll need platform specific code.
if (showEyeBox) {
recycler.get(BOX)
.loadIdentity()
.translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf)
.scale(bbWidth, 0.02f, bbWidth)
.setColor(255, 0, 0)
.setChanged();
}
var viewVector = entity.getViewVector(context.partialTick());
recycler.get(LINE)
.loadIdentity()
.translate(entityX, entityY + entity.getEyeHeight(), entityZ)
.rotate(new Quaternionf().rotateTo(0, 1, 0, (float) viewVector.x, (float) viewVector.y, (float) viewVector.z))
.scale(0.02f, 2f, 0.02f)
.setColor(0, 0, 255)
.setChanged();
}
recycler.discardExtra();
}
@Override
public void delete() {
recycler.delete();
}
private static class BoundingBoxMesh implements QuadMesh {
private static final BoundingBoxMesh INSTANCE = new BoundingBoxMesh();
private static final Vector4fc BOUNDING_SPHERE = new Vector4f(0.5f, 0.5f, 0.5f, MoreMath.SQRT_3_OVER_2);
private BoundingBoxMesh() {
}
@Override
public int vertexCount() {
return 24;
}
@Override
public void write(MutableVertexList vertexList) {
// very cursed, maybe we should use vanilla ModelParts instead?
writeVertex(vertexList, 0, 0, 0, 0, 0, 0);
writeVertex(vertexList, 1, 1, 0, 0, 1, 0);
writeVertex(vertexList, 2, 1, 1, 0, 1, 1);
writeVertex(vertexList, 3, 0, 1, 0, 0, 1);
writeVertex(vertexList, 4, 0, 0, 1, 0, 0);
writeVertex(vertexList, 5, 0, 0, 0, 1, 0);
writeVertex(vertexList, 6, 0, 1, 0, 1, 1);
writeVertex(vertexList, 7, 0, 1, 1, 0, 1);
writeVertex(vertexList, 8, 0, 1, 0, 0, 0);
writeVertex(vertexList, 9, 1, 1, 0, 1, 0);
writeVertex(vertexList, 10, 1, 1, 1, 1, 1);
writeVertex(vertexList, 11, 0, 1, 1, 0, 1);
writeVertex(vertexList, 12, 1, 0, 1, 0, 0);
writeVertex(vertexList, 13, 0, 0, 1, 1, 0);
writeVertex(vertexList, 14, 0, 1, 1, 1, 1);
writeVertex(vertexList, 15, 1, 1, 1, 0, 1);
writeVertex(vertexList, 16, 1, 0, 0, 0, 0);
writeVertex(vertexList, 17, 1, 0, 1, 1, 0);
writeVertex(vertexList, 18, 1, 1, 1, 1, 1);
writeVertex(vertexList, 19, 1, 1, 0, 0, 1);
writeVertex(vertexList, 20, 0, 0, 0, 0, 0);
writeVertex(vertexList, 21, 1, 0, 0, 1, 0);
writeVertex(vertexList, 22, 1, 0, 1, 1, 1);
writeVertex(vertexList, 23, 0, 0, 1, 0, 1);
}
@Override
public Vector4fc boundingSphere() {
return BOUNDING_SPHERE;
}
@Override
public void delete() {
}
private static void writeVertex(MutableVertexList vertexList, int i, float x, float y, float z, float u, float v) {
vertexList.x(i, x);
vertexList.y(i, y);
vertexList.z(i, z);
vertexList.r(i, 1);
vertexList.g(i, 1);
vertexList.b(i, 1);
vertexList.u(i, u);
vertexList.v(i, v);
vertexList.light(i, LightTexture.FULL_BRIGHT);
vertexList.normalX(i, 0);
vertexList.normalY(i, 1);
vertexList.normalZ(i, 0);
}
}
}

View File

@ -0,0 +1,134 @@
package com.jozufozu.flywheel.lib.visual.components;
import org.joml.Quaternionf;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
import com.jozufozu.flywheel.lib.instance.TransformedInstance;
import com.jozufozu.flywheel.lib.model.LineModelBuilder;
import com.jozufozu.flywheel.lib.model.ModelHolder;
import com.jozufozu.flywheel.lib.visual.EntityComponent;
import com.jozufozu.flywheel.lib.visual.SmartRecycler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
public class HitboxComponent implements EntityComponent {
// 010------110
// /| /|
// / | / |
// 011------111 |
// | | | |
// | 000----|-100
// | / | /
// |/ |/
// 001------101
private static final ModelHolder BOX = new ModelHolder(() -> LineModelBuilder.withCapacity(12)
// Starting from 0, 0, 0
.line(0, 0, 0, 0, 0, 1)
.line(0, 0, 0, 0, 1, 0)
.line(0, 0, 0, 1, 0, 0)
// Starting from 0, 1, 1
.line(0, 1, 1, 0, 1, 0)
.line(0, 1, 1, 0, 0, 1)
.line(0, 1, 1, 1, 1, 1)
// Starting from 1, 0, 1
.line(1, 0, 1, 1, 0, 0)
.line(1, 0, 1, 1, 1, 1)
.line(1, 0, 1, 0, 0, 1)
// Starting from 1, 1, 0
.line(1, 1, 0, 1, 1, 1)
.line(1, 1, 0, 1, 0, 0)
.line(1, 1, 0, 0, 1, 0)
.build());
private static final ModelHolder LINE = new ModelHolder(() -> LineModelBuilder.withCapacity(1)
.line(0, 0, 0, 0, 2, 0)
.build());
private final VisualizationContext context;
private final Entity entity;
private boolean showEyeBox;
private final SmartRecycler<Model, TransformedInstance> recycler;
public HitboxComponent(VisualizationContext context, Entity entity) {
this.context = context;
this.entity = entity;
this.showEyeBox = entity instanceof LivingEntity;
this.recycler = new SmartRecycler<>(this::createInstance);
}
private TransformedInstance createInstance(Model model) {
TransformedInstance instance = context.instancerProvider()
.instancer(InstanceTypes.TRANSFORMED, model)
.createInstance();
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK));
instance.setChanged();
return instance;
}
public HitboxComponent showEyeBox(boolean renderEyeBox) {
this.showEyeBox = renderEyeBox;
return this;
}
@Override
public void beginFrame(VisualFrameContext context) {
recycler.resetCount();
var shouldRenderHitBoxes = Minecraft.getInstance()
.getEntityRenderDispatcher()
.shouldRenderHitBoxes();
if (shouldRenderHitBoxes && !entity.isInvisible() && !Minecraft.getInstance()
.showOnlyReducedInfo()) {
double entityX = Mth.lerp(context.partialTick(), entity.xOld, entity.getX());
double entityY = Mth.lerp(context.partialTick(), entity.yOld, entity.getY());
double entityZ = Mth.lerp(context.partialTick(), entity.zOld, entity.getZ());
var bbWidth = entity.getBbWidth();
var bbHeight = entity.getBbHeight();
var bbWidthHalf = bbWidth * 0.5;
recycler.get(BOX.get())
.loadIdentity()
.translate(entityX - bbWidthHalf, entityY, entityZ - bbWidthHalf)
.scale(bbWidth, bbHeight, bbWidth)
.setChanged();
// TODO: multipart entities, but forge seems to have an
// injection for them so we'll need platform specific code.
if (showEyeBox) {
recycler.get(BOX.get())
.loadIdentity()
.translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf)
.scale(bbWidth, 0.02f, bbWidth)
.setColor(255, 0, 0)
.setChanged();
}
var viewVector = entity.getViewVector(context.partialTick());
recycler.get(LINE.get())
.loadIdentity()
.translate(entityX, entityY + entity.getEyeHeight(), entityZ)
.rotate(new Quaternionf().rotateTo(0, 1, 0, (float) viewVector.x, (float) viewVector.y, (float) viewVector.z))
.setColor(0, 0, 255)
.setChanged();
}
recycler.discardExtra();
}
@Override
public void delete() {
recycler.delete();
}
}

View File

@ -15,8 +15,8 @@ import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.visual.SimpleEntityVisual;
import com.jozufozu.flywheel.lib.visual.components.BoundingBoxComponent;
import com.jozufozu.flywheel.lib.visual.components.FireComponent;
import com.jozufozu.flywheel.lib.visual.components.HitboxComponent;
import com.jozufozu.flywheel.lib.visual.components.ShadowComponent;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
@ -63,7 +63,7 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
public void init(float partialTick) {
addComponent(new ShadowComponent(visualizationContext, entity).radius(0.7f));
addComponent(new FireComponent(visualizationContext, entity));
addComponent(new BoundingBoxComponent(visualizationContext, entity));
addComponent(new HitboxComponent(visualizationContext, entity));
body = createBodyInstance();
blockState = entity.getDisplayBlockState();
@ -210,6 +210,7 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
@Override
protected void _delete() {
super._delete();
body.delete();
if (contents != null) {
contents.delete();

View File

@ -9,6 +9,7 @@ void _flw_main(in FlwInstance instance) {
flw_vertexNormal = normalize(flw_vertexNormal);
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos.xyz, flw_fogShape);
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape);
gl_Position = flw_viewProjection * flw_vertexPos;
}

View File

@ -11,9 +11,12 @@ struct FrustumPlanes {
layout(std140) uniform _FlwFrameUniforms {
FrustumPlanes flw_frustumPlanes;
mat4 flw_viewProjection;
vec4 flw_cameraPos;
vec4 flw_cameraLook;
mat4 flw_viewProjectionInverse;
vec4 _flw_cameraPos;
vec4 _flw_cameraLook;
vec2 flw_cameraRot;
vec2 flw_viewportSize;
@ -27,3 +30,6 @@ layout(std140) uniform _FlwFrameUniforms {
float flw_renderTicks;
float flw_renderSeconds;
};
#define flw_cameraPos _flw_cameraPos.xyz
#define flw_cameraLook _flw_cameraLook.xyz

View File

@ -1,10 +0,0 @@
void flw_materialFragment() {
float toCenter = abs(flw_vertexTexCoord.s - 0.5);
// multiply by fwidth to get the width of the edge in screen space
if (flw_defaultLineWidth * fwidth(toCenter) < toCenter) {
discard;
}
flw_fragColor = flw_vertexColor;
}

View File

@ -1,2 +0,0 @@
void flw_materialVertex() {
}

View File

@ -0,0 +1,3 @@
void flw_materialFragment() {
flw_fragColor = flw_vertexColor;
}

View File

@ -0,0 +1,20 @@
void flw_materialVertex() {
vec4 linePosStart = flw_viewProjection * flw_vertexPos;
vec4 linePosEnd = flw_viewProjection * (flw_vertexPos + vec4(flw_vertexNormal, 0.));
vec3 ndc1 = linePosStart.xyz / linePosStart.w;
vec3 ndc2 = linePosEnd.xyz / linePosEnd.w;
vec2 lineScreenDirection = normalize((ndc2.xy - ndc1.xy) * flw_viewportSize);
vec2 lineOffset = vec2(-lineScreenDirection.y, lineScreenDirection.x) * flw_defaultLineWidth / flw_viewportSize;
if (lineOffset.x < 0.0) {
lineOffset *= -1.0;
}
if (gl_VertexID % 2 == 0) {
flw_vertexPos = flw_viewProjectionInverse * vec4((ndc1 + vec3(lineOffset, 0.)) * linePosStart.w, linePosStart.w);
} else {
flw_vertexPos = flw_viewProjectionInverse * vec4((ndc1 - vec3(lineOffset, 0.)) * linePosStart.w, linePosStart.w);
}
}