Includes, quaternions, and frames.

- Shaders can now reference other files with #flwinclude <"...">.
 - Shaders are now located in assets/flywheel/shaders.
 - Include paths are namespaced (a la ResourceLocation) and relative to the flywheel shaders root folder.
 - Optimized glsl rotations using quaternions (when applicable) and vectorized matrix construction.
 - Vectorize diffuse lighting calculations.
 - Micro optimization in SmartTileEntity.java
This commit is contained in:
JozsefA 2021-03-18 14:36:37 -07:00
parent f7f51d1988
commit b7ec884b9c
28 changed files with 590 additions and 447 deletions

View file

@ -10,7 +10,7 @@ public enum ActorVertexAttributes implements IVertexAttrib {
LIGHT("aModelLight", CommonAttributes.LIGHT), LIGHT("aModelLight", CommonAttributes.LIGHT),
OFFSET("aOffset", CommonAttributes.FLOAT), OFFSET("aOffset", CommonAttributes.FLOAT),
AXIS("aAxis", CommonAttributes.NORMAL), AXIS("aAxis", CommonAttributes.NORMAL),
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3), INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION),
ROTATION_CENTER("aRotationCenter", CommonAttributes.NORMAL), ROTATION_CENTER("aRotationCenter", CommonAttributes.NORMAL),
SPEED("aSpeed", CommonAttributes.FLOAT), SPEED("aSpeed", CommonAttributes.FLOAT),
; ;

View file

@ -6,6 +6,7 @@ import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat;
import com.simibubi.create.foundation.render.backend.instancing.InstanceData; import com.simibubi.create.foundation.render.backend.instancing.InstanceData;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.Vector3f;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -23,9 +24,10 @@ public class ContraptionActorData extends InstanceData {
private byte rotationAxisX; private byte rotationAxisX;
private byte rotationAxisY; private byte rotationAxisY;
private byte rotationAxisZ; private byte rotationAxisZ;
private float localRotationX; private float qX;
private float localRotationY; private float qY;
private float localRotationZ; private float qZ;
private float qW;
private byte rotationCenterX = 64; private byte rotationCenterX = 64;
private byte rotationCenterY = 64; private byte rotationCenterY = 64;
private byte rotationCenterZ = 64; private byte rotationCenterZ = 64;
@ -88,15 +90,11 @@ public class ContraptionActorData extends InstanceData {
return this; return this;
} }
public ContraptionActorData setLocalRotation(Vector3f axis) { public ContraptionActorData setLocalRotation(Quaternion q) {
setLocalRotation(axis.getX(), axis.getY(), axis.getZ()); this.qX = q.getX();
return this; this.qY = q.getY();
} this.qZ = q.getZ();
this.qW = q.getW();
public ContraptionActorData setLocalRotation(float localRotationX, float localRotationY, float localRotationZ) {
this.localRotationX = localRotationX;
this.localRotationY = localRotationY;
this.localRotationZ = localRotationZ;
return this; return this;
} }
@ -106,7 +104,7 @@ public class ContraptionActorData extends InstanceData {
putVec2(buf, blockLight, skyLight); putVec2(buf, blockLight, skyLight);
put(buf, rotationOffset); put(buf, rotationOffset);
putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ); putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ);
putVec3(buf, localRotationX, localRotationY, localRotationZ); putVec4(buf, qX, qY, qZ, qW);
putVec3(buf, rotationCenterX, rotationCenterY, rotationCenterZ); putVec3(buf, rotationCenterX, rotationCenterY, rotationCenterZ);
put(buf, speed); put(buf, speed);

View file

@ -10,6 +10,7 @@ import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
public class DrillActorInstance extends ActorInstance { public class DrillActorInstance extends ActorInstance {
@ -25,8 +26,15 @@ public class DrillActorInstance extends ActorInstance {
BlockState state = context.state; BlockState state = context.state;
facing = state.get(DrillBlock.FACING); facing = state.get(DrillBlock.FACING);
float eulerX = AngleHelper.verticalAngle(facing) + ((facing.getAxis() == Direction.Axis.Y) ? 180 : 0);
float eulerY = facing.getHorizontalAngle(); Direction.Axis axis = facing.getAxis();
float eulerX = AngleHelper.verticalAngle(facing);
float eulerY;
if (axis == Direction.Axis.Y)
eulerY = 0;
else
eulerY = facing.getHorizontalAngle() + ((axis == Direction.Axis.X) ? 180 : 0);
drillHead = renderMaterial.getModel(AllBlockPartials.DRILL_HEAD, state).createInstance(); drillHead = renderMaterial.getModel(AllBlockPartials.DRILL_HEAD, state).createInstance();
@ -35,7 +43,7 @@ public class DrillActorInstance extends ActorInstance {
.setBlockLight(localBlockLight()) .setBlockLight(localBlockLight())
.setRotationOffset(0) .setRotationOffset(0)
.setRotationAxis(0, 0, 1) .setRotationAxis(0, 0, 1)
.setLocalRotation(eulerX, eulerY, 0) .setLocalRotation(new Quaternion(eulerX, eulerY, 0, true))
.setSpeed(getSpeed(facing)); .setSpeed(getSpeed(facing));
} }

View file

@ -8,6 +8,7 @@ import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.Vector3f;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.world.LightType; import net.minecraft.world.LightType;
@ -32,13 +33,14 @@ public class HarvesterActorInstance extends ActorInstance {
harvester = renderMaterial.getModel(AllBlockPartials.HARVESTER_BLADE, state).createInstance(); harvester = renderMaterial.getModel(AllBlockPartials.HARVESTER_BLADE, state).createInstance();
float horizontalAngle = facing.getHorizontalAngle() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0);
harvester.getInstance() harvester.getInstance()
.setPosition(context.localPos) .setPosition(context.localPos)
.setBlockLight(localBlockLight()) .setBlockLight(localBlockLight())
.setRotationOffset(0) .setRotationOffset(0)
.setRotationCenter(rotOffset) .setRotationCenter(rotOffset)
.setRotationAxis(-1, 0, 0) .setRotationAxis(-1, 0, 0)
.setLocalRotation(0, facing.getHorizontalAngle(), 0) .setLocalRotation(new Quaternion(Vector3f.POSITIVE_Y, horizontalAngle, true))
.setSpeed(getSpeed(facing)); .setSpeed(getSpeed(facing));
} }

