mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
Fix projection matrix bug
- Copy the projection matrix when vanilla would be uploading it to GL. - This should account for just about everything. Unrelated to the fix: - Shader programs now have more flexibility in specialization. - Accomplished with IMultiProgram. - Remove unnecessary SHADER_DEBUG_OUTPUT boolean.
This commit is contained in:
parent
edb1b59f41
commit
f2c6afdcb3
12 changed files with 127 additions and 88 deletions
|
@ -186,7 +186,6 @@ public class ClientEvents {
|
|||
ms.pop();
|
||||
|
||||
RenderWork.runAll();
|
||||
FastRenderDispatcher.endFrame();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -49,7 +49,7 @@ public class RenderHooksMixin {
|
|||
Matrix4f viewProjection = stack.peek()
|
||||
.getModel()
|
||||
.copy();
|
||||
viewProjection.multiplyBackward(FastRenderDispatcher.getProjectionMatrix());
|
||||
viewProjection.multiplyBackward(Backend.projectionMatrix);
|
||||
|
||||
FastRenderDispatcher.renderLayer(type, viewProjection, camX, camY, camZ);
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.simibubi.create.foundation.mixin;
|
||||
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.simibubi.create.foundation.render.backend.Backend;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class StoreProjectionMatrixMixin {
|
||||
|
||||
@Inject(method = "loadProjectionMatrix", at = @At("TAIL"))
|
||||
private void onProjectionMatrixLoad(Matrix4f projection, CallbackInfo ci) {
|
||||
Backend.projectionMatrix = projection.copy();
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import org.lwjgl.opengl.GLCapabilities;
|
|||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.render.backend.gl.GlFog;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramGroup;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.IMultiProgram;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec;
|
||||
import com.simibubi.create.foundation.render.backend.gl.versioned.GlCompat;
|
||||
import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld;
|
||||
|
@ -20,13 +20,17 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.resources.IReloadableResourceManager;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
||||
|
||||
public class Backend {
|
||||
public static final Boolean SHADER_DEBUG_OUTPUT = true;
|
||||
|
||||
public static final Logger log = LogManager.getLogger(Backend.class);
|
||||
|
||||
public static final ShaderLoader shaderLoader = new ShaderLoader();
|
||||
|
||||
public static Matrix4f projectionMatrix = new Matrix4f();
|
||||
|
||||
public static GLCapabilities capabilities;
|
||||
public static GlCompat compat;
|
||||
|
||||
|
@ -34,7 +38,7 @@ public class Backend {
|
|||
private static boolean enabled;
|
||||
|
||||
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
|
||||
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
|
||||
static final Map<ProgramSpec<?>, IMultiProgram<?>> programs = new HashMap<>();
|
||||
|
||||
public Backend() {
|
||||
throw new IllegalStateException();
|
||||
|
@ -54,7 +58,7 @@ public class Backend {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
|
||||
return (P) programs.get(spec).get(GlFog.getFogMode());
|
||||
return (P) programs.get(spec).get();
|
||||
}
|
||||
|
||||
public static boolean isFlywheelWorld(World world) {
|
||||
|
@ -89,7 +93,7 @@ public class Backend {
|
|||
IResourceManager manager = mc.getResourceManager();
|
||||
|
||||
if (manager instanceof IReloadableResourceManager) {
|
||||
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
|
||||
ISelectiveResourceReloadListener listener = shaderLoader::onResourceManagerReload;
|
||||
((IReloadableResourceManager) manager).addReloadListener(listener);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,6 @@ public class FastRenderDispatcher {
|
|||
|
||||
public static WorldAttached<ConcurrentHashMap.KeySetView<TileEntity, Boolean>> queuedUpdates = new WorldAttached<>(ConcurrentHashMap::newKeySet);
|
||||
|
||||
private static Matrix4f projectionMatrixThisFrame = null;
|
||||
|
||||
public static void endFrame() {
|
||||
projectionMatrixThisFrame = null;
|
||||
}
|
||||
|
||||
public static void enqueueUpdate(TileEntity te) {
|
||||
queuedUpdates.get(te.getWorld()).add(te);
|
||||
}
|
||||
|
@ -82,45 +76,4 @@ public class FastRenderDispatcher {
|
|||
|
||||
layer.endDrawing();
|
||||
}
|
||||
|
||||
// copied from GameRenderer.renderWorld
|
||||
public static Matrix4f getProjectionMatrix() {
|
||||
if (projectionMatrixThisFrame != null) return projectionMatrixThisFrame;
|
||||
|
||||
float partialTicks = AnimationTickHolder.getPartialTicks();
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
GameRenderer gameRenderer = mc.gameRenderer;
|
||||
ClientPlayerEntity player = mc.player;
|
||||
|
||||
MatrixStack matrixstack = new MatrixStack();
|
||||
matrixstack.peek()
|
||||
.getModel()
|
||||
.multiply(gameRenderer.getBasicProjectionMatrix(gameRenderer.getActiveRenderInfo(), partialTicks, true));
|
||||
gameRenderer.bobViewWhenHurt(matrixstack, partialTicks);
|
||||
if (mc.gameSettings.viewBobbing) {
|
||||
gameRenderer.bobView(matrixstack, partialTicks);
|
||||
}
|
||||
|
||||
float portalTime = MathHelper.lerp(partialTicks, player.prevTimeInPortal, player.timeInPortal);
|
||||
if (portalTime > 0.0F) {
|
||||
int i = 20;
|
||||
if (player.isPotionActive(Effects.NAUSEA)) {
|
||||
i = 7;
|
||||
}
|
||||
|
||||
float f1 = 5.0F / (portalTime * portalTime + 5.0F) - portalTime * 0.04F;
|
||||
f1 = f1 * f1;
|
||||
Vector3f vector3f = new Vector3f(0.0F, MathHelper.SQRT_2 / 2.0F, MathHelper.SQRT_2 / 2.0F);
|
||||
matrixstack.multiply(vector3f.getDegreesQuaternion(((float)gameRenderer.rendererUpdateCount + partialTicks) * (float)i));
|
||||
matrixstack.scale(1.0F / f1, 1.0F, 1.0F);
|
||||
float f2 = -((float)gameRenderer.rendererUpdateCount + partialTicks) * (float)i;
|
||||
matrixstack.multiply(vector3f.getDegreesQuaternion(f2));
|
||||
}
|
||||
|
||||
Matrix4f matrix4f = matrixstack.peek().getModel();
|
||||
gameRenderer.loadProjectionMatrix(matrix4f);
|
||||
|
||||
projectionMatrixThisFrame = matrix4f;
|
||||
return projectionMatrixThisFrame;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,11 @@ import org.lwjgl.system.MemoryUtil;
|
|||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.simibubi.create.foundation.render.backend.gl.GlFogMode;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.SingleProgram;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.GlShader;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramGroup;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.FogSensitiveProgram;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.IMultiProgram;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants;
|
||||
import com.simibubi.create.foundation.render.backend.gl.shader.ShaderType;
|
||||
|
@ -45,9 +47,12 @@ 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<>();
|
||||
// #flwinclude <"valid_namespace:valid/path_to_file.glsl">
|
||||
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
|
||||
|
||||
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
|
||||
final Map<ResourceLocation, String> shaderSource = new HashMap<>();
|
||||
|
||||
void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
|
||||
if (predicate.test(VanillaResourceType.SHADERS)) {
|
||||
OptifineHandler.refresh();
|
||||
Backend.refresh();
|
||||
|
@ -56,16 +61,16 @@ public class ShaderLoader {
|
|||
shaderSource.clear();
|
||||
loadShaderSources(manager);
|
||||
|
||||
Backend.programs.values().forEach(ProgramGroup::delete);
|
||||
Backend.programs.values().forEach(IMultiProgram::delete);
|
||||
Backend.programs.clear();
|
||||
Backend.registry.values().forEach(ShaderLoader::loadProgram);
|
||||
Backend.registry.values().forEach(this::loadProgramFromSpec);
|
||||
|
||||
Backend.log.info("Loaded all shader programs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadShaderSources(IResourceManager manager){
|
||||
private void loadShaderSources(IResourceManager manager){
|
||||
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
|
||||
for (String ext : EXTENSIONS) {
|
||||
if (s.endsWith(ext)) return true;
|
||||
|
@ -89,19 +94,26 @@ public class ShaderLoader {
|
|||
}
|
||||
}
|
||||
|
||||
static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(S programSpec) {
|
||||
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
|
||||
private <P extends GlProgram, S extends ProgramSpec<P>> void loadProgramFromSpec(S programSpec) {
|
||||
|
||||
for (GlFogMode fogMode : GlFogMode.values()) {
|
||||
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
|
||||
if (programSpec.fogSensitive) {
|
||||
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
|
||||
|
||||
for (GlFogMode fogMode : GlFogMode.values()) {
|
||||
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
|
||||
}
|
||||
|
||||
Backend.programs.put(programSpec, new FogSensitiveProgram<>(programGroup));
|
||||
} else {
|
||||
P program = loadProgram(programSpec, GlFogMode.NONE);
|
||||
|
||||
Backend.programs.put(programSpec, new SingleProgram<>(program));
|
||||
}
|
||||
|
||||
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) {
|
||||
private <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(S programSpec, GlFogMode fogMode) {
|
||||
GlShader vert = null;
|
||||
GlShader frag = null;
|
||||
try {
|
||||
|
@ -124,16 +136,14 @@ public class ShaderLoader {
|
|||
}
|
||||
}
|
||||
|
||||
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
|
||||
|
||||
private static String processIncludes(ResourceLocation baseName, String source) {
|
||||
private 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) {
|
||||
private Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
|
||||
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
|
||||
|
||||
Matcher matcher = includePattern.matcher(line);
|
||||
|
@ -156,7 +166,7 @@ public class ShaderLoader {
|
|||
});
|
||||
}
|
||||
|
||||
private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
|
||||
private GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
|
||||
String source = shaderSource.get(name);
|
||||
|
||||
source = processIncludes(name, source);
|
||||
|
@ -168,7 +178,7 @@ public class ShaderLoader {
|
|||
return new GlShader(type, name, source);
|
||||
}
|
||||
|
||||
public static String readToString(InputStream is) {
|
||||
public String readToString(InputStream is) {
|
||||
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
|
||||
ByteBuffer bytebuffer = null;
|
||||
|
||||
|
@ -189,7 +199,7 @@ public class ShaderLoader {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
|
||||
public ByteBuffer readToBuffer(InputStream is) throws IOException {
|
||||
ByteBuffer bytebuffer;
|
||||
if (is instanceof FileInputStream) {
|
||||
FileInputStream fileinputstream = (FileInputStream)is;
|
||||
|
|
|
@ -2,21 +2,25 @@ package com.simibubi.create.foundation.render.backend.gl.shader;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.simibubi.create.foundation.render.backend.gl.GlFog;
|
||||
import com.simibubi.create.foundation.render.backend.gl.GlFogMode;
|
||||
|
||||
public class ProgramGroup<P extends GlProgram> {
|
||||
public class FogSensitiveProgram<P extends GlProgram> implements IMultiProgram<P> {
|
||||
|
||||
private final Map<GlFogMode, P> programs;
|
||||
|
||||
public ProgramGroup(Map<GlFogMode, P> programs) {
|
||||
public FogSensitiveProgram(Map<GlFogMode, P> programs) {
|
||||
this.programs = programs;
|
||||
}
|
||||
|
||||
public P get(GlFogMode fogMode) {
|
||||
return programs.get(fogMode);
|
||||
@Override
|
||||
public P get() {
|
||||
return programs.get(GlFog.getFogMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
programs.values().forEach(GlProgram::delete);
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,7 @@ public abstract class GlProgram extends GlObject {
|
|||
public int getUniformLocation(String uniform) {
|
||||
int index = GL20.glGetUniformLocation(this.handle(), uniform);
|
||||
|
||||
if (index < 0 && Backend.SHADER_DEBUG_OUTPUT) {
|
||||
if (index < 0) {
|
||||
Backend.log.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name);
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ public abstract class GlProgram extends GlObject {
|
|||
|
||||
String log = GL20.glGetProgramInfoLog(this.program);
|
||||
|
||||
if (!log.isEmpty() && Backend.SHADER_DEBUG_OUTPUT) {
|
||||
if (!log.isEmpty()) {
|
||||
Backend.log.debug("Program link log for " + this.name + ": " + log);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.simibubi.create.foundation.render.backend.gl.shader;
|
||||
|
||||
/**
|
||||
* Encapsulates any number of shader programs for use in similar contexts.
|
||||
* Allows the implementor to choose which shader program to use based on arbitrary state.
|
||||
*
|
||||
* @param <P>
|
||||
*/
|
||||
public interface IMultiProgram<P extends GlProgram> {
|
||||
|
||||
/**
|
||||
* Get the shader program most suited for the current game state.
|
||||
* @return The one true program.
|
||||
*/
|
||||
P get();
|
||||
|
||||
/**
|
||||
* Delete all shader programs encapsulated by your implementation.
|
||||
*/
|
||||
void delete();
|
||||
}
|
|
@ -20,6 +20,8 @@ public class ProgramSpec<P extends GlProgram> {
|
|||
|
||||
public final ArrayList<IVertexAttrib> attributes;
|
||||
|
||||
public final boolean fogSensitive;
|
||||
|
||||
public static <P extends GlProgram> Builder<P> builder(String name, GlProgram.ProgramFactory<P> factory) {
|
||||
return builder(new ResourceLocation(Create.ID, name), factory);
|
||||
}
|
||||
|
@ -28,16 +30,16 @@ public class ProgramSpec<P extends GlProgram> {
|
|||
return new Builder<>(name, factory);
|
||||
}
|
||||
|
||||
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, GlProgram.ProgramFactory<P> factory, ShaderConstants defines, ArrayList<IVertexAttrib> attributes) {
|
||||
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, GlProgram.ProgramFactory<P> factory, ShaderConstants defines, ArrayList<IVertexAttrib> attributes, boolean fogSensitive) {
|
||||
this.name = name;
|
||||
this.vert = vert;
|
||||
this.frag = frag;
|
||||
this.defines = defines;
|
||||
|
||||
|
||||
this.factory = factory;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
this.fogSensitive = fogSensitive;
|
||||
}
|
||||
|
||||
public ResourceLocation getVert() {
|
||||
return vert;
|
||||
|
@ -51,6 +53,7 @@ public class ProgramSpec<P extends GlProgram> {
|
|||
private ResourceLocation vert;
|
||||
private ResourceLocation frag;
|
||||
private ShaderConstants defines = ShaderConstants.EMPTY;
|
||||
private boolean fogSensitive = true;
|
||||
|
||||
private final ResourceLocation name;
|
||||
private final GlProgram.ProgramFactory<P> factory;
|
||||
|
@ -77,13 +80,18 @@ public class ProgramSpec<P extends GlProgram> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public <A extends Enum<A> & IVertexAttrib> Builder<P> addAttributes(Class<A> attributeEnum) {
|
||||
public Builder<P> setFogSensitive(boolean fogSensitive) {
|
||||
this.fogSensitive = fogSensitive;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <A extends Enum<A> & IVertexAttrib> Builder<P> addAttributes(Class<A> attributeEnum) {
|
||||
attributes.addAll(Arrays.asList(attributeEnum.getEnumConstants()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProgramSpec<P> createProgramSpec() {
|
||||
return new ProgramSpec<>(name, vert, frag, factory, defines, attributes);
|
||||
return new ProgramSpec<>(name, vert, frag, factory, defines, attributes, fogSensitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package com.simibubi.create.foundation.render.backend.gl.shader;
|
||||
|
||||
public class SingleProgram<P extends GlProgram> implements IMultiProgram<P> {
|
||||
final P program;
|
||||
|
||||
public SingleProgram(P program) {
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P get() {
|
||||
return program;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
program.delete();
|
||||
}
|
||||
}
|
|
@ -13,10 +13,11 @@
|
|||
"RenderHooksMixin",
|
||||
"ShaderCloseMixin",
|
||||
"TileRemoveMixin",
|
||||
"EntityContraptionInteractionMixin"
|
||||
"EntityContraptionInteractionMixin",
|
||||
"StoreProjectionMatrixMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"minVersion": "0.8"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue