mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-22 23:26:25 -04:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1585f60cc | ||
|
|
f114a107ca | ||
|
|
f0fdd5dc7e |
@@ -9,6 +9,8 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraHalo;
|
||||
import com.cobblemon.mod.common.integration.IrisCompatibility;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
@@ -48,6 +50,19 @@ public class GameRendererMixin {
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "renderLevel",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/renderer/LevelRenderer;renderLevel(Lnet/minecraft/client/DeltaTracker;ZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V",
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
private void cobblemon$drawAfterShaderPack(DeltaTracker deltaTracker, CallbackInfo ci) {
|
||||
IrisCompatibility.INSTANCE.drawDeferred();
|
||||
TeraHalo.INSTANCE.draw();
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
|
||||
at = @At(
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraHalo;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
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;
|
||||
|
||||
@Mixin(LevelRenderer.class)
|
||||
public class LevelRendererMixin {
|
||||
@Inject(method = "initOutline", at = @At("TAIL"))
|
||||
private void cobblemon$loadTeraHalo(CallbackInfo ci) {
|
||||
TeraHalo.INSTANCE.load();
|
||||
}
|
||||
|
||||
@Inject(method = "resize", at = @At("TAIL"))
|
||||
private void cobblemon$resizeTeraHalo(int width, int height, CallbackInfo ci) {
|
||||
TeraHalo.INSTANCE.resize(width, height);
|
||||
}
|
||||
|
||||
@Inject(method = "close", at = @At("TAIL"))
|
||||
private void cobblemon$closeTeraHalo(CallbackInfo ci) {
|
||||
TeraHalo.INSTANCE.close();
|
||||
}
|
||||
}
|
||||
+11
@@ -53,6 +53,9 @@ import net.minecraft.Util
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import com.cobblemon.mod.common.integration.IrisCompatibility
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraHalo
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraRender
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -175,6 +178,9 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
@Transient
|
||||
var currentState: PosableState? = null
|
||||
|
||||
@Transient
|
||||
var tera: TeraRender? = null
|
||||
|
||||
@Transient
|
||||
val functions = QueryStruct(this.animationFunctions())
|
||||
|
||||
@@ -264,6 +270,7 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
currentLayers = emptyList()
|
||||
bufferProvider = null
|
||||
currentState = null
|
||||
tera = null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,6 +497,10 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
)
|
||||
stack.popPose()
|
||||
}
|
||||
tera?.let { tera ->
|
||||
IrisCompatibility.renderAfterShaderPack(provider, tera.overlay) { rootPart.render(context, stack, it, packedLight, packedOverlay, tera.tint) }
|
||||
TeraHalo.record(tera.halo) { rootPart.render(context, stack, it, packedLight, packedOverlay, tera.tint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -545,12 +545,11 @@ abstract class PosableState : Schedulable {
|
||||
primaryAnimation?.animation?.applyEffects(entity, this, previousSeconds, newSeconds)
|
||||
currentModel?.let { model ->
|
||||
val pose = currentPose?.let { model.poses[it] }
|
||||
// Effects start playing from pose animations as long as the intensity is above 0.5. Pretty sloppy honestly.
|
||||
pose?.animations
|
||||
?.asSequence()
|
||||
?.filter { it.condition(this) }
|
||||
?.forEach {
|
||||
it.applyEffects(entity, this, previousSeconds, newSeconds)
|
||||
}
|
||||
?.filter { shouldIdleRun(it, 0.5F) && it.condition(this) }
|
||||
?.forEach { it.applyEffects(entity, this, previousSeconds, newSeconds) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BE
|
||||
import com.cobblemon.mod.common.client.keybind.boundKey
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
|
||||
import com.cobblemon.mod.common.client.render.item.HeldItemRenderer
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraOverlay
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PosablePokemonEntityModel
|
||||
@@ -144,6 +145,7 @@ class PokemonRenderer(
|
||||
}
|
||||
|
||||
modelNow.setLayerContext(buffer, clientDelegate, VaryingModelRepository.getLayers(entity.pokemon.species.resourceIdentifier, clientDelegate))
|
||||
modelNow.tera = TeraOverlay.forAspects(entity.aspects, getTextureLocation(entity))
|
||||
|
||||
|
||||
if (entity.passengers.isNotEmpty()) {
|
||||
|
||||
+4
@@ -20,6 +20,7 @@ object CobblemonShaders {
|
||||
lateinit var PARTICLE_BLEND: ShaderInstance
|
||||
// This is Material.ALPHA. Weird internal name for "alphatest" shader.
|
||||
lateinit var PARTICLE_CUTOUT: ShaderInstance
|
||||
lateinit var TERA: ShaderInstance
|
||||
|
||||
private fun registerShader(shader: (ResourceProvider) -> ShaderRegistryData, callback: Consumer<ShaderInstance>){
|
||||
SHADERS_TO_REGISTER.add(Pair(shader, callback))
|
||||
@@ -31,5 +32,8 @@ object CobblemonShaders {
|
||||
registerShader({rm: ResourceProvider -> ShaderRegistryData(rm, cobblemonResource("particle_cutout"), DefaultVertexFormat.PARTICLE) }) {
|
||||
PARTICLE_CUTOUT = it
|
||||
}
|
||||
registerShader({rm: ResourceProvider -> ShaderRegistryData(rm, cobblemonResource("tera"), DefaultVertexFormat.NEW_ENTITY) }) {
|
||||
TERA = it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.shader
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.integration.DeferredMeshes
|
||||
import com.cobblemon.mod.common.integration.IrisCompatibility
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.PostChain
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object TeraHalo {
|
||||
private val CHAIN_LOCATION = cobblemonResource("shaders/post/tera_halo.json")
|
||||
|
||||
private val deferred = DeferredMeshes()
|
||||
private var chain: PostChain? = null
|
||||
|
||||
private val MASK_TARGET = RenderStateShard.OutputStateShard(
|
||||
"cobblemon_tera_halo_mask",
|
||||
{ chain?.getTempTarget("mask")?.bindWrite(false) },
|
||||
{ Minecraft.getInstance().mainRenderTarget.bindWrite(false) }
|
||||
)
|
||||
|
||||
private val renderType = Util.memoize { texture: ResourceLocation ->
|
||||
RenderType.create(
|
||||
"cobblemon_tera_halo",
|
||||
DefaultVertexFormat.POSITION_TEX_COLOR,
|
||||
VertexFormat.Mode.QUADS,
|
||||
256,
|
||||
false,
|
||||
false,
|
||||
RenderType.CompositeState.builder()
|
||||
.setShaderState(RenderStateShard.ShaderStateShard(GameRenderer::getRendertypeOutlineShader))
|
||||
.setTextureState(RenderStateShard.TextureStateShard(texture, false, false))
|
||||
.setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST)
|
||||
.setCullState(RenderStateShard.CULL)
|
||||
.setWriteMaskState(RenderStateShard.COLOR_WRITE)
|
||||
.setOutputState(MASK_TARGET)
|
||||
.createCompositeState(false)
|
||||
)
|
||||
}
|
||||
|
||||
fun renderType(texture: ResourceLocation): RenderType = renderType.apply(texture)
|
||||
|
||||
fun record(renderType: RenderType, draw: (VertexConsumer) -> Unit) {
|
||||
if (IrisCompatibility.isRenderingShadowPass()) return
|
||||
deferred.record(renderType, draw)
|
||||
}
|
||||
|
||||
fun draw() {
|
||||
if (deferred.isEmpty()) return
|
||||
val chain = chain ?: return deferred.discard()
|
||||
val main = Minecraft.getInstance().mainRenderTarget
|
||||
|
||||
val mask = chain.getTempTarget("mask")
|
||||
mask.setClearColor(0F, 0F, 0F, 0F)
|
||||
mask.clear(Minecraft.ON_OSX)
|
||||
mask.copyDepthFrom(main)
|
||||
deferred.drawAll()
|
||||
|
||||
chain.process(0F)
|
||||
main.bindWrite(false)
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR)
|
||||
chain.getTempTarget("swap").blitToScreen(main.width, main.height, false)
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
}
|
||||
|
||||
|
||||
fun load() {
|
||||
close()
|
||||
val minecraft = Minecraft.getInstance()
|
||||
chain = try {
|
||||
PostChain(minecraft.textureManager, minecraft.resourceManager, minecraft.mainRenderTarget, CHAIN_LOCATION).also {
|
||||
it.resize(minecraft.mainRenderTarget.width, minecraft.mainRenderTarget.height)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Failed to load tera halo post chain $CHAIN_LOCATION", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun resize(width: Int, height: Int) {
|
||||
chain?.resize(width, height)
|
||||
}
|
||||
|
||||
fun close() {
|
||||
chain?.close()
|
||||
chain = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.shader
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
data class TeraRender(val overlay: RenderType, val halo: RenderType, val tint: Int)
|
||||
|
||||
object TeraOverlay {
|
||||
private const val ASPECT = "terastal"
|
||||
|
||||
// Adds the shader's rgb and scales what's already drawn by its alpha, so facets can shade the base model.
|
||||
// Destination alpha is left alone
|
||||
private val TERA_TRANSPARENCY = RenderStateShard.TransparencyStateShard(
|
||||
"cobblemon_tera_transparency",
|
||||
{
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.blendFuncSeparate(
|
||||
GlStateManager.SourceFactor.ONE,
|
||||
GlStateManager.DestFactor.SRC_ALPHA,
|
||||
GlStateManager.SourceFactor.ZERO,
|
||||
GlStateManager.DestFactor.ONE
|
||||
)
|
||||
},
|
||||
{
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
}
|
||||
)
|
||||
|
||||
private val renderType = Util.memoize { texture: ResourceLocation ->
|
||||
RenderType.create(
|
||||
"cobblemon_tera",
|
||||
DefaultVertexFormat.NEW_ENTITY,
|
||||
VertexFormat.Mode.QUADS,
|
||||
256,
|
||||
true,
|
||||
true,
|
||||
RenderType.CompositeState.builder()
|
||||
.setShaderState(RenderStateShard.ShaderStateShard { CobblemonShaders.TERA })
|
||||
.setTextureState(RenderStateShard.TextureStateShard(texture, false, false))
|
||||
.setTransparencyState(TERA_TRANSPARENCY)
|
||||
.setLightmapState(RenderStateShard.LIGHTMAP)
|
||||
.setOverlayState(RenderStateShard.OVERLAY)
|
||||
.setCullState(RenderStateShard.CULL)
|
||||
.setWriteMaskState(RenderStateShard.COLOR_WRITE)
|
||||
.createCompositeState(false)
|
||||
)
|
||||
}
|
||||
|
||||
fun forAspects(aspects: Set<String>, texture: ResourceLocation): TeraRender? {
|
||||
val aspect = aspects.firstOrNull { it == ASPECT || it.startsWith("$ASPECT-") } ?: return null
|
||||
val hue = ElementalTypes.get(aspect.removePrefix(ASPECT).removePrefix("-"))?.hue
|
||||
return TeraRender(renderType.apply(texture), TeraHalo.renderType(texture), 0xFF000000.toInt() or (hue ?: 0xFFFFFF))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.integration
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder
|
||||
import com.mojang.blaze3d.vertex.ByteBufferBuilder
|
||||
import com.mojang.blaze3d.vertex.MeshData
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexSorting
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import org.joml.Matrix4f
|
||||
|
||||
object IrisCompatibility {
|
||||
private val api = runCatching { Class.forName("net.irisshaders.iris.api.v0.IrisApi") }.getOrNull()
|
||||
private val instance = api?.getMethod("getInstance")?.invoke(null)
|
||||
private val shaderPackInUse = api?.getMethod("isShaderPackInUse")
|
||||
private val renderingShadowPass = api?.getMethod("isRenderingShadowPass")
|
||||
|
||||
private val deferred = DeferredMeshes()
|
||||
|
||||
fun isShaderPackInUse() = shaderPackInUse?.invoke(instance) == true
|
||||
|
||||
fun isRenderingShadowPass() = renderingShadowPass?.invoke(instance) == true
|
||||
|
||||
fun renderAfterShaderPack(provider: MultiBufferSource, renderType: RenderType, draw: (VertexConsumer) -> Unit) {
|
||||
if (!isShaderPackInUse()) return draw(provider.getBuffer(renderType))
|
||||
if (isRenderingShadowPass()) return
|
||||
|
||||
deferred.record(renderType, draw)
|
||||
}
|
||||
|
||||
fun drawDeferred() {
|
||||
if (deferred.isEmpty()) return
|
||||
Minecraft.getInstance().mainRenderTarget.bindWrite(false)
|
||||
deferred.drawAll()
|
||||
}
|
||||
}
|
||||
|
||||
/** Meshes recorded during level rendering, drawn later with the camera matrices they were recorded under. */
|
||||
class DeferredMeshes {
|
||||
private val bytes = ByteBufferBuilder(1 shl 18)
|
||||
private val meshes = mutableListOf<Pair<RenderType, MeshData>>()
|
||||
private val modelView = Matrix4f()
|
||||
private val projection = Matrix4f()
|
||||
|
||||
fun isEmpty() = meshes.isEmpty()
|
||||
|
||||
fun record(renderType: RenderType, draw: (VertexConsumer) -> Unit) {
|
||||
if (meshes.isEmpty()) {
|
||||
modelView.set(RenderSystem.getModelViewMatrix())
|
||||
projection.set(RenderSystem.getProjectionMatrix())
|
||||
}
|
||||
val builder = BufferBuilder(bytes, renderType.mode(), renderType.format())
|
||||
draw(builder)
|
||||
builder.build()?.let { meshes += renderType to it }
|
||||
}
|
||||
|
||||
fun drawAll() {
|
||||
RenderSystem.backupProjectionMatrix()
|
||||
RenderSystem.setProjectionMatrix(projection, VertexSorting.DISTANCE_TO_ORIGIN)
|
||||
val stack = RenderSystem.getModelViewStack()
|
||||
stack.pushMatrix()
|
||||
stack.set(modelView)
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
|
||||
meshes.forEach { (renderType, mesh) -> renderType.draw(mesh) }
|
||||
meshes.clear()
|
||||
|
||||
stack.popMatrix()
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
RenderSystem.restoreProjectionMatrix()
|
||||
}
|
||||
|
||||
fun discard() {
|
||||
meshes.forEach { it.second.close() }
|
||||
meshes.clear()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
#version 150
|
||||
|
||||
#moj_import <fog.glsl>
|
||||
|
||||
uniform sampler2D Sampler0;
|
||||
|
||||
uniform vec4 ColorModulator;
|
||||
uniform float FogStart;
|
||||
uniform float FogEnd;
|
||||
uniform float GameTime;
|
||||
|
||||
in float vertexDistance;
|
||||
in vec4 vertexColor;
|
||||
in vec4 lightMapColor;
|
||||
in float vanillaLight;
|
||||
in vec2 texCoord0;
|
||||
in vec3 viewPos;
|
||||
in vec3 viewNormal;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
const float CELL_SIZE_TEXELS = 16.0 / 3.0;
|
||||
const float FACET_TILT = 0.7;
|
||||
const bool SNAP_TO_TEXELS = true;
|
||||
const int DISTANCE_METRIC = 0;
|
||||
|
||||
const float AMBIENT = 0.5;
|
||||
const float SPEC_SHININESS = 5.0;
|
||||
const float SPEC_STRENGTH = 0.4;
|
||||
const float SPEC_WHITENESS = 0.25;
|
||||
const float SELF_LIGHT = 0.85;
|
||||
const vec3 LIGHT_DIR = vec3(0.5, 0.8, 0.6);
|
||||
|
||||
const float SHADE_SPREAD = 2.0;
|
||||
const float SHEEN_STRENGTH = 0.25;
|
||||
const float FILM_IOR = 1.45;
|
||||
const float FILM_THICKNESS_MIN = 250.0;
|
||||
const float FILM_THICKNESS_MAX = 550.0;
|
||||
const float FILM_WAVELENGTH = 550.0;
|
||||
|
||||
const float SHIMMER_NM = 40.0;
|
||||
const float SHIMMER_SPEED = 1.5;
|
||||
|
||||
const float GLIMMER_PERIOD = 3.0;
|
||||
const float GLIMMER_SHARPNESS = 60.0;
|
||||
const float GLIMMER_STRENGTH = 0.3;
|
||||
|
||||
const float SECONDS_PER_DAY = 1200.0;
|
||||
const float PI = 3.14159265;
|
||||
const float TAU = 6.28318531;
|
||||
|
||||
vec2 random2(vec2 p) {
|
||||
return fract(sin(vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)))) * 43758.5453);
|
||||
}
|
||||
|
||||
float cellDistance(vec2 d) {
|
||||
if (DISTANCE_METRIC == 1) return abs(d.x) + abs(d.y);
|
||||
if (DISTANCE_METRIC == 2) return max(abs(d.x), abs(d.y));
|
||||
return length(d);
|
||||
}
|
||||
|
||||
vec2 cellId(vec2 st) {
|
||||
vec2 i_st = floor(st);
|
||||
vec2 f_st = fract(st);
|
||||
|
||||
vec2 nearestCell = vec2(0.0);
|
||||
float m_dist = 8.0;
|
||||
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
vec2 neighbor = vec2(float(x), float(y));
|
||||
vec2 point = random2(i_st + neighbor);
|
||||
float dist = cellDistance(neighbor + point - f_st);
|
||||
|
||||
if (dist < m_dist) {
|
||||
m_dist = dist;
|
||||
nearestCell = neighbor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i_st + nearestCell;
|
||||
}
|
||||
|
||||
void faceAxes(vec3 normal, out vec3 tangent, out vec3 bitangent) {
|
||||
vec3 dp1 = dFdx(viewPos);
|
||||
vec3 dp2 = dFdy(viewPos);
|
||||
vec2 duv1 = dFdx(texCoord0);
|
||||
vec2 duv2 = dFdy(texCoord0);
|
||||
|
||||
vec3 dp2perp = cross(dp2, normal);
|
||||
vec3 dp1perp = cross(normal, dp1);
|
||||
tangent = normalize(dp2perp * duv1.x + dp1perp * duv2.x);
|
||||
bitangent = normalize(dp2perp * duv1.y + dp1perp * duv2.y);
|
||||
}
|
||||
|
||||
vec3 facetNormal(vec3 normal, vec3 tangent, vec3 bitangent, vec2 id) {
|
||||
float angle = random2(id).x * TAU;
|
||||
vec2 lean = vec2(cos(angle), sin(angle)) * FACET_TILT;
|
||||
return normalize(normal + lean.x * tangent + lean.y * bitangent);
|
||||
}
|
||||
|
||||
float thinFilm(vec3 normal, vec3 viewDir, float thicknessNm) {
|
||||
float cosI = clamp(dot(normal, viewDir), 0.0, 1.0);
|
||||
float sinT2 = (1.0 - cosI * cosI) / (FILM_IOR * FILM_IOR);
|
||||
float cosT = sqrt(1.0 - sinT2);
|
||||
float extraPath = 2.0 * FILM_IOR * thicknessNm * cosT;
|
||||
float phase = TAU * extraPath / FILM_WAVELENGTH + PI;
|
||||
return 0.5 + 0.5 * cos(phase);
|
||||
}
|
||||
|
||||
vec3 teraSheen(vec3 teraColor, float film) {
|
||||
vec3 teraDeep = pow(teraColor, vec3(SHADE_SPREAD));
|
||||
return mix(teraDeep, teraColor, film);
|
||||
}
|
||||
|
||||
vec2 shade(vec3 normal, vec3 lightDir, vec3 viewDir) {
|
||||
float diffuse = AMBIENT + (1.0 - AMBIENT) * max(dot(normal, lightDir), 0.0);
|
||||
vec3 h = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(normal, h), 0.0), SPEC_SHININESS) * SPEC_STRENGTH;
|
||||
return vec2(diffuse, spec);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 albedo = texture(Sampler0, texCoord0);
|
||||
if (albedo.a < 0.1) discard;
|
||||
|
||||
float seconds = GameTime * SECONDS_PER_DAY;
|
||||
vec3 normal = normalize(viewNormal);
|
||||
vec3 viewDir = normalize(-viewPos);
|
||||
vec3 lightDir = normalize(LIGHT_DIR);
|
||||
|
||||
vec2 facetUv = texCoord0 * vec2(textureSize(Sampler0, 0));
|
||||
if (SNAP_TO_TEXELS) {
|
||||
facetUv = floor(facetUv) + 0.5;
|
||||
}
|
||||
vec2 id = cellId(facetUv / CELL_SIZE_TEXELS);
|
||||
|
||||
vec3 tangent, bitangent;
|
||||
faceAxes(normal, tangent, bitangent);
|
||||
vec3 n = facetNormal(normal, tangent, bitangent, id);
|
||||
|
||||
vec2 rnd = random2(id + 17.0);
|
||||
float thickness = mix(FILM_THICKNESS_MIN, FILM_THICKNESS_MAX, rnd.x);
|
||||
thickness += sin(seconds * SHIMMER_SPEED + TAU * rnd.y) * SHIMMER_NM;
|
||||
vec3 film = teraSheen(vertexColor.rgb, thinFilm(n, viewDir, thickness));
|
||||
|
||||
float glimmerPhase = seconds / GLIMMER_PERIOD + random2(id + 53.0).x;
|
||||
float glimmer = pow(0.5 + 0.5 * cos(TAU * glimmerPhase), GLIMMER_SHARPNESS) * GLIMMER_STRENGTH;
|
||||
|
||||
vec2 light = shade(n, lightDir, viewDir);
|
||||
float facetShading = light.x / shade(normal, lightDir, viewDir).x;
|
||||
|
||||
vec3 selfLit = mix(lightMapColor.rgb, vec3(1.0), SELF_LIGHT);
|
||||
float fade = linear_fog_fade(vertexDistance, FogStart, FogEnd);
|
||||
float keep = mix(1.0, min(facetShading, 1.0), fade);
|
||||
|
||||
vec3 base = albedo.rgb * vanillaLight * lightMapColor.rgb;
|
||||
vec3 target = albedo.rgb * vanillaLight * selfLit * facetShading;
|
||||
vec3 brighten = max(target - base * min(facetShading, 1.0), 0.0);
|
||||
vec3 sparkle = mix(film, vec3(1.0), SPEC_WHITENESS) * (light.y + glimmer);
|
||||
vec3 reflection = (sparkle + film * SHEEN_STRENGTH) * selfLit;
|
||||
|
||||
vec3 added = (brighten + reflection) * fade * ColorModulator.rgb;
|
||||
|
||||
fragColor = vec4(added, keep);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"vertex": "cobblemon:tera",
|
||||
"fragment": "cobblemon:tera",
|
||||
"attributes": ["Position", "Color", "UV0", "UV1", "UV2", "Normal"],
|
||||
"samplers": [
|
||||
{"name": "Sampler0"},
|
||||
{"name": "Sampler2"}
|
||||
],
|
||||
"uniforms": [
|
||||
{"name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]},
|
||||
{"name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]},
|
||||
{"name": "ColorModulator", "type": "float", "count": 4, "values": [1.0, 1.0, 1.0, 1.0]},
|
||||
{"name": "Light0_Direction", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0]},
|
||||
{"name": "Light1_Direction", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0]},
|
||||
{"name": "FogStart", "type": "float", "count": 1, "values": [0.0]},
|
||||
{"name": "FogEnd", "type": "float", "count": 1, "values": [1.0]},
|
||||
{"name": "FogShape", "type": "int", "count": 1, "values": [0]},
|
||||
{"name": "GameTime", "type": "float", "count": 1, "values": [0.0]}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#version 150
|
||||
|
||||
#moj_import <light.glsl>
|
||||
#moj_import <fog.glsl>
|
||||
|
||||
in vec3 Position;
|
||||
in vec4 Color;
|
||||
in vec2 UV0;
|
||||
in ivec2 UV2;
|
||||
in vec3 Normal;
|
||||
|
||||
uniform sampler2D Sampler2;
|
||||
|
||||
uniform mat4 ModelViewMat;
|
||||
uniform mat4 ProjMat;
|
||||
uniform int FogShape;
|
||||
|
||||
uniform vec3 Light0_Direction;
|
||||
uniform vec3 Light1_Direction;
|
||||
|
||||
out float vertexDistance;
|
||||
out vec4 vertexColor;
|
||||
out vec4 lightMapColor;
|
||||
out float vanillaLight;
|
||||
out vec2 texCoord0;
|
||||
out vec3 viewPos;
|
||||
out vec3 viewNormal;
|
||||
|
||||
void main() {
|
||||
// Same expression as vanilla so the depth matches the base model exactly, otherwise the overlay z-fights
|
||||
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0);
|
||||
vec4 vp = ModelViewMat * vec4(Position, 1.0);
|
||||
viewPos = vp.xyz;
|
||||
viewNormal = normalize(mat3(ModelViewMat) * Normal);
|
||||
|
||||
vertexDistance = fog_distance(Position, FogShape);
|
||||
vertexColor = Color;
|
||||
lightMapColor = texelFetch(Sampler2, UV2 / 16, 0);
|
||||
// Same shading the base model got, so the fragment shader knows what's underneath
|
||||
vanillaLight = minecraft_mix_light(Light0_Direction, Light1_Direction, Normal, vec4(1.0)).r;
|
||||
texCoord0 = UV0;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"targets": [
|
||||
"mask",
|
||||
"swap",
|
||||
"glow"
|
||||
],
|
||||
"passes": [
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "mask",
|
||||
"outtarget": "swap",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 1.0, 0.0 ] },
|
||||
{ "name": "Radius", "values": [ 16.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "swap",
|
||||
"outtarget": "glow",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 0.0, 1.0 ] },
|
||||
{ "name": "Radius", "values": [ 16.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "glow",
|
||||
"outtarget": "swap",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 1.0, 0.0 ] },
|
||||
{ "name": "Radius", "values": [ 32.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "swap",
|
||||
"outtarget": "glow",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 0.0, 1.0 ] },
|
||||
{ "name": "Radius", "values": [ 32.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_composite",
|
||||
"intarget": "glow",
|
||||
"outtarget": "swap",
|
||||
"auxtargets": [
|
||||
{ "name": "MaskSampler", "id": "mask" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "Strength", "values": [ 1.0 ] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform vec2 InSize;
|
||||
// How far the blur reaches, in pixels on a 1080p screen
|
||||
uniform float Radius;
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec2 sampleStep;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
const float WEIGHTS[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
||||
|
||||
void main() {
|
||||
vec2 tap = sampleStep * Radius * (InSize.y / 1080.0) / 4.0;
|
||||
vec4 color = texture(DiffuseSampler, texCoord) * WEIGHTS[0];
|
||||
for (int i = 1; i < 5; i++) {
|
||||
color += texture(DiffuseSampler, texCoord + tap * float(i)) * WEIGHTS[i];
|
||||
color += texture(DiffuseSampler, texCoord - tap * float(i)) * WEIGHTS[i];
|
||||
}
|
||||
fragColor = color;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"blend": {
|
||||
"func": "add",
|
||||
"srcrgb": "one",
|
||||
"dstrgb": "zero"
|
||||
},
|
||||
"vertex": "blur",
|
||||
"fragment": "cobblemon_tera_halo_blur",
|
||||
"attributes": [ "Position" ],
|
||||
"samplers": [
|
||||
{ "name": "DiffuseSampler" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||
{ "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
|
||||
{ "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
|
||||
{ "name": "BlurDir", "type": "float", "count": 2, "values": [ 1.0, 0.0 ] },
|
||||
{ "name": "Radius", "type": "float", "count": 1, "values": [ 20.0 ] }
|
||||
]
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform sampler2D MaskSampler;
|
||||
uniform float Strength;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// How much the glow is dimmed over the mon itself, so the crystal overlay stays readable
|
||||
const float INNER_DIM = 0.9;
|
||||
|
||||
void main() {
|
||||
vec3 glow = texture(DiffuseSampler, texCoord).rgb;
|
||||
float inside = texture(MaskSampler, texCoord).a;
|
||||
fragColor = vec4(min(glow * Strength, vec3(1.0)) * (1.0 - INNER_DIM * inside), 1.0);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"blend": {
|
||||
"func": "add",
|
||||
"srcrgb": "one",
|
||||
"dstrgb": "zero"
|
||||
},
|
||||
"vertex": "sobel",
|
||||
"fragment": "cobblemon_tera_halo_composite",
|
||||
"attributes": [ "Position" ],
|
||||
"samplers": [
|
||||
{ "name": "DiffuseSampler" },
|
||||
{ "name": "MaskSampler" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||
{ "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
|
||||
{ "name": "Strength", "type": "float", "count": 1, "values": [ 2.2 ] }
|
||||
]
|
||||
}
|
||||
@@ -49,6 +49,7 @@ transitive-accessible field net/minecraft/client/particle/ParticleEngine texture
|
||||
transitive-accessible field net/minecraft/client/renderer/LevelRenderer cullingFrustum Lnet/minecraft/client/renderer/culling/Frustum;
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderType$CompositeRenderType
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderType$CompositeState
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderStateShard$ShaderStateShard
|
||||
transitive-accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/String;Lcom/mojang/blaze3d/vertex/VertexFormat;Lcom/mojang/blaze3d/vertex/VertexFormat$Mode;IZZLnet/minecraft/client/renderer/RenderType$CompositeState;)Lnet/minecraft/client/renderer/RenderType$CompositeRenderType;
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderStateShard$TransparencyStateShard
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard RENDERTYPE_ENTITY_TRANSLUCENT_EMISSIVE_SHADER Lnet/minecraft/client/renderer/RenderStateShard$ShaderStateShard;
|
||||
@@ -70,6 +71,7 @@ transitive-accessible field net/minecraft/client/renderer/RenderStateShard NO_CU
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard COLOR_WRITE Lnet/minecraft/client/renderer/RenderStateShard$WriteMaskStateShard;
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard NO_DEPTH_TEST Lnet/minecraft/client/renderer/RenderStateShard$DepthTestStateShard;
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderStateShard$DepthTestStateShard
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderStateShard$OutputStateShard
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard LEQUAL_DEPTH_TEST Lnet/minecraft/client/renderer/RenderStateShard$DepthTestStateShard;
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard GLINT_TRANSPARENCY Lnet/minecraft/client/renderer/RenderStateShard$TransparencyStateShard;
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard ADDITIVE_TRANSPARENCY Lnet/minecraft/client/renderer/RenderStateShard$TransparencyStateShard;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"client.ItemInHandLayerMixin",
|
||||
"client.ItemInHandRendererMixin",
|
||||
"client.ItemRendererMixin",
|
||||
"client.LevelRendererMixin",
|
||||
"client.LivingEntityRendererMixin",
|
||||
"client.LocalPlayerMixin",
|
||||
"client.ModelLoaderMixin",
|
||||
|
||||
Reference in New Issue
Block a user