correct contraption lighting

This commit is contained in:
JozsefA 2021-01-09 16:34:22 -08:00
parent 7443ac5031
commit 876ddde660
10 changed files with 173 additions and 68 deletions

View file

@ -78,6 +78,7 @@ public class ClientEvents {
return; return;
CreateClient.kineticRenderer.tick(); CreateClient.kineticRenderer.tick();
FastContraptionRenderer.tick();
CreateClient.schematicSender.tick(); CreateClient.schematicSender.tick();
CreateClient.schematicAndQuillHandler.tick(); CreateClient.schematicAndQuillHandler.tick();

View file

@ -1,15 +1,16 @@
package com.simibubi.create.foundation.utility.render; package com.simibubi.create.foundation.utility.render;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.LightType; import net.minecraft.world.LightType;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.lighting.WorldLightManager; import net.minecraft.world.lighting.WorldLightManager;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.*;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL40;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
@ -27,6 +28,8 @@ public class ContraptionLighter {
ByteBuffer lightVolume; ByteBuffer lightVolume;
boolean dirty;
int texture; int texture;
public ContraptionLighter(Contraption contraption) { public ContraptionLighter(Contraption contraption) {
@ -34,53 +37,114 @@ public class ContraptionLighter {
AxisAlignedBB bounds = contraption.bounds; AxisAlignedBB bounds = contraption.bounds;
int minX = (int) Math.floor(bounds.minX); int minX = (int) Math.floor(bounds.minX) - 1;
int minY = (int) Math.floor(bounds.minY); int minY = (int) Math.floor(bounds.minY) - 1;
int minZ = (int) Math.floor(bounds.minZ); int minZ = (int) Math.floor(bounds.minZ) - 1;
int maxX = (int) Math.ceil(bounds.maxX); int maxX = (int) Math.ceil(bounds.maxX) + 1;
int maxY = (int) Math.ceil(bounds.maxY); int maxY = (int) Math.ceil(bounds.maxY) + 1;
int maxZ = (int) Math.ceil(bounds.maxZ); int maxZ = (int) Math.ceil(bounds.maxZ) + 1;
sizeX = maxX - minX; sizeX = nextPowerOf2(maxX - minX);
sizeY = maxY - minY; sizeY = nextPowerOf2(maxY - minY);
sizeZ = maxZ - minZ; sizeZ = nextPowerOf2(maxZ - minZ);
lightVolume = GLAllocation.createDirectByteBuffer(sizeX * sizeY * sizeZ * 2); lightVolume = GLAllocation.createDirectByteBuffer(sizeX * sizeY * sizeZ * 2);
tick(contraption);
}
public static int nextPowerOf2(int a) {
int h = Integer.highestOneBit(a);
return (h == a) ? h : (h << 1);
}
public int getSizeX() {
return sizeX;
}
public int getSizeY() {
return sizeY;
}
public int getSizeZ() {
return sizeZ;
}
public int getMinX() {
return minX;
}
public int getMinY() {
return minY;
}
public int getMinZ() {
return minZ;
} }
public void delete() { public void delete() {
GL11.glDeleteTextures(texture); CreateClient.kineticRenderer.enqueue(() -> {
GL15.glDeleteTextures(texture);
});
} }
public void tick() { private void setupPosition(Contraption c) {
Vec3d positionVec = c.entity.getPositionVec();
minX = (int) (Math.floor(positionVec.x) - sizeX / 2);
minY = (int) (Math.floor(positionVec.y));
minZ = (int) (Math.floor(positionVec.z) - sizeZ / 2);
} }
public void addLightData(World world, BlockPos pos) { public void tick(Contraption c) {
setupPosition(c);
int contraptionX = pos.getX() - minX; World world = c.entity.world;
int contraptionY = pos.getY() - minY;
int contraptionZ = pos.getZ() - minZ;
if (contraptionX < 0 || contraptionX >= sizeX || contraptionY < 0 || contraptionY >= sizeY || contraptionZ < 0 || contraptionZ >= sizeZ) BlockPos.Mutable pos = new BlockPos.Mutable();
return;
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
pos.setPos(minX + x, minY + y, minZ + z);
int blockLight = world.getLightLevel(LightType.BLOCK, pos); int blockLight = world.getLightLevel(LightType.BLOCK, pos);
int skyLight = world.getLightLevel(LightType.SKY, pos); int skyLight = world.getLightLevel(LightType.SKY, pos);
writeLight(contraptionX, contraptionY, contraptionZ, blockLight, skyLight); writeLight(x, y, z, blockLight, skyLight);
}
}
}
dirty = true;
} }
private void writeLight(int x, int y, int z, int block, int sky) { private void writeLight(int x, int y, int z, int block, int sky) {
int i = (x + y * sizeX + z * sizeX * sizeY) * 2; int i = (x + sizeX * (y + z * sizeY)) * 2;
lightVolume.put(i, (byte) (block * 16)); byte b = (byte) ((block & 0xF) << 4);
lightVolume.put(i + 1, (byte) (sky * 16)); byte s = (byte) ((sky & 0xF) << 4);
lightVolume.put(i, b);
lightVolume.put(i + 1, s);
} }
public void use() { public void use() {
GL13.glEnable(GL31.GL_TEXTURE_3D);
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4);
GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture); GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture);
lightVolume.rewind(); if (dirty) {
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume); GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume);
dirty = false;
}
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL13.GL_CLAMP);
GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP);
}
public void release() {
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4);
GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0);
} }
} }

