mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-10 20:11:35 +01:00
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:
parent
f7f51d1988
commit
b7ec884b9c
28 changed files with 590 additions and 447 deletions
|
@ -10,7 +10,7 @@ public enum ActorVertexAttributes implements IVertexAttrib {
|
|||
LIGHT("aModelLight", CommonAttributes.LIGHT),
|
||||
OFFSET("aOffset", CommonAttributes.FLOAT),
|
||||
AXIS("aAxis", CommonAttributes.NORMAL),
|
||||
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3),
|
||||
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION),
|
||||
ROTATION_CENTER("aRotationCenter", CommonAttributes.NORMAL),
|
||||
SPEED("aSpeed", CommonAttributes.FLOAT),
|
||||
;
|
||||
|
|
|
@ -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.InstancedModel;
|
||||
|
||||
import net.minecraft.client.renderer.Quaternion;
|
||||
import net.minecraft.client.renderer.Vector3f;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
|
@ -23,9 +24,10 @@ public class ContraptionActorData extends InstanceData {
|
|||
private byte rotationAxisX;
|
||||
private byte rotationAxisY;
|
||||
private byte rotationAxisZ;
|
||||
private float localRotationX;
|
||||
private float localRotationY;
|
||||
private float localRotationZ;
|
||||
private float qX;
|
||||
private float qY;
|
||||
private float qZ;
|
||||
private float qW;
|
||||
private byte rotationCenterX = 64;
|
||||
private byte rotationCenterY = 64;
|
||||
private byte rotationCenterZ = 64;
|
||||
|
@ -88,15 +90,11 @@ public class ContraptionActorData extends InstanceData {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ContraptionActorData setLocalRotation(Vector3f axis) {
|
||||
setLocalRotation(axis.getX(), axis.getY(), axis.getZ());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContraptionActorData setLocalRotation(float localRotationX, float localRotationY, float localRotationZ) {
|
||||
this.localRotationX = localRotationX;
|
||||
this.localRotationY = localRotationY;
|
||||
this.localRotationZ = localRotationZ;
|
||||
public ContraptionActorData setLocalRotation(Quaternion q) {
|
||||
this.qX = q.getX();
|
||||
this.qY = q.getY();
|
||||
this.qZ = q.getZ();
|
||||
this.qW = q.getW();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -106,7 +104,7 @@ public class ContraptionActorData extends InstanceData {
|
|||
putVec2(buf, blockLight, skyLight);
|
||||
put(buf, rotationOffset);
|
||||
putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ);
|
||||
putVec3(buf, localRotationX, localRotationY, localRotationZ);
|
||||
putVec4(buf, qX, qY, qZ, qW);
|
||||
putVec3(buf, rotationCenterX, rotationCenterY, rotationCenterZ);
|
||||
put(buf, speed);
|
||||
|
||||
|
|
|
@ -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.VecHelper;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.Quaternion;
|
||||
import net.minecraft.util.Direction;
|
||||
|
||||
public class DrillActorInstance extends ActorInstance {
|
||||
|
@ -25,8 +26,15 @@ public class DrillActorInstance extends ActorInstance {
|
|||
BlockState state = context.state;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -35,7 +43,7 @@ public class DrillActorInstance extends ActorInstance {
|
|||
.setBlockLight(localBlockLight())
|
||||
.setRotationOffset(0)
|
||||
.setRotationAxis(0, 0, 1)
|
||||
.setLocalRotation(eulerX, eulerY, 0)
|
||||
.setLocalRotation(new Quaternion(eulerX, eulerY, 0, true))
|
||||
.setSpeed(getSpeed(facing));
|
||||
}
|
||||
|
||||
|
|
|
@ -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.RenderMaterial;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.Quaternion;
|
||||
import net.minecraft.client.renderer.Vector3f;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.world.LightType;
|
||||
|
@ -32,13 +33,14 @@ public class HarvesterActorInstance extends ActorInstance {
|
|||
|
||||
harvester = renderMaterial.getModel(AllBlockPartials.HARVESTER_BLADE, state).createInstance();
|
||||
|
||||
float horizontalAngle = facing.getHorizontalAngle() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0);
|
||||
harvester.getInstance()
|
||||
.setPosition(context.localPos)
|
||||
.setBlockLight(localBlockLight())
|
||||
.setRotationOffset(0)
|
||||
.setRotationCenter(rotOffset)
|
||||
.setRotationAxis(-1, 0, 0)
|
||||
.setLocalRotation(0, facing.getHorizontalAngle(), 0)
|
||||
.setLocalRotation(new Quaternion(Vector3f.POSITIVE_Y, horizontalAngle, true))
|
||||
.setSpeed(getSpeed(facing));
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
|
|||
float zRot;
|
||||
float zRotPole;
|
||||
|
||||
float progress = Float.NaN;
|
||||
|
||||
public DeployerInstance(InstancedTileRenderer<?> dispatcher, KineticTileEntity tile) {
|
||||
super(dispatcher, tile);
|
||||
}
|
||||
|
@ -57,13 +59,19 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
|
|||
@Override
|
||||
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();
|
||||
MatrixStacker msr = MatrixStacker.of(ms);
|
||||
|
||||
msr.translate(getFloatingPos())
|
||||
.translate(getHandOffset(AnimationTickHolder.getPartialTicks()));
|
||||
.translate(getHandOffset());
|
||||
|
||||
transformModel(msr, pole, hand, yRot, zRot, zRotPole);
|
||||
|
||||
|
@ -99,13 +107,7 @@ public class DeployerInstance extends ShaftInstance implements ITickableInstance
|
|||
return true;
|
||||
}
|
||||
|
||||
protected Vec3d getHandOffset(float partialTicks) {
|
||||
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;
|
||||
|
||||
protected Vec3d getHandOffset() {
|
||||
float handLength = tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0
|
||||
: tile.getHandPose() == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
msr.centre();
|
||||
|
|
|
@ -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.instancing.InstancedModel;
|
||||
|
||||
import net.minecraft.client.renderer.Quaternion;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
|
||||
public class BeltData extends KineticData<BeltData> {
|
||||
|
@ -16,9 +17,10 @@ public class BeltData extends KineticData<BeltData> {
|
|||
.addAttributes(BeltVertexAttributes.class)
|
||||
.build();
|
||||
|
||||
private float rotX;
|
||||
private float rotY;
|
||||
private float rotZ;
|
||||
private float qX;
|
||||
private float qY;
|
||||
private float qZ;
|
||||
private float qW;
|
||||
private float sourceU;
|
||||
private float sourceV;
|
||||
private float minU;
|
||||
|
@ -31,10 +33,11 @@ public class BeltData extends KineticData<BeltData> {
|
|||
super(owner);
|
||||
}
|
||||
|
||||
public BeltData setRotation(float rotX, float rotY, float rotZ) {
|
||||
this.rotX = rotX;
|
||||
this.rotY = rotY;
|
||||
this.rotZ = rotZ;
|
||||
public BeltData setRotation(Quaternion q) {
|
||||
this.qX = q.getX();
|
||||
this.qY = q.getY();
|
||||
this.qZ = q.getZ();
|
||||
this.qW = q.getW();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -61,7 +64,7 @@ public class BeltData extends KineticData<BeltData> {
|
|||
public void write(ByteBuffer buf) {
|
||||
super.write(buf);
|
||||
|
||||
putVec3(buf, rotX, rotY, rotZ);
|
||||
putVec4(buf, qX, qY, qZ, qW);
|
||||
|
||||
putVec2(buf, sourceU, sourceV);
|
||||
putVec4(buf, minU, minV, maxU, maxV);
|
||||
|
|
|
@ -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.InstancedModel;
|
||||
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.MatrixStacker;
|
||||
|
||||
import net.minecraft.client.renderer.Quaternion;
|
||||
import net.minecraft.item.DyeColor;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.world.LightType;
|
||||
|
@ -114,10 +116,10 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
|||
private float getScrollSpeed() {
|
||||
float speed = tile.getSpeed();
|
||||
if (((facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ^ upward) ^
|
||||
((alongX && !diagonal) || (alongZ && diagonal)) ^ (vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE)) {
|
||||
((alongX && !diagonal) || (alongZ && diagonal))) {
|
||||
speed = -speed;
|
||||
}
|
||||
if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST))
|
||||
if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST) || (vertical && facing == Direction.EAST))
|
||||
speed = -speed;
|
||||
|
||||
return speed;
|
||||
|
@ -155,15 +157,18 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
|||
}
|
||||
|
||||
private InstanceKey<BeltData> setup(InstanceKey<BeltData> key, boolean bottom, SpriteShiftEntry spriteShift) {
|
||||
float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (beltSlope == BeltSlope.DOWNWARD ? 180 : 0);
|
||||
float rotY = facing.getHorizontalAngle() + (upward ? 180 : 0) + (sideways ? 90 : 0);
|
||||
float rotZ = sideways ? 90 : ((vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ? 180 : 0);
|
||||
boolean downward = beltSlope == BeltSlope.DOWNWARD;
|
||||
float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (downward ? 180 : 0) + (sideways ? 90 : 0) + (vertical && alongZ ? 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()
|
||||
.setTileEntity(tile)
|
||||
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
|
||||
.setSkyLight(world.getLightLevel(LightType.SKY, pos))
|
||||
.setRotation(rotX, rotY, rotZ)
|
||||
.setRotation(q)
|
||||
.setRotationalSpeed(getScrollSpeed())
|
||||
.setRotationOffset(bottom ? 0.5f : 0f)
|
||||
.setScrollTexture(spriteShift)
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib;
|
|||
import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec;
|
||||
|
||||
public enum BeltVertexAttributes implements IVertexAttrib {
|
||||
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3),
|
||||
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION),
|
||||
SOURCE_TEX("aSourceTexture", CommonAttributes.UV),
|
||||
SCROLL_TEX("aScrollTexture", CommonAttributes.VEC4),
|
||||
SCROLL_MULT("aScrollMult", CommonAttributes.NORMALIZED_BYTE),
|
||||
|
|
|
@ -108,7 +108,7 @@ public class AllProgramSpecs {
|
|||
|
||||
|
||||
private static ResourceLocation loc(String name) {
|
||||
return new ResourceLocation(Create.ID, "shader/" + name);
|
||||
return new ResourceLocation(Create.ID, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,26 @@
|
|||
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.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
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.GlFogMode;
|
||||
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.instancing.IFlywheelWorld;
|
||||
import net.minecraft.world.World;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.resources.IReloadableResourceManager;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.resource.IResourceType;
|
||||
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
||||
import net.minecraftforge.resource.VanillaResourceType;
|
||||
|
||||
public class Backend {
|
||||
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 FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
|
||||
|
||||
private static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
|
||||
private static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
|
||||
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
|
||||
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
|
||||
|
||||
private static boolean enabled;
|
||||
|
||||
|
@ -102,85 +92,13 @@ public class Backend {
|
|||
IResourceManager manager = mc.getResourceManager();
|
||||
|
||||
if (manager instanceof IReloadableResourceManager) {
|
||||
ISelectiveResourceReloadListener listener = Backend::onResourceManagerReload;
|
||||
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
|
||||
((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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ public class CommonAttributes {
|
|||
public static final VertexAttribSpec VEC2 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2);
|
||||
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 UV = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2);
|
||||
|
||||
|
|
|
@ -12,18 +12,11 @@ public class GlShader extends GlObject {
|
|||
public final ResourceLocation name;
|
||||
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.name = name;
|
||||
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.glCompileShader(handle);
|
||||
|
||||
|
|
|
@ -147,9 +147,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends TileEntityBehaviour> T getBehaviour(BehaviourType<T> type) {
|
||||
if (behaviours.containsKey(type))
|
||||
return (T) behaviours.get(type);
|
||||
return null;
|
||||
return (T) behaviours.get(type);
|
||||
}
|
||||
|
||||
protected boolean isItemHandlerCap(Capability<?> cap) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#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;
|
||||
|
@ -10,7 +14,7 @@ attribute vec2 aLight;
|
|||
attribute vec3 aNetworkTint;
|
||||
attribute float aSpeed;
|
||||
attribute float aOffset;
|
||||
attribute vec3 aInstanceRot;
|
||||
attribute vec4 aInstanceRot;
|
||||
attribute vec2 aSourceTexture;
|
||||
attribute vec4 aScrollTexture;
|
||||
attribute float aScrollMult;
|
||||
|
@ -38,54 +42,24 @@ uniform vec3 uCameraPos;
|
|||
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 localRotation() {
|
||||
vec3 rot = fract(aInstanceRot / 360.) * PI * 2.;
|
||||
return rotation(rot);
|
||||
}
|
||||
|
||||
void main() {
|
||||
mat4 localRotation = localRotation();
|
||||
vec4 worldPos = localRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.);
|
||||
vec3 rotated = rotateVertexByQuat(aPos - .5, aInstanceRot) + aInstancePos + .5;
|
||||
|
||||
#ifdef CONTRAPTION
|
||||
vec4 worldPos = vec4(rotated, 1.);
|
||||
|
||||
vec3 norm = rotateVertexByQuat(aNormal, aInstanceRot);
|
||||
|
||||
#ifdef CONTRAPTION
|
||||
worldPos = uModel * worldPos;
|
||||
mat4 normalMat = uModel * localRotation;
|
||||
norm = normalize(modelToNormal(uModel) * norm);
|
||||
|
||||
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
|
||||
#if defined(USE_FOG)
|
||||
FragDistance = length(worldPos.xyz);
|
||||
#endif
|
||||
#else
|
||||
mat4 normalMat = localRotation;
|
||||
|
||||
#if defined(USE_FOG)
|
||||
#elif defined(USE_FOG)
|
||||
FragDistance = length(worldPos.xyz - uCameraPos);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz;
|
||||
#endif
|
||||
|
||||
float scrollSize = aScrollTexture.w - aScrollTexture.y;
|
||||
float scroll = fract(aSpeed * uTime / (31.5 * 16.) + aOffset) * scrollSize * aScrollMult;
|
|
@ -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.);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
#version 110
|
||||
#define PI 3.1415926538
|
||||
|
||||
#flwinclude <"create:core/matutils.glsl">
|
||||
#flwinclude <"create:core/diffuse.glsl">
|
||||
|
||||
attribute vec3 aPos;
|
||||
attribute vec3 aNormal;
|
||||
attribute vec2 aTexCoords;
|
||||
|
@ -27,24 +30,6 @@ uniform vec3 uCameraPos;
|
|||
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.);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 viewPos = uModel * vec4(aPos, 1.);
|
||||
|
|
@ -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.);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
#version 110
|
||||
#define PI 3.1415926538
|
||||
|
||||
#flwinclude <"create:core/matutils.glsl">
|
||||
#flwinclude <"create:core/quaternion.glsl">
|
||||
#flwinclude <"create:core/diffuse.glsl">
|
||||
|
||||
attribute vec3 aPos;
|
||||
attribute vec3 aNormal;
|
||||
attribute vec2 aTexCoords;
|
||||
|
@ -40,24 +44,6 @@ uniform vec3 uCameraPos;
|
|||
varying float FragDistance;
|
||||
#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) {
|
||||
return fract(degrees / 360.) * PI * 2.;
|
||||
}
|
||||
|
@ -72,35 +58,32 @@ float getFlapAngle() {
|
|||
float which = step(0., aFlapness);
|
||||
float degrees = which * halfAngle + (1. - which) * angle; // branchless conditional multiply
|
||||
|
||||
return -toRad(degrees);
|
||||
return degrees;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float flapAngle = getFlapAngle();
|
||||
|
||||
mat4 orientation = rotate(vec3(0., 1., 0.), toRad(aHorizontalAngle));
|
||||
mat4 flapRotation = rotate(vec3(1., 0., 0.), flapAngle);
|
||||
vec4 orientation = quat(vec3(0., 1., 0.), -aHorizontalAngle);
|
||||
vec4 flapRotation = quat(vec3(1., 0., 0.), flapAngle);
|
||||
|
||||
vec4 worldPos = flapRotation * vec4(aPos - aPivot, 1.) + vec4(aPivot + aSegmentOffset, 0.);
|
||||
worldPos = orientation * vec4(worldPos.xyz - .5, 1.) + vec4(aInstancePos + .5, 0.);
|
||||
vec3 rotated = rotateVertexByQuat(aPos - aPivot, flapRotation) + aPivot + aSegmentOffset;
|
||||
rotated = rotateVertexByQuat(rotated - .5, orientation) + aInstancePos + .5;
|
||||
|
||||
vec4 worldPos = vec4(rotated, 1.);
|
||||
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, flapRotation), orientation);
|
||||
|
||||
#ifdef CONTRAPTION
|
||||
worldPos = uModel * worldPos;
|
||||
mat4 normalMat = uModel * orientation * flapRotation;
|
||||
norm = modelToNormal(uModel) * norm;
|
||||
|
||||
BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize;
|
||||
#if defined(USE_FOG)
|
||||
FragDistance = length(worldPos.xyz);
|
||||
#endif
|
||||
#else
|
||||
mat4 normalMat = orientation * flapRotation;
|
||||
|
||||
#if defined(USE_FOG)
|
||||
#elif defined(USE_FOG)
|
||||
FragDistance = length(worldPos.xyz - uCameraPos);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz;
|
||||
|
||||
Diffuse = diffuse(norm);
|
||||
TexCoords = aTexCoords;
|
|
@ -1,5 +1,8 @@
|
|||
#version 110
|
||||
|
||||
#flwinclude <"create:core/matutils.glsl">
|
||||
#flwinclude <"create:core/diffuse.glsl">
|
||||
|
||||
attribute vec3 aPos;
|
||||
attribute vec3 aNormal;
|
||||
attribute vec2 aTexCoords;
|
||||
|
@ -32,23 +35,6 @@ uniform vec3 uCameraPos;
|
|||
varying float FragDistance;
|
||||
#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() {
|
||||
vec4 worldPos = aTransform * vec4(aPos, 1.);
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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.);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in a new issue