prepare for fast actor rendering

This commit is contained in:
JozsefA 2021-01-21 14:14:20 -08:00
parent 697a7df59c
commit 11f9c7459c
11 changed files with 421 additions and 167 deletions

View file

@ -10,90 +10,39 @@ import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*; import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*;
public class ContraptionBuffer extends TemplateBuffer { public class ContraptionBuffer extends GPUBuffer {
public static final VertexFormat FORMAT = new VertexFormat(InstanceBuffer.FORMAT, RGBA); public static final VertexFormat FORMAT = new VertexFormat(InstanceBuffer.FORMAT, RGBA);
protected int vao, ebo, vbo;
public ContraptionBuffer(BufferBuilder buf) { public ContraptionBuffer(BufferBuilder buf) {
super(buf); super(buf);
if (vertexCount > 0) setup();
} }
public void delete() { @Override
if (vertexCount > 0) { protected void copyVertex(ByteBuffer to, int vertex) {
RenderWork.enqueue(() -> { to.putFloat(getX(template, vertex));
GL15.glDeleteBuffers(vbo); to.putFloat(getY(template, vertex));
GL15.glDeleteBuffers(ebo); to.putFloat(getZ(template, vertex));
GL30.glDeleteVertexArrays(vao);
}); to.put(getNX(template, vertex));
} to.put(getNY(template, vertex));
to.put(getNZ(template, vertex));
to.putFloat(getU(template, vertex));
to.putFloat(getV(template, vertex));
to.put(getR(template, vertex));
to.put(getG(template, vertex));
to.put(getB(template, vertex));
to.put(getA(template, vertex));
} }
public void render() { @Override
if (vertexCount == 0) return; protected VertexFormat getModelFormat() {
GL30.glBindVertexArray(vao); return FORMAT;
}
for (int i = 0; i <= 3; i++) {
GL40.glEnableVertexAttribArray(i);
}
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
@Override
protected void drawCall() {
GL40.glDrawElements(GL11.GL_QUADS, vertexCount, GL11.GL_UNSIGNED_SHORT, 0); GL40.glDrawElements(GL11.GL_QUADS, vertexCount, GL11.GL_UNSIGNED_SHORT, 0);
for (int i = 0; i <= FORMAT.getNumAttributes(); i++) {
GL40.glDisableVertexAttribArray(i);
}
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
}
private void setup() {
int stride = FORMAT.getStride();
int invariantSize = vertexCount * stride;
vao = GL30.glGenVertexArrays();
ebo = GlStateManager.genBuffers();
vbo = GlStateManager.genBuffers();
GL30.glBindVertexArray(vao);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
// allocate the buffer on the gpu
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW);
// mirror it in system memory so we can write to it
ByteBuffer constant = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
for (int i = 0; i < vertexCount; i++) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
constant.put(getNX(template, i));
constant.put(getNY(template, i));
constant.put(getNZ(template, i));
constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i));
constant.put(getR(template, i));
constant.put(getG(template, i));
constant.put(getB(template, i));
constant.put(getA(template, i));
}
constant.rewind();
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
buildEBO(ebo);
FORMAT.informAttributes(0);
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
// Deselect (bind to 0) the VAO
GL30.glBindVertexArray(0);
} }
} }

View file

@ -0,0 +1,107 @@
package com.simibubi.create.foundation.render;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.foundation.render.instancing.VertexFormat;
import net.minecraft.client.renderer.BufferBuilder;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL40;
import java.nio.ByteBuffer;
public abstract class GPUBuffer extends TemplateBuffer {
protected int vao, ebo, invariantVBO;
public GPUBuffer(BufferBuilder buf) {
super(buf);
if (vertexCount > 0) setup();
}
protected void setup() {
int stride = getModelFormat().getStride();
int invariantSize = vertexCount * stride;
vao = GL30.glGenVertexArrays();
ebo = GlStateManager.genBuffers();
invariantVBO = GlStateManager.genBuffers();
GL30.glBindVertexArray(vao);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, invariantVBO);
// allocate the buffer on the gpu
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW);
// mirror it in system memory so we can write to it
ByteBuffer constant = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
for (int i = 0; i < vertexCount; i++) {
copyVertex(constant, i);
}
constant.rewind();
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
buildEBO(ebo);
getModelFormat().informAttributes(0);
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
// Deselect (bind to 0) the VAO
GL30.glBindVertexArray(0);
}
protected abstract void copyVertex(ByteBuffer to, int index);
protected abstract VertexFormat getModelFormat();
protected int getTotalShaderAttributeCount() {
return getModelFormat().getShaderAttributeCount();
}
protected abstract void drawCall();
protected void preDrawTask() {
}
public void render() {
if (vao == 0) return;
GL30.glBindVertexArray(vao);
preDrawTask();
int numAttributes = getTotalShaderAttributeCount();
for (int i = 0; i <= numAttributes; i++) {
GL40.glEnableVertexAttribArray(i);
}
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
drawCall();
for (int i = 0; i <= numAttributes; i++) {
GL40.glDisableVertexAttribArray(i);
}
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
}
public void delete() {
if (vertexCount > 0) {
RenderWork.enqueue(this::deleteInternal);
}
}
protected void deleteInternal() {
GL15.glDeleteBuffers(invariantVBO);
GL15.glDeleteBuffers(ebo);
GL30.glDeleteVertexArrays(vao);
vao = 0;
ebo = 0;
invariantVBO = 0;
}
}