View file

@ -31,6 +31,8 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
float zRot; float zRot;
float zRotPole; float zRotPole;
float progress = Float.NaN;
public DeployerInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) { public DeployerInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
super(dispatcher, tile); super(dispatcher, tile);
} }
@ -57,13 +59,19 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
@Override @Override
public void tick() { public void tick() {
updateHandPose(); boolean newHand = updateHandPose();
float newProgress = getProgress(AnimationTickHolder.getPartialTicks());
if (!newHand && MathHelper.epsilonEquals(newProgress, progress)) return;
progress = newProgress;
MatrixStack ms = new MatrixStack(); MatrixStack ms = new MatrixStack();
MatrixStacker msr = MatrixStacker.of(ms); MatrixStacker msr = MatrixStacker.of(ms);
msr.translate(getFloatingPos()) msr.translate(getFloatingPos())
.translate(getHandOffset(AnimationTickHolder.getPartialTicks())); .translate(getHandOffset());
transformModel(msr, pole, hand, yRot, zRot, zRotPole); transformModel(msr, pole, hand, yRot, zRot, zRotPole);
@ -99,13 +107,7 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
return true; return true;
} }
protected Vec3d getHandOffset(float partialTicks) { protected Vec3d getHandOffset() {
float progress = 0;
if (tile.state == DeployerTileEntity.State.EXPANDING)
progress = 1 - (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f;
if (tile.state == DeployerTileEntity.State.RETRACTING)
progress = (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f;
float handLength = tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0 float handLength = tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0
: tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; : tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f;
float distance = Math.min(MathHelper.clamp(progress, 0, 1) * (tile.reach + handLength), 21 / 16f); float distance = Math.min(MathHelper.clamp(progress, 0, 1) * (tile.reach + handLength), 21 / 16f);
@ -113,6 +115,14 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
return offset; return offset;
} }
private float getProgress(float partialTicks) {
if (tile.state == DeployerTileEntity.State.EXPANDING)
return 1 - (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f;
if (tile.state == DeployerTileEntity.State.RETRACTING)
return (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f;
return 0;
}
static void transformModel(MatrixStacker msr, InstanceKey<ModelData> pole, InstanceKey<ModelData> hand, float yRot, float zRot, float zRotPole) { static void transformModel(MatrixStacker msr, InstanceKey<ModelData> pole, InstanceKey<ModelData> hand, float yRot, float zRot, float zRotPole) {
msr.centre(); msr.centre();

View file

@ -8,6 +8,7 @@ import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
public class BeltData extends KineticData<BeltData> { public class BeltData extends KineticData<BeltData> {
@ -16,9 +17,10 @@ public class BeltData extends KineticData<BeltData> {
.addAttributes(BeltVertexAttributes.class) .addAttributes(BeltVertexAttributes.class)
.build(); .build();
private float rotX; private float qX;
private float rotY; private float qY;
private float rotZ; private float qZ;
private float qW;
private float sourceU; private float sourceU;
private float sourceV; private float sourceV;
private float minU; private float minU;
@ -31,10 +33,11 @@ public class BeltData extends KineticData<BeltData> {
super(owner); super(owner);
} }
public BeltData setRotation(float rotX, float rotY, float rotZ) { public BeltData setRotation(Quaternion q) {
this.rotX = rotX; this.qX = q.getX();
this.rotY = rotY; this.qY = q.getY();
this.rotZ = rotZ; this.qZ = q.getZ();
this.qW = q.getW();
return this; return this;
} }
@ -61,7 +64,7 @@ public class BeltData extends KineticData<BeltData> {
public void write(ByteBuffer buf) { public void write(ByteBuffer buf) {
super.write(buf); super.write(buf);
putVec3(buf, rotX, rotY, rotZ); putVec4(buf, qX, qY, qZ, qW);
putVec2(buf, sourceU, sourceV); putVec2(buf, sourceU, sourceV);
putVec4(buf, minU, minV, maxU, maxV); putVec4(buf, minU, minV, maxU, maxV);

View file

@ -13,9 +13,11 @@ import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; import com.simibubi.create.foundation.render.backend.instancing.InstanceKey;
import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; import com.simibubi.create.foundation.render.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.client.renderer.Quaternion;
import net.minecraft.item.DyeColor; import net.minecraft.item.DyeColor;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.world.LightType; import net.minecraft.world.LightType;
@ -114,10 +116,10 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
private float getScrollSpeed() { private float getScrollSpeed() {
float speed = tile.getSpeed(); float speed = tile.getSpeed();
if (((facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ^ upward) ^ if (((facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ^ upward) ^
((alongX && !diagonal) || (alongZ && diagonal)) ^ (vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE)) { ((alongX && !diagonal) || (alongZ && diagonal))) {
speed = -speed; speed = -speed;
} }
if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST)) if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST) || (vertical && facing == Direction.EAST))
speed = -speed; speed = -speed;
return speed; return speed;
@ -155,15 +157,18 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
} }
private InstanceKey<BeltData> setup(InstanceKey<BeltData> key, boolean bottom, SpriteShiftEntry spriteShift) { private InstanceKey<BeltData> setup(InstanceKey<BeltData> key, boolean bottom, SpriteShiftEntry spriteShift) {
float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (beltSlope == BeltSlope.DOWNWARD ? 180 : 0); boolean downward = beltSlope == BeltSlope.DOWNWARD;
float rotY = facing.getHorizontalAngle() + (upward ? 180 : 0) + (sideways ? 90 : 0); float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (downward ? 180 : 0) + (sideways ? 90 : 0) + (vertical && alongZ ? 180 : 0);
float rotZ = sideways ? 90 : ((vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ? 180 : 0); float rotY = facing.getHorizontalAngle() + ((diagonal ^ alongX) && !downward ? 180 : 0) + (sideways && alongZ ? 180 : 0) + (vertical && alongX ? 90 : 0);
float rotZ = (sideways ? 90 : 0) + (vertical && alongX ? 90 : 0);
Quaternion q = new Quaternion(rotX, rotY, rotZ, true);
key.getInstance() key.getInstance()
.setTileEntity(tile) .setTileEntity(tile)
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) .setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
.setSkyLight(world.getLightLevel(LightType.SKY, pos)) .setSkyLight(world.getLightLevel(LightType.SKY, pos))
.setRotation(rotX, rotY, rotZ) .setRotation(q)
.setRotationalSpeed(getScrollSpeed()) .setRotationalSpeed(getScrollSpeed())
.setRotationOffset(bottom ? 0.5f : 0f) .setRotationOffset(bottom ? 0.5f : 0f)
.setScrollTexture(spriteShift) .setScrollTexture(spriteShift)

View file

@ -6,7 +6,7 @@ import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib;
import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec;
public enum BeltVertexAttributes implements IVertexAttrib { public enum BeltVertexAttributes implements IVertexAttrib {
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3), INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION),
SOURCE_TEX("aSourceTexture", CommonAttributes.UV), SOURCE_TEX("aSourceTexture", CommonAttributes.UV),
SCROLL_TEX("aScrollTexture", CommonAttributes.VEC4), SCROLL_TEX("aScrollTexture", CommonAttributes.VEC4),
SCROLL_MULT("aScrollMult", CommonAttributes.NORMALIZED_BYTE), SCROLL_MULT("aScrollMult", CommonAttributes.NORMALIZED_BYTE),

View file

@ -108,7 +108,7 @@ public class AllProgramSpecs {
private static ResourceLocation loc(String name) { private static ResourceLocation loc(String name) {
return new ResourceLocation(Create.ID, "shader/" + name); return new ResourceLocation(Create.ID, name);
} }
} }
} }

View file

@ -1,36 +1,26 @@
package com.simibubi.create.foundation.render.backend; package com.simibubi.create.foundation.render.backend;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import com.simibubi.create.foundation.render.backend.gl.GlFog; import com.simibubi.create.foundation.render.backend.gl.GlFog;
import com.simibubi.create.foundation.render.backend.gl.GlFogMode;
import com.simibubi.create.foundation.render.backend.gl.shader.*; import com.simibubi.create.foundation.render.backend.gl.shader.*;
import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat; import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat;
import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager; import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener; import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.resource.VanillaResourceType;
public class Backend { public class Backend {
public static final Boolean SHADER_DEBUG_OUTPUT = true; public static final Boolean SHADER_DEBUG_OUTPUT = true;
@ -38,8 +28,8 @@ public class Backend {
public static final Logger log = LogManager.getLogger(Backend.class); public static final Logger log = LogManager.getLogger(Backend.class);
public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16); public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
private static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>(); static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
private static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>(); static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
private static boolean enabled; private static boolean enabled;
@ -102,85 +92,13 @@ public class Backend {
IResourceManager manager = mc.getResourceManager(); IResourceManager manager = mc.getResourceManager();
if (manager instanceof IReloadableResourceManager) { if (manager instanceof IReloadableResourceManager) {
ISelectiveResourceReloadListener listener = Backend::onResourceManagerReload; ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
((IReloadableResourceManager) manager).addReloadListener(listener); ((IReloadableResourceManager) manager).addReloadListener(listener);
} }
} }
private static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
if (predicate.test(VanillaResourceType.SHADERS)) {
capabilities = GL.createCapabilities();
compat = new GlFeatureCompat(capabilities);
OptifineHandler.refresh();
refresh();
if (gl20()) {
programs.values().forEach(ProgramGroup::delete);
programs.clear();
for (ProgramSpec<?> shader : registry.values()) {
loadProgram(manager, shader);
}
log.info("Loaded all shader programs.");
}
}
}
public static void refresh() { public static void refresh() {
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders(); enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
} }
private static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(IResourceManager manager, S programSpec) {
try {
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
for (GlFogMode fogMode : GlFogMode.values()) {
programGroup.put(fogMode, loadProgram(manager, programSpec, fogMode));
}
programs.put(programSpec, new ProgramGroup<>(programGroup));
log.debug("Loaded program {}", programSpec.name);
} catch (IOException ex) {
log.error("Failed to load program {}", programSpec.name, ex);
return;
}
}
private static <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(IResourceManager manager, S programSpec, GlFogMode fogMode) throws IOException {
GlShader vert = null;
GlShader frag = null;
try {
ShaderConstants defines = new ShaderConstants(programSpec.defines);
defines.defineAll(fogMode.getDefines());
vert = loadShader(manager, programSpec.getVert(), ShaderType.VERTEX, defines);
frag = loadShader(manager, programSpec.getFrag(), ShaderType.FRAGMENT, defines);
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
programSpec.attributes.forEach(builder::addAttribute);
return builder.build(programSpec.factory);
} finally {
if (vert != null) vert.delete();
if (frag != null) frag.delete();
}
}
private static GlShader loadShader(IResourceManager manager, ResourceLocation name, ShaderType type, GlShader.PreProcessor preProcessor) throws IOException {
try (InputStream is = new BufferedInputStream(manager.getResource(name).getInputStream())) {
String source = TextureUtil.func_225687_b_(is);
if (source == null) {
throw new IOException("Could not load program " + name);
} else {
return new GlShader(type, name, source, preProcessor);
}
}
}
} }

View file

@ -0,0 +1,202 @@
package com.simibubi.create.foundation.render.backend;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.foundation.render.backend.gl.GlFogMode;
import com.simibubi.create.foundation.render.backend.gl.shader.*;
import com.simibubi.create.foundation.render.backend.gl.versioned.GlFeatureCompat;
import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.VanillaResourceType;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryUtil;
import java.io.*;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ShaderLoader {
public static final String SHADER_DIR = "flywheel/shaders/";
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
static final Map<ResourceLocation, String> shaderSource = new HashMap<>();
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
if (predicate.test(VanillaResourceType.SHADERS)) {
Backend.capabilities = GL.createCapabilities();
Backend.compat = new GlFeatureCompat(Backend.capabilities);
OptifineHandler.refresh();
Backend.refresh();
if (Backend.gl20()) {
shaderSource.clear();
loadShaderSources(manager);
Backend.programs.values().forEach(ProgramGroup::delete);
Backend.programs.clear();
Backend.registry.values().forEach(ShaderLoader::loadProgram);
Backend.log.info("Loaded all shader programs.");
}
}
}
private static void loadShaderSources(IResourceManager manager){
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
for (String ext : EXTENSIONS) {
if (s.endsWith(ext)) return true;
}
return false;
});
for (ResourceLocation location : allShaders) {
try {
IResource resource = manager.getResource(location);
String file = readToString(resource.getInputStream());
ResourceLocation name = new ResourceLocation(location.getNamespace(),
location.getPath().substring(SHADER_DIR.length()));
shaderSource.put(name, file);
} catch (IOException e) {
}
}
}
static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(S programSpec) {
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
for (GlFogMode fogMode : GlFogMode.values()) {
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
}
Backend.programs.put(programSpec, new ProgramGroup<>(programGroup));
Backend.log.debug("Loaded program {}", programSpec.name);
}
private static <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(S programSpec, GlFogMode fogMode) {
GlShader vert = null;
GlShader frag = null;
try {
ShaderConstants defines = new ShaderConstants(programSpec.defines);
defines.defineAll(fogMode.getDefines());
vert = loadShader(programSpec.getVert(), ShaderType.VERTEX, defines);
frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines);
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
programSpec.attributes.forEach(builder::addAttribute);
return builder.build(programSpec.factory);
} finally {
if (vert != null) vert.delete();
if (frag != null) frag.delete();
}
}
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
private static String processIncludes(ResourceLocation baseName, String source) {
HashSet<ResourceLocation> seen = new HashSet<>();
seen.add(baseName);
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
}
private static Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
Matcher matcher = includePattern.matcher(line);
if (matcher.find()) {
String includeName = matcher.group(1);
ResourceLocation include = new ResourceLocation(includeName);
if (seen.add(include)) {
String includeSource = shaderSource.get(include);
if (includeSource != null) {
return includeRecursive(includeSource, seen);
}
}
}
return Stream.of(line);
});
}
private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
String source = shaderSource.get(name);
source = processIncludes(name, source);
if (defines != null)
source = defines.process(source);
return new GlShader(type, name, source);
}
public static String readToString(InputStream is) {
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
ByteBuffer bytebuffer = null;
try {
bytebuffer = readToBuffer(is);
int i = bytebuffer.position();
((Buffer)bytebuffer).rewind();
return MemoryUtil.memASCII(bytebuffer, i);
} catch (IOException e) {
} finally {
if (bytebuffer != null) {
MemoryUtil.memFree(bytebuffer);
}
}
return null;
}
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
ByteBuffer bytebuffer;
if (is instanceof FileInputStream) {
FileInputStream fileinputstream = (FileInputStream)is;
FileChannel filechannel = fileinputstream.getChannel();
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
while (filechannel.read(bytebuffer) != -1) { }
} else {
bytebuffer = MemoryUtil.memAlloc(8192);
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
while (readablebytechannel.read(bytebuffer) != -1) {
if (bytebuffer.remaining() == 0) {
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
}
}
}
return bytebuffer;
}
}

View file

@ -0,0 +1,23 @@
package com.simibubi.create.foundation.render.backend;
public class ShaderLoadingException extends RuntimeException {
public ShaderLoadingException() {
}
public ShaderLoadingException(String message) {
super(message);
}
public ShaderLoadingException(String message, Throwable cause) {
super(message, cause);
}
public ShaderLoadingException(Throwable cause) {
super(cause);
}
public ShaderLoadingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View file

@ -9,6 +9,7 @@ public class CommonAttributes {
public static final VertexAttribSpec VEC2 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2); public static final VertexAttribSpec VEC2 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2);
public static final VertexAttribSpec FLOAT = new VertexAttribSpec(GlPrimitiveType.FLOAT, 1); public static final VertexAttribSpec FLOAT = new VertexAttribSpec(GlPrimitiveType.FLOAT, 1);
public static final VertexAttribSpec QUATERNION = new VertexAttribSpec(GlPrimitiveType.FLOAT, 4);
public static final VertexAttribSpec NORMAL = new VertexAttribSpec(GlPrimitiveType.BYTE, 3, true); public static final VertexAttribSpec NORMAL = new VertexAttribSpec(GlPrimitiveType.BYTE, 3, true);
public static final VertexAttribSpec UV = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2); public static final VertexAttribSpec UV = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2);

View file

@ -12,18 +12,11 @@ public class GlShader extends GlObject {
public final ResourceLocation name; public final ResourceLocation name;
public final ShaderType type; public final ShaderType type;
public GlShader(ShaderType type, ResourceLocation name, String source, PreProcessor preProcessor) { public GlShader(ShaderType type, ResourceLocation name, String source) {
this.type = type; this.type = type;
this.name = name; this.name = name;
int handle = GL20.glCreateShader(type.glEnum); int handle = GL20.glCreateShader(type.glEnum);
if (preProcessor != null) {
source = preProcessor.process(source);
if (Backend.SHADER_DEBUG_OUTPUT)
Backend.log.debug("Preprocessor run on " + name);// + ":\n" + source);
}
GL20.glShaderSource(handle, source); GL20.glShaderSource(handle, source);
GL20.glCompileShader(handle); GL20.glCompileShader(handle);

View file

@ -147,9 +147,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends TileEntityBehaviour> T getBehaviour(BehaviourType<T> type) { public <T extends TileEntityBehaviour> T getBehaviour(BehaviourType<T> type) {
if (behaviours.containsKey(type))
return (T) behaviours.get(type); return (T) behaviours.get(type);
return null;
} }
protected boolean isItemHandlerCap(Capability<?> cap) { protected boolean isItemHandlerCap(Capability<?> cap) {

View file

@ -1,6 +1,10 @@
#version 110 #version 110
#define PI 3.1415926538 #define PI 3.1415926538
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos; attribute vec3 aPos;
attribute vec3 aNormal; attribute vec3 aNormal;
attribute vec2 aTexCoords; attribute vec2 aTexCoords;
@ -10,7 +14,7 @@ attribute vec2 aLight;
attribute vec3 aNetworkTint; attribute vec3 aNetworkTint;
attribute float aSpeed; attribute float aSpeed;
attribute float aOffset; attribute float aOffset;
attribute vec3 aInstanceRot; attribute vec4 aInstanceRot;
attribute vec2 aSourceTexture; attribute vec2 aSourceTexture;
attribute vec4 aScrollTexture; attribute vec4 aScrollTexture;
attribute float aScrollMult; attribute float aScrollMult;
@ -38,54 +42,24 @@ uniform vec3 uCameraPos;
varying float FragDistance; varying float FragDistance;
#endif #endif
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1. - 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.);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.);
}
mat4 rotation(vec3 rot) {
return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x);
}
mat4 localRotation() {
vec3 rot = fract(aInstanceRot / 360.) * PI * 2.;
return rotation(rot);
}
void main() { void main() {
mat4 localRotation = localRotation(); vec3 rotated = rotateVertexByQuat(aPos - .5, aInstanceRot) + aInstancePos + .5;
vec4 worldPos = localRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.);
vec4 worldPos = vec4(rotated, 1.);
vec3 norm = rotateVertexByQuat(aNormal, aInstanceRot);
#ifdef CONTRAPTION #ifdef CONTRAPTION
worldPos = uModel * worldPos; worldPos = uModel * worldPos;
mat4 normalMat = uModel * localRotation; norm = normalize(modelToNormal(uModel) * norm);
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
#if defined(USE_FOG) #if defined(USE_FOG)
FragDistance = length(worldPos.xyz); FragDistance = length(worldPos.xyz);
#endif #endif
#else #elif defined(USE_FOG)
mat4 normalMat = localRotation;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz - uCameraPos); FragDistance = length(worldPos.xyz - uCameraPos);
#endif #endif
#endif
vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz;
float scrollSize = aScrollTexture.w - aScrollTexture.y; float scrollSize = aScrollTexture.w - aScrollTexture.y;
float scroll = fract(aSpeed * uTime / (31.5 * 16.) + aOffset) * scrollSize * aScrollMult; float scroll = fract(aSpeed * uTime / (31.5 * 16.) + aOffset) * scrollSize * aScrollMult;

View file

@ -0,0 +1,71 @@
#version 110
#define PI 3.1415926538
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/diffuse.glsl">
// model data
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
// instance data
attribute vec3 aInstancePos;
attribute vec2 aModelLight;
attribute float aOffset;
attribute vec3 aAxis;
attribute vec4 aInstanceRot;
attribute vec3 aRotationCenter;
attribute float aSpeed;
varying float Diffuse;
varying vec2 TexCoords;
varying vec4 Color;
varying vec3 BoxCoord;
varying vec2 Light;
uniform vec3 uLightBoxSize;
uniform vec3 uLightBoxMin;
uniform mat4 uModel;
uniform float uTime;
uniform mat4 uViewProjection;
uniform int uDebug;
uniform vec3 uCameraPos;
#if defined(USE_FOG)
varying float FragDistance;
#endif
void main() {
float degrees = aOffset + uTime * aSpeed / 20.;
//float angle = fract(degrees / 360.) * PI * 2.;
vec4 kineticRot = quat(aAxis, degrees);
vec3 rotated = rotateVertexByQuat(aPos - aRotationCenter, kineticRot) + aRotationCenter;
vec3 localPos = rotateVertexByQuat(rotated - .5, aInstanceRot) + aInstancePos + .5;
vec4 worldPos = uModel * vec4(localPos, 1.);
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, kineticRot), aInstanceRot);
norm = modelToNormal(uModel) * norm;
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aModelLight;
gl_Position = uViewProjection * worldPos;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz);
#endif
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
}

