diff --git a/src/main/java/ru/windcorp/optica/client/ClientProxy.java b/src/main/java/ru/windcorp/optica/client/ClientProxy.java
index c0f1bcf..4df867b 100644
--- a/src/main/java/ru/windcorp/optica/client/ClientProxy.java
+++ b/src/main/java/ru/windcorp/optica/client/ClientProxy.java
@@ -21,8 +21,8 @@ import ru.windcorp.optica.Proxy;
import ru.windcorp.optica.client.graphics.GUI;
import ru.windcorp.optica.client.graphics.backend.GraphicsBackend;
import ru.windcorp.optica.client.graphics.backend.RenderTaskQueue;
-import ru.windcorp.optica.client.graphics.model.ShapeRenderProgram;
import ru.windcorp.optica.client.graphics.world.LayerWorld;
+import ru.windcorp.optica.client.graphics.world.WorldRenderProgram;
public class ClientProxy implements Proxy {
@@ -30,7 +30,7 @@ public class ClientProxy implements Proxy {
public void initialize() {
GraphicsBackend.initialize();
try {
- RenderTaskQueue.waitAndInvoke(ShapeRenderProgram::init);
+ RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/EmptyModel.java b/src/main/java/ru/windcorp/optica/client/graphics/model/EmptyModel.java
index 0fda90c..8e22707 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/EmptyModel.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/EmptyModel.java
@@ -18,7 +18,6 @@
package ru.windcorp.optica.client.graphics.model;
import glm.mat._4.Mat4;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
public class EmptyModel extends Model {
@@ -33,7 +32,7 @@ public class EmptyModel extends Model {
}
@Override
- public void render(WorldRenderer renderer) {
+ public void render(ShapeRenderHelper helper) {
// Do nothing
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/Face.java b/src/main/java/ru/windcorp/optica/client/graphics/model/Face.java
index ec90680..353eb75 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/Face.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/Face.java
@@ -21,7 +21,6 @@ import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.util.Objects;
-import glm.vec._3.Vec3;
import ru.windcorp.optica.client.graphics.texture.Texture;
public class Face {
@@ -63,39 +62,6 @@ public class Face {
checkVertices();
checkIndices();
}
-
- void computeNormals() {
- Vec3 a = new Vec3();
- Vec3 b = new Vec3();
- Vec3 c = new Vec3();
- Vec3 normal = new Vec3();
-
- for (int i = 0; i < getIndexCount(); i += 3) {
- int indexA = getIndex(i + 0);
- int indexB = getIndex(i + 1);
- int indexC = getIndex(i + 2);
-
- loadVertexPosition(indexA, a);
- loadVertexPosition(indexB, b);
- loadVertexPosition(indexC, c);
-
- computeOneNormal(a, b, c, normal);
-
- saveVertexNormal(indexA, normal);
- saveVertexNormal(indexB, normal);
- saveVertexNormal(indexC, normal);
- }
- }
-
- private void computeOneNormal(
- Vec3 a, Vec3 b, Vec3 c,
- Vec3 normal
- ) {
- b.sub(a);
- c.sub(a);
- b.cross(c, normal);
- normal.normalize();
- }
private void checkVertices() {
if (vertices.remaining() % getBytesPerVertex() != 0) {
@@ -143,6 +109,12 @@ public class Face {
}
}
+ public void markForVertexUpdate() {
+ if (shape != null) checkVertices();
+ markShapeForReassembly();
+ verticesUpdated = true;
+ }
+
boolean needsVerticesUpdate() {
return verticesUpdated;
}
@@ -180,37 +152,9 @@ public class Face {
return vertices;
}
- private void loadVertexPosition(int index, Vec3 result) {
- int offset = vertices.position() + index * getBytesPerVertex();
-
- result.set(
- vertices.getFloat(offset + 0 * Float.BYTES),
- vertices.getFloat(offset + 1 * Float.BYTES),
- vertices.getFloat(offset + 2 * Float.BYTES)
- );
- }
-
- private void saveVertexNormal(int index, Vec3 normal) {
- int offset = vertices.position() + index * getBytesPerVertex() + (
- 3 * Float.BYTES +
- 3 * Float.BYTES +
- 2 * Float.BYTES
- );
-
- vertices.putFloat(offset + 0 * Float.BYTES, normal.x);
- vertices.putFloat(offset + 1 * Float.BYTES, normal.y);
- vertices.putFloat(offset + 2 * Float.BYTES, normal.z);
-
- verticesUpdated = true;
- }
-
public Face setVertices(ByteBuffer vertices) {
this.vertices = Objects.requireNonNull(vertices, "vertices");
- markShapeForReassembly();
- this.verticesUpdated = true;
-
- if (shape != null) checkVertices();
-
+ markForVertexUpdate();
return this;
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/Faces.java b/src/main/java/ru/windcorp/optica/client/graphics/model/Faces.java
index 6c5d6c9..1d32beb 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/Faces.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/Faces.java
@@ -30,13 +30,14 @@ public class Faces {
private Faces() {}
public static Face createRectangle(
+ ShapeRenderProgram program,
Texture texture,
Vec3 colorMultiplier,
Vec3 origin,
Vec3 width,
Vec3 height
) {
- VertexBuilder builder = new VertexBuilder();
+ VertexBuilder builder = program.getVertexBuilder();
Vec3 pos = new Vec3();
Vec2 texCoords = new Vec2();
@@ -70,6 +71,7 @@ public class Faces {
}
public static Face createBlockFace(
+ ShapeRenderProgram program,
Texture texture,
Vec3 colorMultiplier,
Vec3 blockCenter,
@@ -78,6 +80,7 @@ public class Faces {
switch (face) {
case TOP:
return createRectangle(
+ program,
texture, colorMultiplier,
blockCenter.add(-0.5f, +0.5f, +0.5f),
new Vec3( 0, -1, 0),
@@ -85,6 +88,7 @@ public class Faces {
);
case BOTTOM:
return createRectangle(
+ program,
texture, colorMultiplier,
blockCenter.add(-0.5f, -0.5f, -0.5f),
new Vec3( 0, +1, 0),
@@ -92,6 +96,7 @@ public class Faces {
);
case NORTH:
return createRectangle(
+ program,
texture, colorMultiplier,
blockCenter.add(+0.5f, -0.5f, -0.5f),
new Vec3( 0, +1, 0),
@@ -99,6 +104,7 @@ public class Faces {
);
case SOUTH:
return createRectangle(
+ program,
texture, colorMultiplier,
blockCenter.add(-0.5f, +0.5f, -0.5f),
new Vec3( 0, -1, 0),
@@ -106,6 +112,7 @@ public class Faces {
);
case EAST:
return createRectangle(
+ program,
texture, colorMultiplier,
blockCenter.add(-0.5f, -0.5f, -0.5f),
new Vec3(+1, 0, 0),
@@ -113,6 +120,7 @@ public class Faces {
);
case WEST:
return createRectangle(
+ program,
texture, colorMultiplier,
blockCenter.add(+0.5f, +0.5f, -0.5f),
new Vec3(-1, 0, 0),
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/Model.java b/src/main/java/ru/windcorp/optica/client/graphics/model/Model.java
index b65ed39..c2864c1 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/Model.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/Model.java
@@ -18,7 +18,6 @@
package ru.windcorp.optica.client.graphics.model;
import glm.mat._4.Mat4;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
public abstract class Model implements WorldRenderable {
@@ -31,16 +30,16 @@ public abstract class Model implements WorldRenderable {
protected abstract Mat4 getTransform(int partIndex);
@Override
- public void render(WorldRenderer renderer) {
+ public void render(ShapeRenderHelper helper) {
for (int i = 0; i < parts.length; ++i) {
WorldRenderable part = parts[i];
Mat4 transform = getTransform(i);
try {
- renderer.pushWorldTransform().mul(transform);
- part.render(renderer);
+ helper.pushWorldTransform().mul(transform);
+ part.render(helper);
} finally {
- renderer.popWorldTransform();
+ helper.popWorldTransform();
}
}
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/Shape.java b/src/main/java/ru/windcorp/optica/client/graphics/model/Shape.java
index 05dba75..c733ba7 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/Shape.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/Shape.java
@@ -24,7 +24,6 @@ import org.lwjgl.BufferUtils;
import ru.windcorp.optica.client.graphics.backend.Usage;
import ru.windcorp.optica.client.graphics.backend.VertexBufferObject;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
public class Shape implements WorldRenderable {
@@ -48,18 +47,14 @@ public class Shape implements WorldRenderable {
this.usage = usage;
configureFaces();
+ program.preprocess(this);
assembleBuffers();
}
- public Shape(Usage usage, Face... faces) {
- this(usage, ShapeRenderProgram.getDefault(), faces);
- }
-
private void configureFaces() {
for (Face face : faces) {
face.setShape(this);
- face.computeNormals();
}
}
@@ -153,12 +148,12 @@ public class Shape implements WorldRenderable {
}
@Override
- public void render(WorldRenderer renderer) {
+ public void render(ShapeRenderHelper helper) {
if (!initialized) initialize();
if (needsAssembly) assembleBuffers();
if (needsVBOUpdate) updateVBO();
- program.render(renderer, this);
+ program.render(helper, this);
}
private void initialize() {
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java b/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java
new file mode 100644
index 0000000..f01f716
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderHelper.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Optica
+ * Copyright (C) 2020 Wind Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *******************************************************************************/
+package ru.windcorp.optica.client.graphics.model;
+
+import glm.mat._4.Mat4;
+import ru.windcorp.optica.common.util.StashingStack;
+
+public class ShapeRenderHelper {
+
+ protected static final int TRANSFORM_STACK_SIZE = 64;
+
+ private final StashingStack transformStack = new StashingStack<>(
+ TRANSFORM_STACK_SIZE, Mat4::new
+ );
+
+ {
+ transformStack.push().identity();
+ }
+
+ public Mat4 pushWorldTransform() {
+ Mat4 previous = transformStack.getHead();
+ return transformStack.push().set(previous);
+ }
+
+ public void popWorldTransform() {
+ transformStack.removeHead();
+ }
+
+ public Mat4 getWorldTransform() {
+ return transformStack.getHead();
+ }
+
+ public Mat4 getFinalTransform() {
+ return getWorldTransform();
+ }
+
+ public void reset() {
+ transformStack.removeAll();
+ transformStack.push().identity();
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderProgram.java b/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderProgram.java
index e0560ca..c695f70 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderProgram.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/ShapeRenderProgram.java
@@ -32,33 +32,16 @@ import ru.windcorp.optica.client.graphics.backend.VertexBufferObject;
import ru.windcorp.optica.client.graphics.backend.VertexBufferObject.BindTarget;
import ru.windcorp.optica.client.graphics.backend.shaders.CombinedShader;
import ru.windcorp.optica.client.graphics.backend.shaders.Program;
-import ru.windcorp.optica.client.graphics.backend.shaders.attributes.AttributeVertexArray;
-import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.Uniform1Int;
-import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.Uniform2Float;
-import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.Uniform4Matrix;
+import ru.windcorp.optica.client.graphics.backend.shaders.attributes.*;
+import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.*;
import ru.windcorp.optica.client.graphics.texture.Sprite;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
public class ShapeRenderProgram extends Program {
- private static ShapeRenderProgram def = null;
-
- public static void init() {
- def = new ShapeRenderProgram(
- new String[] {"WorldDefault.vertex.glsl"},
- new String[] {"WorldDefault.fragment.glsl"}
- );
- }
-
- public static ShapeRenderProgram getDefault() {
- return def;
- }
-
private static final int DEFAULT_BYTES_PER_VERTEX =
3 * Float.BYTES + // Position
3 * Float.BYTES + // Color multiplier
- 2 * Float.BYTES + // Texture coordinates
- 3 * Float.BYTES; // Normals
+ 2 * Float.BYTES; // Texture coordinates
private static final String SHAPE_VERTEX_SHADER_RESOURCE =
"Shape.vertex.glsl";
@@ -67,24 +50,20 @@ public class ShapeRenderProgram extends Program {
private static final String
FINAL_TRANSFORM_UNIFORM_NAME = "finalTransform",
- WORLD_TRANSFORM_UNIFORM_NAME = "worldTransform",
POSITIONS_ATTRIBUTE_NAME = "inputPositions",
COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier",
TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords",
TEXTURE_SLOT_UNIFORM_NAME = "textureSlot",
TEXTURE_START_UNIFORM_NAME = "textureStart",
- TEXTURE_SIZE_UNIFORM_NAME = "textureSize",
- NORMALS_ATTRIBUTE_NAME = "inputNormals";
+ TEXTURE_SIZE_UNIFORM_NAME = "textureSize";
private final Uniform4Matrix finalTransformUniform;
- private final Uniform4Matrix worldTransformUniform;
private final AttributeVertexArray positionsAttribute;
private final AttributeVertexArray colorsAttribute;
private final AttributeVertexArray textureCoordsAttribute;
private final Uniform1Int textureSlotUniform;
private final Uniform2Float textureStartUniform;
private final Uniform2Float textureSizeUniform;
- private final AttributeVertexArray normalsAttribute;
public ShapeRenderProgram(
String[] vertexShaderResources,
@@ -102,9 +81,6 @@ public class ShapeRenderProgram extends Program {
this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME)
.as4Matrix();
- this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME)
- .as4Matrix();
-
this.positionsAttribute =
getAttribute(POSITIONS_ATTRIBUTE_NAME).asVertexArray();
@@ -122,9 +98,6 @@ public class ShapeRenderProgram extends Program {
this.textureSizeUniform = getUniform(TEXTURE_SIZE_UNIFORM_NAME)
.as2Float();
-
- this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME)
- .asVertexArray();
}
private static String[] attachVertexShader(String[] others) {
@@ -136,36 +109,39 @@ public class ShapeRenderProgram extends Program {
}
public void render(
- WorldRenderer renderer,
+ ShapeRenderHelper helper,
Shape shape
) {
use();
- configure(renderer);
+ configure(helper);
bindVertices(shape.getVerticesVbo());
bindIndices(shape.getIndicesVbo());
try {
- positionsAttribute.enable();
- colorsAttribute.enable();
- textureCoordsAttribute.enable();
- normalsAttribute.enable();
-
+ enableAttributes();
for (Face face : shape.getFaces()) {
renderFace(face);
}
-
} finally {
- positionsAttribute.disable();
- colorsAttribute.disable();
- textureCoordsAttribute.disable();
- normalsAttribute.disable();
+ disableAttributes();
}
}
- protected void configure(WorldRenderer renderer) {
- finalTransformUniform.set(renderer.getFinalTransform());
- worldTransformUniform.set(renderer.getWorldTransform());
+ protected void enableAttributes() {
+ positionsAttribute.enable();
+ colorsAttribute.enable();
+ textureCoordsAttribute.enable();
+ }
+
+ protected void disableAttributes() {
+ positionsAttribute.disable();
+ colorsAttribute.disable();
+ textureCoordsAttribute.disable();
+ }
+
+ protected void configure(ShapeRenderHelper helper) {
+ finalTransformUniform.set(helper.getFinalTransform());
}
protected int bindVertices(VertexBufferObject vertices) {
@@ -190,12 +166,6 @@ public class ShapeRenderProgram extends Program {
);
offset += 2 * Float.BYTES;
- normalsAttribute.set(
- 3, GL11.GL_FLOAT, false, vertexStride, vertices,
- offset
- );
- offset += 3 * Float.BYTES;
-
return offset;
}
@@ -224,7 +194,31 @@ public class ShapeRenderProgram extends Program {
return DEFAULT_BYTES_PER_VERTEX;
}
- public static class VertexBuilder {
+ public void preprocess(Shape shape) {
+ // To be overridden
+ }
+
+ public VertexBuilder getVertexBuilder() {
+ return new SRPVertexBuilder();
+ }
+
+ public static interface VertexBuilder {
+ VertexBuilder addVertex(
+ float x, float y, float z,
+ float r, float g, float b,
+ float tx, float ty
+ );
+
+ VertexBuilder addVertex(
+ Vec3 position,
+ Vec3 colorMultiplier,
+ Vec2 textureCoords
+ );
+
+ ByteBuffer assemble();
+ }
+
+ public static class SRPVertexBuilder implements VertexBuilder {
private static class Vertex {
final Vec3 position;
@@ -282,10 +276,7 @@ public class ShapeRenderProgram extends Program {
.putFloat(v.colorMultiplier.y)
.putFloat(v.colorMultiplier.z)
.putFloat(v.textureCoords.x)
- .putFloat(v.textureCoords.y)
- .putFloat(Float.NaN)
- .putFloat(Float.NaN)
- .putFloat(Float.NaN);
+ .putFloat(v.textureCoords.y);
}
result.flip();
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/optica/client/graphics/model/Shapes.java
index 54dac98..9da8fbe 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/Shapes.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/Shapes.java
@@ -24,6 +24,8 @@ import ru.windcorp.optica.client.graphics.texture.Texture;
public class Shapes {
public static Shape createParallelepiped( // Try saying that 10 times fast
+ ShapeRenderProgram program,
+
Vec3 origin,
Vec3 width,
@@ -44,6 +46,7 @@ public class Shapes {
Vec3 faceWidth = new Vec3();
Face top = Faces.createRectangle(
+ program,
topTexture, colorMultiplier,
faceOrigin.set(origin).add(height).add(width),
faceWidth.set(width).negate(),
@@ -51,6 +54,7 @@ public class Shapes {
);
Face bottom = Faces.createRectangle(
+ program,
bottomTexture, colorMultiplier,
origin,
width,
@@ -58,6 +62,7 @@ public class Shapes {
);
Face north = Faces.createRectangle(
+ program,
northTexture, colorMultiplier,
faceOrigin.set(origin).add(depth),
width,
@@ -65,6 +70,7 @@ public class Shapes {
);
Face south = Faces.createRectangle(
+ program,
southTexture, colorMultiplier,
faceOrigin.set(origin).add(width),
faceWidth.set(width).negate(),
@@ -72,6 +78,7 @@ public class Shapes {
);
Face east = Faces.createRectangle(
+ program,
eastTexture, colorMultiplier,
origin,
depth,
@@ -79,6 +86,7 @@ public class Shapes {
);
Face west = Faces.createRectangle(
+ program,
westTexture, colorMultiplier,
faceOrigin.set(origin).add(width).add(depth),
faceWidth.set(depth).negate(),
@@ -87,6 +95,7 @@ public class Shapes {
Shape result = new Shape(
Usage.STATIC,
+ program,
top, bottom, north, south, east, west
);
@@ -95,6 +104,8 @@ public class Shapes {
public static class PppBuilder {
+ private final ShapeRenderProgram program;
+
private final Vec3 origin = new Vec3(-0.5f, -0.5f, -0.5f);
private final Vec3 depth = new Vec3(1, 0, 0);
@@ -111,6 +122,7 @@ public class Shapes {
private final Texture westTexture;
public PppBuilder(
+ ShapeRenderProgram program,
Texture top,
Texture bottom,
Texture north,
@@ -118,6 +130,7 @@ public class Shapes {
Texture east,
Texture west
) {
+ this.program = program;
this.topTexture = top;
this.bottomTexture = bottom;
this.northTexture = north;
@@ -126,8 +139,8 @@ public class Shapes {
this.westTexture = west;
}
- public PppBuilder(Texture texture) {
- this(texture, texture, texture, texture, texture, texture);
+ public PppBuilder(ShapeRenderProgram program, Texture texture) {
+ this(program, texture, texture, texture, texture, texture, texture);
}
public PppBuilder setOrigin(Vec3 origin) {
@@ -201,6 +214,7 @@ public class Shapes {
public Shape create() {
return createParallelepiped(
+ program,
origin,
width, height, depth,
colorMultiplier,
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/model/WorldRenderable.java b/src/main/java/ru/windcorp/optica/client/graphics/model/WorldRenderable.java
index e8fbe90..d4333a0 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/model/WorldRenderable.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/model/WorldRenderable.java
@@ -17,10 +17,8 @@
*******************************************************************************/
package ru.windcorp.optica.client.graphics.model;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
-
public interface WorldRenderable {
- void render(WorldRenderer renderer);
+ void render(ShapeRenderHelper renderer);
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java b/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java
index 9ff3b2f..8f28c38 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/texture/Pixels.java
@@ -75,8 +75,6 @@ class Pixels {
data // Data buffer
);
- glBindTexture(GL_TEXTURE_2D, 0);
-
return handle;
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/world/Camera.java b/src/main/java/ru/windcorp/optica/client/graphics/world/Camera.java
index 071575e..5ce57f1 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/world/Camera.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/world/Camera.java
@@ -42,18 +42,18 @@ public class Camera {
public Camera() {}
- public void apply(WorldRenderer renderer) {
- Mat4 previous = renderer.getViewTransform();
+ public void apply(WorldRenderHelper helper) {
+ Mat4 previous = helper.getViewTransform();
Glm.perspective(
computeFovY(),
GraphicsInterface.getAspectRatio(),
0.01f, 10000.0f,
- renderer.pushViewTransform()
+ helper.pushViewTransform()
).mul(previous);
- renderer.pushViewTransform().rotateX(pitch).rotateY(yaw);
+ helper.pushViewTransform().rotateX(pitch).rotateY(yaw);
- renderer.pushViewTransform().translate(position.negate());
+ helper.pushViewTransform().translate(position.negate());
position.negate();
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java
index e086e60..59d5bad 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/world/LayerWorld.java
@@ -50,7 +50,10 @@ public class LayerWorld extends Layer {
private int movementY = 0;
private int movementZ = 0;
- private final WorldRenderer renderer = new WorldRenderer();
+ private static final boolean I_WANT_TO_THROW_UP = false;
+ private float shakeParam = 0;
+
+ private final WorldRenderHelper helper = new WorldRenderHelper();
private final WorldRender world = new WorldRender(new WorldData());
@@ -66,13 +69,14 @@ public class LayerWorld extends Layer {
@Override
protected void doRender() {
- camera.apply(renderer);
+ camera.apply(helper);
renderWorld();
- renderer.reset();
+ helper.reset();
angMat.set().rotateY(-camera.getYaw());
tmp.set(movementX, 0, movementZ);
+ if (movementX != 0 && movementZ != 0) tmp.normalize();
angMat.mul_(tmp); // bug in jglm
tmp.y = movementY;
tmp.mul(0.1f);
@@ -82,10 +86,23 @@ public class LayerWorld extends Layer {
tmp.set(velocity);
tmp.mul((float) (GraphicsInterface.getFrameLength() * 60));
camera.move(tmp);
+
+ if (I_WANT_TO_THROW_UP) {
+ shakeParam += tmp.set(tmp.x, 0, tmp.z).length() * 1.5f;
+ float vel = tmp.set(velocity).set(tmp.x, 0, tmp.z).length() * 0.7f;
+
+ helper.pushViewTransform().translate(
+ (float) Math.sin(shakeParam) * vel,
+ (float) Math.sin(2 * shakeParam) * vel,
+ 0.25f
+ ).rotateZ(
+ (float) Math.sin(shakeParam) * vel * 0.15f
+ );
+ }
}
private void renderWorld() {
- world.render(renderer);
+ world.render(helper);
}
public Camera getCamera() {
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderer.java b/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderHelper.java
similarity index 71%
rename from src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderer.java
rename to src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderHelper.java
index 1733b4f..5caefd9 100644
--- a/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderer.java
+++ b/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderHelper.java
@@ -18,38 +18,20 @@
package ru.windcorp.optica.client.graphics.world;
import glm.mat._4.Mat4;
+import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.optica.common.util.StashingStack;
-public class WorldRenderer {
-
- private static final int TRANSFORM_STACK_SIZE = 64;
-
- private final StashingStack worldTransformStack = new StashingStack<>(
- TRANSFORM_STACK_SIZE, Mat4::new
- );
+public class WorldRenderHelper extends ShapeRenderHelper {
private final StashingStack viewTransformStack = new StashingStack<>(
TRANSFORM_STACK_SIZE, Mat4::new
);
- private final Mat4 finalTransform = new Mat4();
-
{
- reset();
+ viewTransformStack.push().identity();
}
- public Mat4 pushWorldTransform() {
- Mat4 previous = worldTransformStack.getHead();
- return worldTransformStack.push().set(previous);
- }
-
- public void popWorldTransform() {
- worldTransformStack.removeHead();
- }
-
- public Mat4 getWorldTransform() {
- return worldTransformStack.getHead();
- }
+ private final Mat4 finalTransform = new Mat4();
public Mat4 pushViewTransform() {
Mat4 previous = viewTransformStack.getHead();
@@ -64,13 +46,14 @@ public class WorldRenderer {
return viewTransformStack.getHead();
}
+ @Override
public Mat4 getFinalTransform() {
return finalTransform.set(getViewTransform()).mul(getWorldTransform());
}
+ @Override
public void reset() {
- worldTransformStack.removeAll();
- worldTransformStack.push().identity();
+ super.reset();
viewTransformStack.removeAll();
viewTransformStack.push().identity();
}
diff --git a/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderProgram.java b/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderProgram.java
new file mode 100644
index 0000000..baac644
--- /dev/null
+++ b/src/main/java/ru/windcorp/optica/client/graphics/world/WorldRenderProgram.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Optica
+ * Copyright (C) 2020 Wind Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *******************************************************************************/
+package ru.windcorp.optica.client.graphics.world;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.GL11;
+
+import com.google.common.collect.ObjectArrays;
+
+import glm.vec._2.Vec2;
+import glm.vec._3.Vec3;
+import ru.windcorp.optica.client.graphics.backend.VertexBufferObject;
+import ru.windcorp.optica.client.graphics.backend.shaders.attributes.*;
+import ru.windcorp.optica.client.graphics.backend.shaders.uniforms.*;
+import ru.windcorp.optica.client.graphics.model.Face;
+import ru.windcorp.optica.client.graphics.model.Shape;
+import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
+import ru.windcorp.optica.client.graphics.model.ShapeRenderProgram;
+
+public class WorldRenderProgram extends ShapeRenderProgram {
+
+ private static WorldRenderProgram def = null;
+
+ public static void init() {
+ def = new WorldRenderProgram(
+ new String[] {"WorldDefault.vertex.glsl"},
+ new String[] {"WorldDefault.fragment.glsl"}
+ );
+ }
+
+ public static WorldRenderProgram getDefault() {
+ return def;
+ }
+
+ private static final int DEFAULT_BYTES_PER_VERTEX =
+ 3 * Float.BYTES + // Position
+ 3 * Float.BYTES + // Color multiplier
+ 2 * Float.BYTES + // Texture coordinates
+ 3 * Float.BYTES; // Normals
+
+ private static final String WORLD_VERTEX_SHADER_RESOURCE =
+ "World.vertex.glsl";
+ private static final String WORLD_FRAGMENT_SHADER_RESOURCE =
+ "World.fragment.glsl";
+
+ private static final String
+ WORLD_TRANSFORM_UNIFORM_NAME = "worldTransform",
+ NORMALS_ATTRIBUTE_NAME = "inputNormals";
+
+ private final Uniform4Matrix worldTransformUniform;
+ private final AttributeVertexArray normalsAttribute;
+
+ public WorldRenderProgram(
+ String[] vertexShaderResources,
+ String[] fragmentShaderResources
+ ) {
+ super(
+ attachVertexShader(vertexShaderResources),
+ attachFragmentShader(fragmentShaderResources)
+ );
+
+ this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME)
+ .as4Matrix();
+
+ this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME)
+ .asVertexArray();
+ }
+
+ private static String[] attachVertexShader(String[] others) {
+ return ObjectArrays.concat(WORLD_VERTEX_SHADER_RESOURCE, others);
+ }
+
+ private static String[] attachFragmentShader(String[] others) {
+ return ObjectArrays.concat(WORLD_FRAGMENT_SHADER_RESOURCE, others);
+ }
+
+ @Override
+ protected void configure(ShapeRenderHelper helper) {
+ super.configure(helper);
+ worldTransformUniform.set(helper.getWorldTransform());
+ }
+
+ @Override
+ protected int bindVertices(VertexBufferObject vertices) {
+ int vertexStride = getBytesPerVertex();
+ int offset = super.bindVertices(vertices);
+
+ normalsAttribute.set(
+ 3, GL11.GL_FLOAT, false, vertexStride, vertices,
+ offset
+ );
+ offset += 3 * Float.BYTES;
+
+ return offset;
+ }
+
+ @Override
+ protected void enableAttributes() {
+ super.enableAttributes();
+ normalsAttribute.enable();
+ }
+
+ @Override
+ protected void disableAttributes() {
+ super.disableAttributes();
+ normalsAttribute.disable();
+ }
+
+ @Override
+ public int getBytesPerVertex() {
+ return super.getBytesPerVertex() +
+ 3 * Float.BYTES; // Normals
+ }
+
+ @Override
+ public void preprocess(Shape shape) {
+ super.preprocess(shape);
+
+ for (Face face : shape.getFaces()) {
+ computeNormals(face);
+ }
+ }
+
+ private void computeNormals(Face face) {
+ Vec3 a = new Vec3();
+ Vec3 b = new Vec3();
+ Vec3 c = new Vec3();
+ Vec3 normal = new Vec3();
+
+ for (int i = 0; i < face.getIndexCount(); i += 3) {
+ int indexA = face.getIndex(i + 0);
+ int indexB = face.getIndex(i + 1);
+ int indexC = face.getIndex(i + 2);
+
+ loadVertexPosition(face, indexA, a);
+ loadVertexPosition(face, indexB, b);
+ loadVertexPosition(face, indexC, c);
+
+ computeOneNormal(a, b, c, normal);
+
+ saveVertexNormal(face, indexA, normal);
+ saveVertexNormal(face, indexB, normal);
+ saveVertexNormal(face, indexC, normal);
+ }
+ }
+
+ private void computeOneNormal(
+ Vec3 a, Vec3 b, Vec3 c,
+ Vec3 normal
+ ) {
+ b.sub(a);
+ c.sub(a);
+ b.cross(c, normal);
+ normal.normalize();
+ }
+
+ private void loadVertexPosition(Face face, int index, Vec3 result) {
+ ByteBuffer vertices = face.getVertices();
+ int offset = vertices.position() + index * getBytesPerVertex();
+
+ result.set(
+ vertices.getFloat(offset + 0 * Float.BYTES),
+ vertices.getFloat(offset + 1 * Float.BYTES),
+ vertices.getFloat(offset + 2 * Float.BYTES)
+ );
+ }
+
+ private void saveVertexNormal(Face face, int index, Vec3 normal) {
+ ByteBuffer vertices = face.getVertices();
+ int offset = vertices.position() + index * getBytesPerVertex() + (
+ 3 * Float.BYTES +
+ 3 * Float.BYTES +
+ 2 * Float.BYTES
+ );
+
+ vertices.putFloat(offset + 0 * Float.BYTES, normal.x);
+ vertices.putFloat(offset + 1 * Float.BYTES, normal.y);
+ vertices.putFloat(offset + 2 * Float.BYTES, normal.z);
+
+ face.markForVertexUpdate();
+ }
+
+ @Override
+ public VertexBuilder getVertexBuilder() {
+ return new WRPVertexBuilder();
+ }
+
+ private static class WRPVertexBuilder implements VertexBuilder {
+ // TODO Throw VertexBuilders out the window and rewrite completely.
+ // I want to _extend_ VBs, not re-implement them for children of SRP
+
+ private static class Vertex {
+ final Vec3 position;
+ final Vec3 colorMultiplier;
+ final Vec2 textureCoords;
+
+ Vertex(Vec3 position, Vec3 colorMultiplier, Vec2 textureCoords) {
+ this.position = position;
+ this.colorMultiplier = colorMultiplier;
+ this.textureCoords = textureCoords;
+ }
+ }
+
+ private final List vertices = new ArrayList<>();
+
+ @Override
+ public VertexBuilder addVertex(
+ float x, float y, float z,
+ float r, float g, float b,
+ float tx, float ty
+ ) {
+ vertices.add(new Vertex(
+ new Vec3(x, y, z),
+ new Vec3(r, g, b),
+ new Vec2(tx, ty)
+ ));
+
+ return this;
+ }
+
+ @Override
+ public VertexBuilder addVertex(
+ Vec3 position,
+ Vec3 colorMultiplier,
+ Vec2 textureCoords
+ ) {
+ vertices.add(new Vertex(
+ new Vec3(position),
+ new Vec3(colorMultiplier),
+ new Vec2(textureCoords)
+ ));
+
+ return this;
+ }
+
+ @Override
+ public ByteBuffer assemble() {
+ ByteBuffer result = BufferUtils.createByteBuffer(
+ DEFAULT_BYTES_PER_VERTEX * vertices.size()
+ );
+
+ for (Vertex v : vertices) {
+ result
+ .putFloat(v.position.x)
+ .putFloat(v.position.y)
+ .putFloat(v.position.z)
+ .putFloat(v.colorMultiplier.x)
+ .putFloat(v.colorMultiplier.y)
+ .putFloat(v.colorMultiplier.z)
+ .putFloat(v.textureCoords.x)
+ .putFloat(v.textureCoords.y)
+ .putFloat(Float.NaN)
+ .putFloat(Float.NaN)
+ .putFloat(Float.NaN);
+ }
+
+ result.flip();
+
+ return result;
+ }
+
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/optica/client/world/ChunkRender.java b/src/main/java/ru/windcorp/optica/client/world/ChunkRender.java
index 1e166b0..53cfe27 100644
--- a/src/main/java/ru/windcorp/optica/client/world/ChunkRender.java
+++ b/src/main/java/ru/windcorp/optica/client/world/ChunkRender.java
@@ -26,7 +26,7 @@ import ru.windcorp.optica.client.graphics.model.Shape;
import ru.windcorp.optica.client.graphics.model.StaticModel;
import ru.windcorp.optica.client.graphics.model.StaticModel.Builder;
import ru.windcorp.optica.client.graphics.model.WorldRenderable;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
+import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.optica.client.world.renders.BlockRender;
import ru.windcorp.optica.client.world.renders.BlockRenderNone;
import ru.windcorp.optica.client.world.renders.BlockRenders;
@@ -70,7 +70,7 @@ public class ChunkRender {
);
}
- public void render(WorldRenderer renderer) {
+ public void render(ShapeRenderHelper renderer) {
if (model == null || needsUpdate()) {
buildModel();
}
diff --git a/src/main/java/ru/windcorp/optica/client/world/WorldRender.java b/src/main/java/ru/windcorp/optica/client/world/WorldRender.java
index 46efe7c..67301c9 100644
--- a/src/main/java/ru/windcorp/optica/client/world/WorldRender.java
+++ b/src/main/java/ru/windcorp/optica/client/world/WorldRender.java
@@ -21,7 +21,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
+import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.optica.common.world.ChunkData;
import ru.windcorp.optica.common.world.WorldData;
@@ -55,7 +55,7 @@ public class WorldRender {
return chunks.values();
}
- public void render(WorldRenderer renderer) {
+ public void render(ShapeRenderHelper renderer) {
renderer.pushWorldTransform().rotateX(-Math.PI / 2);
for (ChunkRender chunk : getChunks()) {
diff --git a/src/main/java/ru/windcorp/optica/client/world/renders/BlockRender.java b/src/main/java/ru/windcorp/optica/client/world/renders/BlockRender.java
index ca5731e..faadf63 100644
--- a/src/main/java/ru/windcorp/optica/client/world/renders/BlockRender.java
+++ b/src/main/java/ru/windcorp/optica/client/world/renders/BlockRender.java
@@ -18,7 +18,7 @@
package ru.windcorp.optica.client.world.renders;
import ru.windcorp.optica.client.graphics.model.WorldRenderable;
-import ru.windcorp.optica.client.graphics.world.WorldRenderer;
+import ru.windcorp.optica.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.optica.common.util.Namespaced;
public abstract class BlockRender extends Namespaced {
@@ -41,7 +41,7 @@ public abstract class BlockRender extends Namespaced {
this.optimizer = optimizer;
}
- public void render(WorldRenderer renderer) {
+ public void render(ShapeRenderHelper renderer) {
throw new UnsupportedOperationException(
"BlockRender.render() not implemented"
);
diff --git a/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenderTexturedCube.java
index f555c88..4359882 100644
--- a/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenderTexturedCube.java
+++ b/src/main/java/ru/windcorp/optica/client/world/renders/BlockRenderTexturedCube.java
@@ -24,6 +24,7 @@ import java.util.EnumMap;
import ru.windcorp.optica.client.graphics.model.Shapes;
import ru.windcorp.optica.client.graphics.model.WorldRenderable;
import ru.windcorp.optica.client.graphics.texture.Texture;
+import ru.windcorp.optica.client.graphics.world.WorldRenderProgram;
import ru.windcorp.optica.common.block.BlockFace;
public abstract class BlockRenderTexturedCube extends BlockRender {
@@ -54,6 +55,7 @@ public abstract class BlockRenderTexturedCube extends BlockRender {
@Override
public WorldRenderable createRenderable() {
return new Shapes.PppBuilder(
+ WorldRenderProgram.getDefault(),
getTexture(TOP), getTexture(BOTTOM),
getTexture(NORTH), getTexture(SOUTH),
getTexture(EAST), getTexture(WEST)
diff --git a/src/main/java/ru/windcorp/optica/client/world/renders/bro/BlockRenderOpaqueCubeOptimizer.java b/src/main/java/ru/windcorp/optica/client/world/renders/bro/BlockRenderOpaqueCubeOptimizer.java
index 5450456..002e160 100644
--- a/src/main/java/ru/windcorp/optica/client/world/renders/bro/BlockRenderOpaqueCubeOptimizer.java
+++ b/src/main/java/ru/windcorp/optica/client/world/renders/bro/BlockRenderOpaqueCubeOptimizer.java
@@ -28,6 +28,7 @@ import ru.windcorp.optica.client.graphics.model.Face;
import ru.windcorp.optica.client.graphics.model.Faces;
import ru.windcorp.optica.client.graphics.model.Shape;
import ru.windcorp.optica.client.graphics.texture.Texture;
+import ru.windcorp.optica.client.graphics.world.WorldRenderProgram;
import ru.windcorp.optica.client.world.ChunkRender;
import ru.windcorp.optica.client.world.renders.BlockRender;
import ru.windcorp.optica.common.block.BlockFace;
@@ -167,6 +168,7 @@ public class BlockRenderOpaqueCubeOptimizer extends BlockRenderOptimizer {
return new Shape(
Usage.STATIC,
+ WorldRenderProgram.getDefault(),
shapeFaces.toArray(new Face[shapeFaces.size()])
);
}
@@ -177,6 +179,7 @@ public class BlockRenderOpaqueCubeOptimizer extends BlockRenderOptimizer {
Texture texture = blockRender.getTexture(face);
return Faces.createBlockFace(
+ WorldRenderProgram.getDefault(),
texture,
COLOR_MULTIPLIER,
blockCenter.set(x, y, z),
diff --git a/src/main/resources/assets/shaders/Shape.fragment.glsl b/src/main/resources/assets/shaders/Shape.fragment.glsl
index b80887c..d5e69b5 100644
--- a/src/main/resources/assets/shaders/Shape.fragment.glsl
+++ b/src/main/resources/assets/shaders/Shape.fragment.glsl
@@ -2,7 +2,6 @@
varying vec3 varyingColorMultiplier;
varying vec2 varyingTextureCoords;
-varying vec3 varyingNormals;
uniform sampler2D textureSlot;
uniform vec2 textureStart;
@@ -36,16 +35,6 @@ void applyColorMultiplier() {
linearMultiply(gl_FragColor, vec4(varyingColorMultiplier, 1.0));
}
-void applyShading() {
- vec3 light = normalize(vec3(0.5, 1.0, 0.2));
- vec3 normal = varyingNormals;
-
- float angleCos = dot(normal, light);
- float lightness = (angleCos + 1.5) / 2;
-
- linearMultiply(gl_FragColor, vec4(lightness, lightness, lightness, 1.0));
-}
-
void applyAlpha() {
if (gl_FragColor.w < 0.01) {
discard;
diff --git a/src/main/resources/assets/shaders/Shape.vertex.glsl b/src/main/resources/assets/shaders/Shape.vertex.glsl
index 3ce95ff..b5da67f 100644
--- a/src/main/resources/assets/shaders/Shape.vertex.glsl
+++ b/src/main/resources/assets/shaders/Shape.vertex.glsl
@@ -8,20 +8,13 @@ varying vec3 varyingColorMultiplier;
attribute vec2 inputTextureCoords;
varying vec2 varyingTextureCoords;
-attribute vec3 inputNormals;
-varying vec3 varyingNormals;
-
-uniform mat4 worldTransform;
uniform mat4 finalTransform;
vec4 applyFinalTransform(vec4 vector) {
return finalTransform * vector;
}
-void transferToFragment() {
+void shapeTransferToFragment() {
varyingColorMultiplier = inputColorMultiplier;
varyingTextureCoords = inputTextureCoords;
-
- mat3 worldRotation = mat3(worldTransform);
- varyingNormals = normalize(worldRotation * inputNormals);
}
\ No newline at end of file
diff --git a/src/main/resources/assets/shaders/World.fragment.glsl b/src/main/resources/assets/shaders/World.fragment.glsl
new file mode 100644
index 0000000..7ec061b
--- /dev/null
+++ b/src/main/resources/assets/shaders/World.fragment.glsl
@@ -0,0 +1,13 @@
+#version 120
+
+varying vec3 varyingNormals;
+
+void applyShading() {
+ vec3 light = normalize(vec3(0.5, 1.0, 0.2));
+ vec3 normal = varyingNormals;
+
+ float angleCos = dot(normal, light);
+ float lightness = (angleCos + 1.5) / 2;
+
+ linearMultiply(gl_FragColor, vec4(lightness, lightness, lightness, 1.0));
+}
\ No newline at end of file
diff --git a/src/main/resources/assets/shaders/World.vertex.glsl b/src/main/resources/assets/shaders/World.vertex.glsl
new file mode 100644
index 0000000..229df49
--- /dev/null
+++ b/src/main/resources/assets/shaders/World.vertex.glsl
@@ -0,0 +1,13 @@
+#version 120
+
+attribute vec3 inputNormals;
+varying vec3 varyingNormals;
+
+uniform mat4 worldTransform;
+
+void worldTransferToFragment() {
+ shapeTransferToFragment();
+
+ mat3 worldRotation = mat3(worldTransform);
+ varyingNormals = normalize(worldRotation * inputNormals);
+}
\ No newline at end of file
diff --git a/src/main/resources/assets/shaders/WorldDefault.vertex.glsl b/src/main/resources/assets/shaders/WorldDefault.vertex.glsl
index 11faad1..e9b6579 100644
--- a/src/main/resources/assets/shaders/WorldDefault.vertex.glsl
+++ b/src/main/resources/assets/shaders/WorldDefault.vertex.glsl
@@ -2,5 +2,5 @@
void main(void) {
gl_Position = applyFinalTransform(vec4(inputPositions, 1.0));
- transferToFragment();
+ worldTransferToFragment();
}
\ No newline at end of file