Compare commits

..
19 changed files with 706 additions and 4 deletions
@@ -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();
}
}
@@ -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) }
}
}
}
@@ -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) }
}
}
@@ -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()) {
@@ -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 ] }
]
}
]
}
@@ -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;
}
@@ -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 ] }
]
}
@@ -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);
}
@@ -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",