View file

@ -1,6 +1,9 @@
#version 110 #version 110
#define PI 3.1415926538 #define PI 3.1415926538
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos; attribute vec3 aPos;
attribute vec3 aNormal; attribute vec3 aNormal;
attribute vec2 aTexCoords; attribute vec2 aTexCoords;
@ -27,24 +30,6 @@ uniform vec3 uCameraPos;
varying float FragDistance; varying float FragDistance;
#endif #endif
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1. - 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.);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.);
}
void main() { void main() {
vec4 viewPos = uModel * vec4(aPos, 1.); vec4 viewPos = uModel * vec4(aPos, 1.);

View file

@ -0,0 +1,5 @@
float diffuse(vec3 normal) {
vec3 n2 = normal * normal * vec3(.6, .25, .8);
return min(n2.x + n2.y * (3. + normal.y) + n2.z, 1.);
}

View file

@ -0,0 +1,42 @@
//mat4 rotate(vec3 axis, float angle) {
// float s = sin(angle);
// float c = cos(angle);
// float oc = 1. - 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 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1. - c;
vec3 sa = axis * s;
mat4 mr = mat4(1.);
mr[0].xyz = oc * axis.xxz * axis.xyx + vec3(c, sa.z, -sa.y);
mr[1].xyz = oc * axis.xyy * axis.yyz + vec3(-sa.z, c, sa.x);
mr[2].xyz = oc * axis.zyz * axis.xzz + vec3(sa.y, -sa.x, c);
return mr;
}
mat4 rotation(vec3 rot) {
return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x);
}
mat3 modelToNormal(mat4 mat) {
// Discard the edges. This won't be accurate for scaled or skewed matrices,
// but we don't have to work with those often.
mat3 m;
m[0] = mat[0].xyz;
m[1] = mat[1].xyz;
m[2] = mat[2].xyz;
return m;
}