View file

@ -14,18 +14,20 @@ import net.minecraft.client.renderer.color.BlockColors;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.event.RenderWorldLastEvent;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL40; import org.lwjgl.opengl.GL40;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
public class FastContraptionRenderer extends ContraptionRenderer { public class FastContraptionRenderer extends ContraptionRenderer {
private static final Cache<Integer, FastContraptionRenderer> renderers = CacheBuilder.newBuilder().build(); private static final HashMap<Integer, FastContraptionRenderer> renderers = new HashMap<>();
private ArrayList<ContraptionBuffer> renderLayers = new ArrayList<>(); private ArrayList<ContraptionBuffer> renderLayers = new ArrayList<>();
@ -43,33 +45,48 @@ public class FastContraptionRenderer extends ContraptionRenderer {
buildLayers(); buildLayers();
} }
public static void tick() {
if (Minecraft.getInstance().isGamePaused()) return;
CreateClient.kineticRenderer.enqueue(() -> {
for (FastContraptionRenderer renderer : renderers.values()) {
renderer.lighter.tick(renderer.c);
}
});
}
private void setRenderSettings(Vec3d position, Vec3d rotation) { private void setRenderSettings(Vec3d position, Vec3d rotation) {
renderPos = position; renderPos = position;
renderRot = rotation; renderRot = rotation;
} }
private void render(int shader) { private void render(int shader) {
// GL13.glActiveTexture(GL40.GL_TEXTURE2); lighter.use();
// lighter.use();
int cSize = GlStateManager.getUniformLocation(shader, "cSize");
int cPos = GlStateManager.getUniformLocation(shader, "cPos");
int cRot = GlStateManager.getUniformLocation(shader, "cRot");
FloatBuffer buf = ShaderHelper.VEC3_BUFFER; FloatBuffer buf = ShaderHelper.VEC3_BUFFER;
buf.put(0, (float) c.bounds.getXSize()); int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize");
buf.put(1, (float) c.bounds.getYSize()); buf.put(0, (float) lighter.getSizeX());
buf.put(2, (float) c.bounds.getZSize()); buf.put(1, (float) lighter.getSizeY());
buf.put(2, (float) lighter.getSizeZ());
buf.rewind(); buf.rewind();
GlStateManager.uniform3(cSize, buf); GlStateManager.uniform3(lightBoxSize, buf);
int lightBoxMin = GlStateManager.getUniformLocation(shader, "lightBoxMin");
buf.put(0, (float) lighter.getMinX());
buf.put(1, (float) lighter.getMinY());
buf.put(2, (float) lighter.getMinZ());
buf.rewind();
GlStateManager.uniform3(lightBoxMin, buf);
int cPos = GlStateManager.getUniformLocation(shader, "cPos");
buf.put(0, (float) renderPos.x); buf.put(0, (float) renderPos.x);
buf.put(1, (float) renderPos.y); buf.put(1, (float) renderPos.y);
buf.put(2, (float) renderPos.z); buf.put(2, (float) renderPos.z);
buf.rewind(); buf.rewind();
GlStateManager.uniform3(cPos, buf); GlStateManager.uniform3(cPos, buf);
int cRot = GlStateManager.getUniformLocation(shader, "cRot");
buf.put(0, (float) renderRot.x); buf.put(0, (float) renderRot.x);
buf.put(1, (float) renderRot.y); buf.put(1, (float) renderRot.y);
buf.put(2, (float) renderRot.z); buf.put(2, (float) renderRot.z);
@ -79,6 +96,8 @@ public class FastContraptionRenderer extends ContraptionRenderer {
for (ContraptionBuffer layer : renderLayers) { for (ContraptionBuffer layer : renderLayers) {
layer.render(); layer.render();
} }
lighter.release();
} }
private void buildLayers() { private void buildLayers() {
@ -86,8 +105,7 @@ public class FastContraptionRenderer extends ContraptionRenderer {
List<RenderType> blockLayers = RenderType.getBlockLayers(); List<RenderType> blockLayers = RenderType.getBlockLayers();
for (int i = 0; i < blockLayers.size(); i++) { for (RenderType layer : blockLayers) {
RenderType layer = blockLayers.get(i);
renderLayers.add(buildStructureBuffer(c, layer)); renderLayers.add(buildStructureBuffer(c, layer));
} }
} }
@ -96,6 +114,7 @@ public class FastContraptionRenderer extends ContraptionRenderer {
for (ContraptionBuffer buffer : renderLayers) { for (ContraptionBuffer buffer : renderLayers) {
buffer.invalidate(); buffer.invalidate();
} }
lighter.delete();
renderLayers.clear(); renderLayers.clear();
} }
@ -105,12 +124,16 @@ public class FastContraptionRenderer extends ContraptionRenderer {
} }
private static FastContraptionRenderer getRenderer(World world, Contraption c) { private static FastContraptionRenderer getRenderer(World world, Contraption c) {
try { FastContraptionRenderer renderer;
return renderers.get(c.entity.getEntityId(), () -> new FastContraptionRenderer(world, c)); int entityId = c.entity.getEntityId();
} catch (ExecutionException e) { if (renderers.containsKey(entityId)) {
e.printStackTrace(); renderer = renderers.get(entityId);
return null; } else {
renderer = new FastContraptionRenderer(world, c);
renderers.put(entityId, renderer);
} }
return renderer;
} }
public static void renderAll(RenderWorldLastEvent event) { public static void renderAll(RenderWorldLastEvent event) {
@ -123,7 +146,7 @@ public class FastContraptionRenderer extends ContraptionRenderer {
ArrayList<Integer> toRemove = new ArrayList<>(); ArrayList<Integer> toRemove = new ArrayList<>();
for (FastContraptionRenderer renderer : renderers.asMap().values()) { for (FastContraptionRenderer renderer : renderers.values()) {
if (renderer.c.entity.isAlive()) if (renderer.c.entity.isAlive())
renderer.render(shader); renderer.render(shader);
else else
@ -134,15 +157,17 @@ public class FastContraptionRenderer extends ContraptionRenderer {
CreateClient.kineticRenderer.teardown(); CreateClient.kineticRenderer.teardown();
renderers.invalidateAll(toRemove); for (Integer id : toRemove) {
renderers.remove(id);
}
} }
public static void invalidateAll() { public static void invalidateAll() {
for (FastContraptionRenderer renderer : renderers.asMap().values()) { for (FastContraptionRenderer renderer : renderers.values()) {
renderer.invalidate(); renderer.invalidate();
} }
renderers.invalidateAll(); renderers.clear();
} }
private static ContraptionBuffer buildStructureBuffer(Contraption c, RenderType layer) { private static ContraptionBuffer buildStructureBuffer(Contraption c, RenderType layer) {

View file

@ -124,7 +124,7 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
GL30.glBindVertexArray(vao); GL30.glBindVertexArray(vao);
finishBuffering(); finishBuffering();
int numAttributes = getInstanceFormat().getNumAttributes() + 3; int numAttributes = getInstanceFormat().getNumAttributes() + FORMAT.getNumAttributes();
for (int i = 0; i <= numAttributes; i++) { for (int i = 0; i <= numAttributes; i++) {
GL40.glEnableVertexAttribArray(i); GL40.glEnableVertexAttribArray(i);
} }

View file

@ -3,7 +3,7 @@ package com.simibubi.create.foundation.utility.render.shader;
public enum Shader { public enum Shader {
ROTATING_INSTANCED("shader/rotating.vert", "shader/instanced.frag"), ROTATING_INSTANCED("shader/rotating.vert", "shader/instanced.frag"),
BELT_INSTANCED("shader/belt.vert", "shader/instanced.frag"), BELT_INSTANCED("shader/belt.vert", "shader/instanced.frag"),
CONTRAPTION_STRUCTURE("shader/contraption_static.vert", "shader/instanced.frag"), CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"),
; ;
public final String vert; public final String vert;

View file

@ -15,7 +15,6 @@ layout (location = 9) in float scrollMult;
out vec2 TexCoords; out vec2 TexCoords;
out vec2 Light; out vec2 Light;
out vec4 Color;
out float Diffuse; out float Diffuse;
uniform float time; uniform float time;
@ -54,7 +53,6 @@ void main() {
float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult; float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult;
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz)); Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
Color = vec4(1f);
Light = light; Light = light;
TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll); TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll);
gl_Position = projection * view * renderPos; gl_Position = projection * view * renderPos;

View file

@ -0,0 +1,24 @@
#version 440 core
in vec2 TexCoords;
in vec4 Color;
in float Diffuse;
in vec3 BoxCoord;
out vec4 fragColor;
layout(binding=0) uniform sampler2D BlockAtlas;
layout(binding=1) uniform sampler2D LightMap;
layout(binding=4) uniform sampler3D LightVolume;
vec4 light() {
vec2 lm = texture(LightVolume, BoxCoord).rg * 0.9375 + 0.03125;
return texture2D(LightMap, lm);
}
void main() {
vec4 tex = texture2D(BlockAtlas, TexCoords);
fragColor = vec4(tex.rgb * light().rgb * Diffuse, tex.a);
}

View file

@ -8,12 +8,11 @@ layout (location = 3) in vec4 aColor;
out float Diffuse; out float Diffuse;
out vec2 TexCoords; out vec2 TexCoords;
out vec2 Light;
out vec4 Color; out vec4 Color;
out vec3 BoxCoord;
layout (binding = 2) uniform sampler3D lightVolume; uniform vec3 lightBoxSize;
uniform vec3 lightBoxMin;
uniform vec3 cSize;
uniform vec3 cPos; uniform vec3 cPos;
uniform vec3 cRot; uniform vec3 cRot;
@ -53,13 +52,13 @@ void main() {
vec4 worldPos = rotatedPos + vec4(cPos + vec3(0.5), 0); vec4 worldPos = rotatedPos + vec4(cPos + vec3(0.5), 0);
vec3 boxCoord = (worldPos.xyz - cPos - cSize * 0.5) / cSize; vec3 boxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize;
float df = diffuse(normalize(aNormal)); float df = diffuse(normalize(aNormal));
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz)); Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
Color = vec4(aColor.rgb / df, aColor.a); Color = vec4(aColor.rgb / df, aColor.a);
Light = vec2(1.); BoxCoord = boxCoord;
TexCoords = aTexCoords; TexCoords = aTexCoords;
gl_Position = projection * view * worldPos; gl_Position = projection * view * worldPos;
} }

View file

@ -2,7 +2,6 @@
in vec2 TexCoords; in vec2 TexCoords;
in vec2 Light; in vec2 Light;
in vec4 Color;
in float Diffuse; in float Diffuse;
out vec4 fragColor; out vec4 fragColor;
@ -15,11 +14,8 @@ vec4 light() {
return texture2D(LightMap, lm); return texture2D(LightMap, lm);
} }
void main() { void main() {
vec4 tex = texture2D(BlockAtlas, TexCoords); vec4 tex = texture2D(BlockAtlas, TexCoords);
tex *= vec4(light().rgb * Diffuse, 1); fragColor = vec4(tex.rgb * light().rgb * Diffuse, tex.a);
fragColor = tex;
} }

View file

@ -12,7 +12,6 @@ layout (location = 7) in vec3 rotationAxis;
out vec2 TexCoords; out vec2 TexCoords;
out vec2 Light; out vec2 Light;
out vec4 Color;
out float Diffuse; out float Diffuse;
uniform float time; uniform float time;
@ -48,7 +47,6 @@ void main() {
renderPos += vec4(instancePos + vec3(0.5), 0); renderPos += vec4(instancePos + vec3(0.5), 0);
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz)); Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
Color = vec4(1f);
TexCoords = aTexCoords; TexCoords = aTexCoords;
gl_Position = projection * view * renderPos; gl_Position = projection * view * renderPos;
Light = light; Light = light;