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;
CreateClient.kineticRenderer.tick();
FastContraptionRenderer.tick();
CreateClient.schematicSender.tick();
CreateClient.schematicAndQuillHandler.tick();

View file

@ -1,15 +1,16 @@
package com.simibubi.create.foundation.utility.render;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.util.math.AxisAlignedBB;
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.World;
import net.minecraft.world.lighting.WorldLightManager;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
@ -27,6 +28,8 @@ public class ContraptionLighter {
ByteBuffer lightVolume;
boolean dirty;
int texture;
public ContraptionLighter(Contraption contraption) {
@ -34,53 +37,114 @@ public class ContraptionLighter {
AxisAlignedBB bounds = contraption.bounds;
int minX = (int) Math.floor(bounds.minX);
int minY = (int) Math.floor(bounds.minY);
int minZ = (int) Math.floor(bounds.minZ);
int maxX = (int) Math.ceil(bounds.maxX);
int maxY = (int) Math.ceil(bounds.maxY);
int maxZ = (int) Math.ceil(bounds.maxZ);
int minX = (int) Math.floor(bounds.minX) - 1;
int minY = (int) Math.floor(bounds.minY) - 1;
int minZ = (int) Math.floor(bounds.minZ) - 1;
int maxX = (int) Math.ceil(bounds.maxX) + 1;
int maxY = (int) Math.ceil(bounds.maxY) + 1;
int maxZ = (int) Math.ceil(bounds.maxZ) + 1;
sizeX = maxX - minX;
sizeY = maxY - minY;
sizeZ = maxZ - minZ;
sizeX = nextPowerOf2(maxX - minX);
sizeY = nextPowerOf2(maxY - minY);
sizeZ = nextPowerOf2(maxZ - minZ);
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() {
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;
int contraptionY = pos.getY() - minY;
int contraptionZ = pos.getZ() - minZ;
World world = c.entity.world;
if (contraptionX < 0 || contraptionX >= sizeX || contraptionY < 0 || contraptionY >= sizeY || contraptionZ < 0 || contraptionZ >= sizeZ)
return;
BlockPos.Mutable pos = new BlockPos.Mutable();
int blockLight = world.getLightLevel(LightType.BLOCK, pos);
int skyLight = world.getLightLevel(LightType.SKY, pos);
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);
writeLight(contraptionX, contraptionY, contraptionZ, blockLight, skyLight);
int blockLight = world.getLightLevel(LightType.BLOCK, pos);
int skyLight = world.getLightLevel(LightType.SKY, pos);
writeLight(x, y, z, blockLight, skyLight);
}
}
}
dirty = true;
}
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));
lightVolume.put(i + 1, (byte) (sky * 16));
byte b = (byte) ((block & 0xF) << 4);
byte s = (byte) ((sky & 0xF) << 4);
lightVolume.put(i, b);
lightVolume.put(i + 1, s);
}
public void use() {
GL13.glEnable(GL31.GL_TEXTURE_3D);
GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4);
GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture);
lightVolume.rewind();
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume);
if (dirty) {
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.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL40;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
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<>();
@ -43,33 +45,48 @@ public class FastContraptionRenderer extends ContraptionRenderer {
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) {
renderPos = position;
renderRot = rotation;
}
private void render(int shader) {
// GL13.glActiveTexture(GL40.GL_TEXTURE2);
// lighter.use();
int cSize = GlStateManager.getUniformLocation(shader, "cSize");
int cPos = GlStateManager.getUniformLocation(shader, "cPos");
int cRot = GlStateManager.getUniformLocation(shader, "cRot");
lighter.use();
FloatBuffer buf = ShaderHelper.VEC3_BUFFER;
buf.put(0, (float) c.bounds.getXSize());
buf.put(1, (float) c.bounds.getYSize());
buf.put(2, (float) c.bounds.getZSize());
int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize");
buf.put(0, (float) lighter.getSizeX());
buf.put(1, (float) lighter.getSizeY());
buf.put(2, (float) lighter.getSizeZ());
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(1, (float) renderPos.y);
buf.put(2, (float) renderPos.z);
buf.rewind();
GlStateManager.uniform3(cPos, buf);
int cRot = GlStateManager.getUniformLocation(shader, "cRot");
buf.put(0, (float) renderRot.x);
buf.put(1, (float) renderRot.y);
buf.put(2, (float) renderRot.z);
@ -79,6 +96,8 @@ public class FastContraptionRenderer extends ContraptionRenderer {
for (ContraptionBuffer layer : renderLayers) {
layer.render();
}
lighter.release();
}
private void buildLayers() {
@ -86,8 +105,7 @@ public class FastContraptionRenderer extends ContraptionRenderer {
List<RenderType> blockLayers = RenderType.getBlockLayers();
for (int i = 0; i < blockLayers.size(); i++) {
RenderType layer = blockLayers.get(i);
for (RenderType layer : blockLayers) {
renderLayers.add(buildStructureBuffer(c, layer));
}
}
@ -96,6 +114,7 @@ public class FastContraptionRenderer extends ContraptionRenderer {
for (ContraptionBuffer buffer : renderLayers) {
buffer.invalidate();
}
lighter.delete();
renderLayers.clear();
}
@ -105,12 +124,16 @@ public class FastContraptionRenderer extends ContraptionRenderer {
}
private static FastContraptionRenderer getRenderer(World world, Contraption c) {
try {
return renderers.get(c.entity.getEntityId(), () -> new FastContraptionRenderer(world, c));
} catch (ExecutionException e) {
e.printStackTrace();
return null;
FastContraptionRenderer renderer;
int entityId = c.entity.getEntityId();
if (renderers.containsKey(entityId)) {
renderer = renderers.get(entityId);
} else {
renderer = new FastContraptionRenderer(world, c);
renderers.put(entityId, renderer);
}
return renderer;
}
public static void renderAll(RenderWorldLastEvent event) {
@ -123,7 +146,7 @@ public class FastContraptionRenderer extends ContraptionRenderer {
ArrayList<Integer> toRemove = new ArrayList<>();
for (FastContraptionRenderer renderer : renderers.asMap().values()) {
for (FastContraptionRenderer renderer : renderers.values()) {
if (renderer.c.entity.isAlive())
renderer.render(shader);
else
@ -134,15 +157,17 @@ public class FastContraptionRenderer extends ContraptionRenderer {
CreateClient.kineticRenderer.teardown();
renderers.invalidateAll(toRemove);
for (Integer id : toRemove) {
renderers.remove(id);
}
}
public static void invalidateAll() {
for (FastContraptionRenderer renderer : renderers.asMap().values()) {
for (FastContraptionRenderer renderer : renderers.values()) {
renderer.invalidate();
}
renderers.invalidateAll();
renderers.clear();
}
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);
finishBuffering();
int numAttributes = getInstanceFormat().getNumAttributes() + 3;
int numAttributes = getInstanceFormat().getNumAttributes() + FORMAT.getNumAttributes();
for (int i = 0; i <= numAttributes; i++) {
GL40.glEnableVertexAttribArray(i);
}

View file

@ -3,7 +3,7 @@ package com.simibubi.create.foundation.utility.render.shader;
public enum Shader {
ROTATING_INSTANCED("shader/rotating.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;

View file

@ -15,7 +15,6 @@ layout (location = 9) in float scrollMult;
out vec2 TexCoords;
out vec2 Light;
out vec4 Color;
out float Diffuse;
uniform float time;
@ -54,7 +53,6 @@ void main() {
float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult;
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
Color = vec4(1f);
Light = light;
TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll);
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 vec2 TexCoords;
out vec2 Light;
out vec4 Color;
out vec3 BoxCoord;
layout (binding = 2) uniform sampler3D lightVolume;
uniform vec3 cSize;
uniform vec3 lightBoxSize;
uniform vec3 lightBoxMin;
uniform vec3 cPos;
uniform vec3 cRot;
@ -53,13 +52,13 @@ void main() {
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));
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
Color = vec4(aColor.rgb / df, aColor.a);
Light = vec2(1.);
BoxCoord = boxCoord;
TexCoords = aTexCoords;
gl_Position = projection * view * worldPos;
}

View file

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

View file

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