View file

@ -0,0 +1,56 @@
#define PIOVER2 1.5707963268
vec4 quat(vec3 axis, float angle) {
float halfAngle = angle * PIOVER2 / 180.0;
vec2 cs = sin(vec2(PIOVER2 - halfAngle, halfAngle)); // compute sin and cos in one instruction
return vec4(axis.xyz * cs.y, cs.x);
}
vec4 quatMult(vec4 q1, vec4 q2) {
// disgustingly vectorized quaternion multiplication
vec4 a = q1.w * q2.xyzw;
vec4 b = q1.x * q2.wzxy * vec4(1., -1., 1., -1.);
vec4 c = q1.y * q2.zwxy * vec4(1., 1., -1., -1.);
vec4 d = q1.z * q2.yxwz * vec4(-1., 1., 1., -1.);
return a + b + c + d;
}
//
//vec4 exp(vec4 q) {
// vec3 i = q.xyz;
// float r = sqrt(dot(i, i));
// float et = exp(q.w);
// float s = et * sin(r) / r;
//
// vec4 qr;
// qr.w = et * cos(r);
// qr.xyz = i * s;
//
// return qr;
//}
//
//vec4 ln(vec4 q) {
// vec3 i = q.xyz;
// float r = sqrt(dot(i, i));
// float t = atan(r, q.w) / r;
//
// vec4 qr;
// qr.w = log(dot(q, q)) * 0.5;
// qr.xyz = i * t;
//
// return qr;
//}
//
//vec4 pow(vec4 q, float n) {
// return exp(ln(q) * n);
//}
vec3 rotateVertexByQuat(vec3 v, vec4 q) {
vec3 i = q.xyz;
return v + 2.0 * cross(i, cross(i, v) + q.w * v);
}
vec3 rotateAbout(vec3 v, vec3 axis, float angle) {
return rotateVertexByQuat(v, quat(axis, angle));
}