View file

@ -0,0 +1,30 @@
package com.simibubi.create.foundation.render.instancing;
import net.minecraft.client.renderer.BufferBuilder;
import org.lwjgl.opengl.*;
public abstract class DynamicInstanceBuffer<S extends InstanceData, D extends InstanceData> extends InstanceBuffer<S> {
protected int dynamicVBO;
protected int dynamicBufferSize = -1;
public DynamicInstanceBuffer(BufferBuilder buf) {
super(buf);
}
@Override
protected void setup() {
super.setup();
dynamicVBO = GL20.glGenBuffers();
}
protected abstract VertexFormat getDynamicFormat();
protected abstract D newDynamicPart();
@Override
protected int getTotalShaderAttributeCount() {
return super.getTotalShaderAttributeCount() + getDynamicFormat().getShaderAttributeCount();
}
}

View file

@ -2,6 +2,7 @@ package com.simibubi.create.foundation.render.instancing;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.foundation.render.GPUBuffer;
import com.simibubi.create.foundation.render.RenderMath; import com.simibubi.create.foundation.render.RenderMath;
import com.simibubi.create.foundation.render.RenderWork; import com.simibubi.create.foundation.render.RenderWork;
import com.simibubi.create.foundation.render.TemplateBuffer; import com.simibubi.create.foundation.render.TemplateBuffer;
@ -14,12 +15,13 @@ import java.util.function.Consumer;
import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*; import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*;
public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuffer { public abstract class InstanceBuffer<D extends InstanceData> extends GPUBuffer {
public static final VertexFormat FORMAT = new VertexFormat(POSITION, NORMAL, UV); public static final VertexFormat FORMAT = new VertexFormat(POSITION, NORMAL, UV);
protected int vao, ebo, invariantVBO, instanceVBO, instanceCount; protected int instanceVBO;
protected int instanceCount;
protected int bufferSize = -1; protected int instanceBufferSize = -1;
protected final ArrayList<D> data = new ArrayList<>(); protected final ArrayList<D> data = new ArrayList<>();
protected boolean rebuffer = false; protected boolean rebuffer = false;
@ -27,51 +29,31 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
public InstanceBuffer(BufferBuilder buf) { public InstanceBuffer(BufferBuilder buf) {
super(buf); super(buf);
if (vertexCount > 0) setup();
} }
private void setup() { @Override
int stride = FORMAT.getStride(); protected void setup() {
super.setup();
int invariantSize = vertexCount * stride;
vao = GL30.glGenVertexArrays();
ebo = GlStateManager.genBuffers();
invariantVBO = GlStateManager.genBuffers();
instanceVBO = GlStateManager.genBuffers(); instanceVBO = GlStateManager.genBuffers();
}
GL30.glBindVertexArray(vao); @Override
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, invariantVBO); protected VertexFormat getModelFormat() {
return FORMAT;
}
// allocate the buffer on the gpu @Override
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW); protected void copyVertex(ByteBuffer constant, int i) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
// mirror it in system memory so we can write to it constant.put(getNX(template, i));
ByteBuffer constant = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY); constant.put(getNY(template, i));
constant.put(getNZ(template, i));
for (int i = 0; i < vertexCount; i++) { constant.putFloat(getU(template, i));
constant.putFloat(getX(template, i)); constant.putFloat(getV(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));
constant.put(getNX(template, i));
constant.put(getNY(template, i));
constant.put(getNZ(template, i));
constant.putFloat(getU(template, i));
constant.putFloat(getV(template, i));
}
constant.rewind();
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
buildEBO(ebo);
FORMAT.informAttributes(0);
GlStateManager.bindBuffers(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
// Deselect (bind to 0) the VAO
GL30.glBindVertexArray(0);
} }
protected abstract VertexFormat getInstanceFormat(); protected abstract VertexFormat getInstanceFormat();
@ -93,20 +75,16 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
if (shouldBuild) rebuffer = true; if (shouldBuild) rebuffer = true;
} }
public void delete() { protected void deleteInternal() {
if (vertexCount > 0) { GL15.glDeleteBuffers(invariantVBO);
RenderWork.enqueue(() -> { GL15.glDeleteBuffers(instanceVBO);
GL15.glDeleteBuffers(invariantVBO); GL15.glDeleteBuffers(ebo);
GL15.glDeleteBuffers(instanceVBO); GL30.glDeleteVertexArrays(vao);
GL15.glDeleteBuffers(ebo); vao = 0;
GL30.glDeleteVertexArrays(vao); ebo = 0;
vao = 0; invariantVBO = 0;
ebo = 0; instanceVBO = 0;
invariantVBO = 0; instanceBufferSize = -1;
instanceVBO = 0;
bufferSize = -1;
});
}
} }
protected abstract D newInstance(); protected abstract D newInstance();
@ -120,30 +98,16 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
data.add(instanceData); data.add(instanceData);
} }
public void render() { protected int getTotalShaderAttributeCount() {
if (vao == 0) return; return getInstanceFormat().getShaderAttributeCount() + FORMAT.getShaderAttributeCount();
GL30.glBindVertexArray(vao);
finishBuffering();
int numAttributes = getInstanceFormat().getNumAttributes() + FORMAT.getNumAttributes();
for (int i = 0; i <= numAttributes; i++) {
GL40.glEnableVertexAttribArray(i);
}
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL40.glDrawElementsInstanced(GL11.GL_QUADS, vertexCount, GL11.GL_UNSIGNED_SHORT, 0, instanceCount);
for (int i = 0; i <= numAttributes; i++) {
GL40.glDisableVertexAttribArray(i);
}
GlStateManager.bindBuffers(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
} }
private void finishBuffering() { @Override
protected void drawCall() {
GL40.glDrawElementsInstanced(GL11.GL_QUADS, vertexCount, GL11.GL_UNSIGNED_SHORT, 0, instanceCount);
}
protected void preDrawTask() {
if (!rebuffer || data.isEmpty()) return; if (!rebuffer || data.isEmpty()) return;
instanceCount = data.size(); instanceCount = data.size();
@ -155,9 +119,9 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceVBO); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceVBO);
// this changes enough that it's not worth reallocating the entire buffer every time. // this changes enough that it's not worth reallocating the entire buffer every time.
if (instanceSize > bufferSize) { if (instanceSize > instanceBufferSize) {
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, instanceSize, GL15.GL_STATIC_DRAW); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, instanceSize, GL15.GL_STATIC_DRAW);
bufferSize = instanceSize; instanceBufferSize = instanceSize;
} }
ByteBuffer buffer = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY); ByteBuffer buffer = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
@ -166,10 +130,10 @@ public abstract class InstanceBuffer<D extends InstanceData> extends TemplateBuf
buffer.rewind(); buffer.rewind();
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER); GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
int staticAttributes = FORMAT.getNumAttributes(); int staticAttributes = FORMAT.getShaderAttributeCount();
instanceFormat.informAttributes(staticAttributes); instanceFormat.informAttributes(staticAttributes);
for (int i = 0; i < instanceFormat.getNumAttributes(); i++) { for (int i = 0; i < instanceFormat.getShaderAttributeCount(); i++) {
GL33.glVertexAttribDivisor(i + staticAttributes, 1); GL33.glVertexAttribDivisor(i + staticAttributes, 1);
} }