View file

@ -1,6 +1,10 @@
#version 110 #version 110
#define PI 3.1415926538 #define PI 3.1415926538
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos; attribute vec3 aPos;
attribute vec3 aNormal; attribute vec3 aNormal;
attribute vec2 aTexCoords; attribute vec2 aTexCoords;
@ -40,24 +44,6 @@ uniform vec3 uCameraPos;
varying float FragDistance; varying float FragDistance;
#endif #endif
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.);
}
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1. - 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.);
}
float toRad(float degrees) { float toRad(float degrees) {
return fract(degrees / 360.) * PI * 2.; return fract(degrees / 360.) * PI * 2.;
} }
@ -72,35 +58,32 @@ float getFlapAngle() {
float which = step(0., aFlapness); float which = step(0., aFlapness);
float degrees = which * halfAngle + (1. - which) * angle; // branchless conditional multiply float degrees = which * halfAngle + (1. - which) * angle; // branchless conditional multiply
return -toRad(degrees); return degrees;
} }
void main() { void main() {
float flapAngle = getFlapAngle(); float flapAngle = getFlapAngle();
mat4 orientation = rotate(vec3(0., 1., 0.), toRad(aHorizontalAngle)); vec4 orientation = quat(vec3(0., 1., 0.), -aHorizontalAngle);
mat4 flapRotation = rotate(vec3(1., 0., 0.), flapAngle); vec4 flapRotation = quat(vec3(1., 0., 0.), flapAngle);
vec4 worldPos = flapRotation * vec4(aPos - aPivot, 1.) + vec4(aPivot + aSegmentOffset, 0.); vec3 rotated = rotateVertexByQuat(aPos - aPivot, flapRotation) + aPivot + aSegmentOffset;
worldPos = orientation * vec4(worldPos.xyz - .5, 1.) + vec4(aInstancePos + .5, 0.); rotated = rotateVertexByQuat(rotated - .5, orientation) + aInstancePos + .5;
vec4 worldPos = vec4(rotated, 1.);
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, flapRotation), orientation);
#ifdef CONTRAPTION #ifdef CONTRAPTION
worldPos = uModel * worldPos; worldPos = uModel * worldPos;
mat4 normalMat = uModel * orientation * flapRotation; norm = modelToNormal(uModel) * norm;
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
#if defined(USE_FOG) #if defined(USE_FOG)
FragDistance = length(worldPos.xyz); FragDistance = length(worldPos.xyz);
#endif #endif
#else #elif defined(USE_FOG)
mat4 normalMat = orientation * flapRotation;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz - uCameraPos); FragDistance = length(worldPos.xyz - uCameraPos);
#endif #endif
#endif
vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz;
Diffuse = diffuse(norm); Diffuse = diffuse(norm);
TexCoords = aTexCoords; TexCoords = aTexCoords;

View file

@ -1,5 +1,8 @@
#version 110 #version 110
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos; attribute vec3 aPos;
attribute vec3 aNormal; attribute vec3 aNormal;
attribute vec2 aTexCoords; attribute vec2 aTexCoords;
@ -32,23 +35,6 @@ uniform vec3 uCameraPos;
varying float FragDistance; varying float FragDistance;
#endif #endif
mat3 modelToNormal(mat4 mat) {
// Discard the edges. This won't be accurate for scaled or skewed matrices,
// but we don't have to work with those often.
mat3 m;
m[0] = mat[0].xyz;
m[1] = mat[1].xyz;
m[2] = mat[2].xyz;
return m;
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.);
}
void main() { void main() {
vec4 worldPos = aTransform * vec4(aPos, 1.); vec4 worldPos = aTransform * vec4(aPos, 1.);

View file

@ -0,0 +1,82 @@
#version 110
#define PI 3.1415926538
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
attribute vec3 aInstancePos;
attribute vec2 aLight;
attribute vec3 aNetworkTint;
attribute float aSpeed;
attribute float aOffset;
attribute vec3 aAxis;
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
#if defined(CONTRAPTION)
varying vec3 BoxCoord;
uniform vec3 uLightBoxSize;
uniform vec3 uLightBoxMin;
uniform mat4 uModel;
#endif
uniform float uTime;
uniform mat4 uViewProjection;
uniform int uDebug;
uniform vec3 uCameraPos;
#if defined(USE_FOG)
varying float FragDistance;
#endif
void main() {
float degrees = aOffset + uTime * aSpeed * 3./10.;
vec4 kineticRot = quat(aAxis, degrees);
vec4 worldPos = vec4(rotateVertexByQuat(aPos - .5, kineticRot) + aInstancePos + .5, 1.);
vec3 norm = rotateVertexByQuat(aNormal, kineticRot);
#ifdef CONTRAPTION
worldPos = uModel * worldPos;
norm = modelToNormal(uModel) * norm;
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz);
#endif
#elif defined(USE_FOG)
FragDistance = length(worldPos.xyz - uCameraPos);
#endif
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aLight;
gl_Position = uViewProjection * worldPos;
#ifdef CONTRAPTION
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
#else
if (uDebug == 1) {
Color = vec4(aNetworkTint, 1.);
} else if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
#endif
}

View file

@ -1,94 +0,0 @@
#version 110
#define PI 3.1415926538
// model data
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
// instance data
attribute vec3 aInstancePos;
attribute vec2 aModelLight;
attribute float aOffset;
attribute vec3 aAxis;
attribute vec3 aInstanceRot;
attribute vec3 aRotationCenter;
attribute float aSpeed;
varying float Diffuse;
varying vec2 TexCoords;
varying vec4 Color;
varying vec3 BoxCoord;
varying vec2 Light;
uniform vec3 uLightBoxSize;
uniform vec3 uLightBoxMin;
uniform mat4 uModel;
uniform float uTime;
uniform mat4 uViewProjection;
uniform int uDebug;
uniform vec3 uCameraPos;
#if defined(USE_FOG)
varying float FragDistance;
#endif
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1. - 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.);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.);
}
mat4 rotation(vec3 rot) {
return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x);
}
mat4 kineticRotation() {
float degrees = aOffset + uTime * aSpeed / 20.;
float angle = fract(degrees / 360.) * PI * 2.;
return rotate(normalize(aAxis), -angle);
}
void main() {
mat4 kineticRotation = kineticRotation();
vec4 localPos = kineticRotation * vec4(aPos - aRotationCenter, 1.) + vec4(aRotationCenter, 0.);
vec3 rot = fract(aInstanceRot / 360.) * PI * 2.;
mat4 localRot = rotation(rot);
localPos = localRot * vec4(localPos.xyz - .5, 1.) + vec4(aInstancePos + .5, 0.);
vec4 worldPos = uModel * localPos;
vec3 norm = normalize(uModel * localRot * kineticRotation * vec4(aNormal, 0.)).xyz;
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aModelLight;
gl_Position = uViewProjection * worldPos;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz);
#endif
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
}

View file

@ -1,108 +0,0 @@
#version 110
#define PI 3.1415926538
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
attribute vec3 aInstancePos;
attribute vec2 aLight;
attribute vec3 aNetworkTint;
attribute float aSpeed;
attribute float aOffset;
attribute vec3 aAxis;
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
#if defined(CONTRAPTION)
varying vec3 BoxCoord;
uniform vec3 uLightBoxSize;
uniform vec3 uLightBoxMin;
uniform mat4 uModel;
#endif
uniform float uTime;
uniform mat4 uViewProjection;
uniform int uDebug;
uniform vec3 uCameraPos;
#if defined(USE_FOG)
varying float FragDistance;
#endif
mat4 rotate(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1. - 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.);
}
float diffuse(vec3 normal) {
float x = normal.x;
float y = normal.y;
float z = normal.z;
return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.);
}
mat4 rotation(vec3 rot) {
return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x);
}
mat4 kineticRotation() {
float degrees = aOffset + uTime * aSpeed * -3./10.;
float angle = fract(degrees / 360.) * PI * 2.;
return rotate(aAxis, angle);
}
void main() {
mat4 kineticRotation = kineticRotation();
vec4 worldPos = kineticRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.);
#ifdef CONTRAPTION
worldPos = uModel * worldPos;
mat4 normalMat = uModel * kineticRotation;
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz);
#endif
#else
mat4 normalMat = kineticRotation;
#if defined(USE_FOG)
FragDistance = length(worldPos.xyz - uCameraPos);
#endif
#endif
vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz;
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aLight;
gl_Position = uViewProjection * worldPos;
#ifdef CONTRAPTION
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
#else
if (uDebug == 1) {
Color = vec4(aNetworkTint, 1.);
} else if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
#endif
}