View file

@ -7,13 +7,13 @@ import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*; import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*;
public class RotatingData extends BasicData<RotatingData> { public class RotatingData extends BasicData<RotatingData> {
public static VertexFormat FORMAT = new VertexFormat(BasicData.FORMAT, FLOAT, FLOAT, VEC3); public static VertexFormat FORMAT = new VertexFormat(BasicData.FORMAT, FLOAT, FLOAT, NORMAL);
private float rotationalSpeed; private float rotationalSpeed;
private float rotationOffset; private float rotationOffset;
private float rotationAxisX; private byte rotationAxisX;
private float rotationAxisY; private byte rotationAxisY;
private float rotationAxisZ; private byte rotationAxisZ;
public RotatingData setRotationalSpeed(float rotationalSpeed) { public RotatingData setRotationalSpeed(float rotationalSpeed) {
this.rotationalSpeed = rotationalSpeed; this.rotationalSpeed = rotationalSpeed;
@ -26,16 +26,14 @@ public class RotatingData extends BasicData<RotatingData> {
} }
public RotatingData setRotationAxis(Vector3f axis) { public RotatingData setRotationAxis(Vector3f axis) {
this.rotationAxisX = axis.getX(); setRotationAxis(axis.getX(), axis.getY(), axis.getZ());
this.rotationAxisY = axis.getY();
this.rotationAxisZ = axis.getZ();
return this; return this;
} }
public RotatingData setRotationAxis(float rotationAxisX, float rotationAxisY, float rotationAxisZ) { public RotatingData setRotationAxis(float rotationAxisX, float rotationAxisY, float rotationAxisZ) {
this.rotationAxisX = rotationAxisX; this.rotationAxisX = (byte) (rotationAxisX * 127);
this.rotationAxisY = rotationAxisY; this.rotationAxisY = (byte) (rotationAxisY * 127);
this.rotationAxisZ = rotationAxisZ; this.rotationAxisZ = (byte) (rotationAxisZ * 127);
return this; return this;
} }

View file

@ -34,7 +34,7 @@ public class VertexFormat {
this.stride = stride; this.stride = stride;
} }
public int getNumAttributes() { public int getShaderAttributeCount() {
return numAttributes; return numAttributes;
} }

View file

@ -0,0 +1,35 @@
package com.simibubi.create.foundation.render.instancing.actors;
import com.simibubi.create.foundation.render.instancing.InstanceData;
import com.simibubi.create.foundation.render.instancing.VertexFormat;
import net.minecraft.client.renderer.Vector3f;
import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*;
import static com.simibubi.create.foundation.render.instancing.VertexAttribute.NORMAL;
public class DynamicRotatingActorData extends InstanceData {
public static VertexFormat FORMAT = new VertexFormat(NORMAL);
private byte relativeMotionX;
private byte relativeMotionY;
private byte relativeMotionZ;
public DynamicRotatingActorData setRelativeMotion(Vector3f axis) {
setRelativeMotion(axis.getX(), axis.getY(), axis.getZ());
return this;
}
public DynamicRotatingActorData setRelativeMotion(float relativeMotionX, float relativeMotionY, float relativeMotionZ) {
this.relativeMotionX = (byte) (relativeMotionX * 127);
this.relativeMotionY = (byte) (relativeMotionY * 127);
this.relativeMotionZ = (byte) (relativeMotionZ * 127);
return this;
}
@Override
public void write(ByteBuffer buf) {
putVec3(buf, relativeMotionX, relativeMotionY, relativeMotionZ);
}
}

View file

@ -0,0 +1,31 @@
package com.simibubi.create.foundation.render.instancing.actors;
import com.simibubi.create.foundation.render.instancing.DynamicInstanceBuffer;
import com.simibubi.create.foundation.render.instancing.VertexFormat;
import net.minecraft.client.renderer.BufferBuilder;
public class RotatingActorBuffer extends DynamicInstanceBuffer<StaticRotatingActorData, DynamicRotatingActorData> {
public RotatingActorBuffer(BufferBuilder buf) {
super(buf);
}
@Override
protected VertexFormat getDynamicFormat() {
return DynamicRotatingActorData.FORMAT;
}
@Override
protected DynamicRotatingActorData newDynamicPart() {
return new DynamicRotatingActorData();
}
@Override
protected VertexFormat getInstanceFormat() {
return StaticRotatingActorData.FORMAT;
}
@Override
protected StaticRotatingActorData newInstance() {
return new StaticRotatingActorData();
}
}

View file

@ -0,0 +1,71 @@
package com.simibubi.create.foundation.render.instancing.actors;
import com.simibubi.create.foundation.render.instancing.InstanceData;
import com.simibubi.create.foundation.render.instancing.RotatingData;
import com.simibubi.create.foundation.render.instancing.VertexFormat;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.util.math.BlockPos;
import java.nio.ByteBuffer;
import static com.simibubi.create.foundation.render.instancing.VertexAttribute.*;
public class StaticRotatingActorData extends InstanceData {
public static VertexFormat FORMAT = new VertexFormat(POSITION, FLOAT, NORMAL, NORMAL);
private float x;
private float y;
private float z;
private float rotationOffset;
private byte rotationAxisX;
private byte rotationAxisY;
private byte rotationAxisZ;
private byte localOrientationX;
private byte localOrientationY;
private byte localOrientationZ;
public StaticRotatingActorData setPosition(BlockPos pos) {
this.x = pos.getX();
this.y = pos.getY();
this.z = pos.getZ();
return this;
}
public StaticRotatingActorData setRotationOffset(float rotationOffset) {
this.rotationOffset = rotationOffset;
return this;
}
public StaticRotatingActorData setRotationAxis(Vector3f axis) {
setRotationAxis(axis.getX(), axis.getY(), axis.getZ());
return this;
}
public StaticRotatingActorData setRotationAxis(float rotationAxisX, float rotationAxisY, float rotationAxisZ) {
this.rotationAxisX = (byte) (rotationAxisX * 127);
this.rotationAxisY = (byte) (rotationAxisY * 127);
this.rotationAxisZ = (byte) (rotationAxisZ * 127);
return this;
}
public StaticRotatingActorData setLocalOrientation(Vector3f axis) {
setRotationAxis(axis.getX(), axis.getY(), axis.getZ());
return this;
}
public StaticRotatingActorData setLocalOrientation(float localOrientationX, float localOrientationY, float localOrientationZ) {
this.localOrientationX = (byte) (localOrientationX * 127);
this.localOrientationY = (byte) (localOrientationY * 127);
this.localOrientationZ = (byte) (localOrientationZ * 127);
return this;
}
@Override
public void write(ByteBuffer buf) {
putVec3(buf, x, y, z);
put(buf, rotationOffset);
putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ);
putVec3(buf, localOrientationX, localOrientationY, localOrientationZ);
}
}

View file

@ -6,6 +6,7 @@ public enum Shader {
CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"), CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"),
CONTRAPTION_ROTATING("shader/contraption_rotating.vert", "shader/contraption.frag"), CONTRAPTION_ROTATING("shader/contraption_rotating.vert", "shader/contraption.frag"),
CONTRAPTION_BELT("shader/contraption_belt.vert", "shader/contraption.frag"), CONTRAPTION_BELT("shader/contraption_belt.vert", "shader/contraption.frag"),
//CONTRAPTION_ACTOR("shader/contraption_actor.vert", "shader/contraption.frag"),
; ;
public final String vert; public final String vert;

View file

@ -0,0 +1,68 @@
#version 330 core
#define PI 3.1415926538
// model data
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
// instance data
layout (location = 3) in vec3 instancePos;
layout (location = 4) in float rotationOffset;
layout (location = 5) in vec3 localRotationAxis;
layout (location = 6) in vec3 localOrientation;
// dynamic data
layout (location = 7) in vec3 relativeMotion;
out float Diffuse;
out vec2 TexCoords;
out vec4 Color;
out vec3 BoxCoord;
uniform vec3 lightBoxSize;
uniform vec3 lightBoxMin;
uniform mat4 model;
uniform float time;
uniform int ticks;
uniform mat4 projection;
uniform mat4 view;
uniform int debug;
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.,
0., 0., 0., 1.);
}
mat4 kineticRotation() {
float degrees = rotationOffset + time * speed * -3./10.;
float angle = fract(degrees / 360.) * PI * 2.;
return rotate(normalize(localRotationAxis), angle);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f);
}
void main() {
mat4 kineticRotation = kineticRotation();
vec4 localPos = kineticRotation * vec4(aPos - 0.5, 1f) + vec4(instancePos + 0.5, 0);
vec4 worldPos = model * localPos;
BoxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize;
Diffuse = diffuse(normalize(model * kineticRotation * vec4(aNormal, 0.)).xyz);
Color = vec4(1.);
TexCoords = aTexCoords;
gl_Position = projection * view * worldPos;
}