Respackopts/run/resourcepacks/lumi/assets/canvas/shaders/internal/material_main.frag
2020-11-26 20:11:38 +01:00

378 lines
12 KiB
GLSL

/*
* Lumi Lights - A shader pack for Canvas
* Copyright (c) 2020 spiralhalo and Contributors
*
* See `README.md` for license notice.
*/
#include canvas:shaders/internal/header.glsl
#include canvas:shaders/internal/varying.glsl
#include canvas:shaders/internal/diffuse.glsl
#include canvas:shaders/internal/flags.glsl
#include canvas:shaders/internal/fog.glsl
#include frex:shaders/api/world.glsl
#include frex:shaders/api/player.glsl
#include frex:shaders/api/material.glsl
#include frex:shaders/api/fragment.glsl
#include frex:shaders/api/sampler.glsl
#include frex:shaders/lib/math.glsl
#include frex:shaders/lib/color.glsl
#include canvas:shaders/internal/program.glsl
#include lumi:shaders/api/varying.glsl
#include canvas:apitarget
#include respackopts:config_supplier
/******************************************************
canvas:shaders/internal/material_main.frag
******************************************************/
#define M_PI 3.1415926535897932384626433832795
const float hdr_sunStr = 3;
const float hdr_moonStr = 0.4;
const float hdr_blockStr = 1.5;
const float hdr_handHeldStr = 0.9;
const float hdr_skylessStr = 0.2;
const float hdr_baseMinStr = 0.0;
const float hdr_baseMaxStr = 0.25;
const float hdr_emissiveStr = 1;
const float hdr_relAmbient = 0.09;
const float hdr_relSunHorizon = 0.5;
const float hdr_zWobbleDefault = 0.1;
const float hdr_finalMult = 1;
const float hdr_gamma = 2.2;
float hdr_gammaAdjust(float x){
return pow(x, hdr_gamma);
}
vec3 hdr_gammaAdjust(vec3 x){
return pow(x, vec3(hdr_gamma));
}
vec3 hdr_reinhardJodieTonemap(in vec3 v) {
float l = frx_luminance(v);
vec3 tv = v / (1.0f + v);
return mix(v / (1.0f + l), tv, tv);
}
vec3 hdr_vibrantTonemap(in vec3 v){
return v / (frx_luminance(v) + vec3(1.0));
}
void _cv_startFragment(inout frx_FragmentData data) {
int cv_programId = _cv_fragmentProgramId();
#include canvas:startfragment
}
float l2_clampScale(float e0, float e1, float v){
return clamp((v-e0)/(e1-e0), 0.0, 1.0);
}
float l2_max3(vec3 vec){
return max(vec.x, max(vec.y, vec.z));
}
// vec3 l2_what(vec3 rgb){
// return vec3(0.4123910 * rgb.r + 0.3575840 * rgb.g + 0.1804810 * rgb.b,
// 0.2126390 * rgb.r + 0.7151690 * rgb.g + 0.0721923 * rgb.b,
// 0.0193308 * rgb.r + 0.1191950 * rgb.g + 0.9505320 * rgb.b);
// }
vec3 l2_blockLight(float blockLight){
float bl = l2_clampScale(0.03125, 1.0, blockLight);
bl *= bl * hdr_blockStr;
vec3 block = hdr_gammaAdjust(vec3(bl, bl*0.875, bl*0.75));
#if HANDHELD_LIGHT_RADIUS != 0
vec4 held = frx_heldLight();
if (held.w > 0.0) {
float hl = l2_clampScale(held.w * HANDHELD_LIGHT_RADIUS, 0.0, gl_FogFragCoord);
hl *= hl * hdr_handHeldStr;
return block + hdr_gammaAdjust(held.rgb * hl);
}
#endif
return block;
}
vec3 l2_emissiveLight(float emissivity){
return vec3(hdr_gammaAdjust(emissivity) * hdr_emissiveStr);
}
float l2_skyLight(float skyLight, float intensity)
{
float sl = l2_clampScale(0.03125, 1.0, skyLight);
return hdr_gammaAdjust(sl) * intensity;
}
vec3 l2_ambientColor(float time){
vec3 ambientColor = hdr_gammaAdjust(vec3(0.6, 0.9, 1.0)) * hdr_sunStr * hdr_relAmbient;
vec3 sunriseAmbient = hdr_gammaAdjust(vec3(1.0, 0.8, 0.4)) * hdr_sunStr * hdr_relAmbient * hdr_relSunHorizon;
vec3 sunsetAmbient = hdr_gammaAdjust(vec3(1.0, 0.6, 0.2)) * hdr_sunStr * hdr_relAmbient * hdr_relSunHorizon;
vec3 nightAmbient = hdr_gammaAdjust(vec3(1.0, 1.0, 2.0)) * hdr_moonStr * hdr_relAmbient;
if(time > 0.94){
ambientColor = mix(nightAmbient, sunriseAmbient, l2_clampScale(0.94, 0.98, time));
} else if(time > 0.52){
ambientColor = mix(sunsetAmbient, nightAmbient, l2_clampScale(0.52, 0.56, time));
} else if(time > 0.48){
ambientColor = mix(ambientColor, sunsetAmbient, l2_clampScale(0.48, 0.5, time));
} else if(time < 0.02){
ambientColor = mix(ambientColor, sunriseAmbient, l2_clampScale(0.02, 0, time));
}
return ambientColor;
}
vec3 l2_skyAmbient(float skyLight, float time, float intensity){
float sa = l2_skyLight(skyLight, intensity) * 2.5;
return sa * l2_ambientColor(time);
}
float l2_userBrightness(){
float base = texture2D(frxs_lightmap, vec2(0.03125, 0.03125)).r;
// if(frx_isWorldTheNether()){
// return smoothstep(0.15/*0.207 no true darkness in nether*/, 0.577, base);
// } else if (frx_isWorldTheEnd(){
// return smoothstep(0.18/*0.271 no true darkness in the end*/, 0.685, base);
// } else {
// return smoothstep(0.053, 0.135, base);
// }
// Simplify nether/the end check
if(frx_worldHasSkylight()){
return smoothstep(0.053, 0.135, base);
} else {
return smoothstep(0.15, 0.63, base);
}
}
vec3 l2_skylessLightColor(){
return hdr_gammaAdjust(vec3(1.0));
}
vec3 l2_dimensionColor(){
if (frx_isWorldTheNether()) {
float min_col = min(min(gl_Fog.color.rgb.x, gl_Fog.color.rgb.y), gl_Fog.color.rgb.z);
float max_col = max(max(gl_Fog.color.rgb.x, gl_Fog.color.rgb.y), gl_Fog.color.rgb.z);
float sat = 0.0;
if (max_col != 0.0) {
sat = (max_col-min_col)/max_col;
}
return hdr_gammaAdjust(clamp((gl_Fog.color.rgb*(1/max_col))+pow(sat,2)/2, 0.0, 1.0));
}
else {
return hdr_gammaAdjust(vec3(0.8, 0.7, 1.0));
}
}
vec3 l2_skylessLight(vec3 normal){
if(frx_worldHasSkylight()){
return vec3(0);
} else {
float yalign = dot(normal,vec3(0, 0.977358, 0.211593)); // a bit towards z for more interesting effect
yalign = frx_isSkyDarkened()?abs(yalign):max(0,yalign);
return yalign * hdr_skylessStr * l2_skylessLightColor() * l2_userBrightness();
}
}
vec3 l2_baseAmbient(){
if(frx_worldHasSkylight()){
return vec3(0.1) * mix(hdr_baseMinStr, hdr_baseMaxStr, l2_userBrightness());
} else {
return l2_dimensionColor() * mix(hdr_baseMinStr, hdr_baseMaxStr, l2_userBrightness());
}
}
vec3 l2_sunColor(float time){
vec3 sunColor = hdr_gammaAdjust(vec3(1.0, 1.0, lumi_sunColorFactor)) * hdr_sunStr;
vec3 sunriseColor = hdr_gammaAdjust(vec3(1.0, 0.8, 0.4)) * hdr_sunStr * hdr_relSunHorizon;
vec3 sunsetColor = hdr_gammaAdjust(vec3(1.0, 0.6, 0.4)) * hdr_sunStr * hdr_relSunHorizon;
if(time > 0.94){
sunColor = sunriseColor;
} else if(time > 0.56){
sunColor = vec3(0); // pitch black at night
} else if(time > 0.54){
sunColor = mix(sunsetColor, vec3(0), l2_clampScale(0.54, 0.56, time));
} else if(time > 0.5){
sunColor = sunsetColor;
} else if(time > 0.48){
sunColor = mix(sunColor, sunsetColor, l2_clampScale(0.48, 0.5, time));
} else if(time < 0.02){
sunColor = mix(sunColor, sunriseColor, l2_clampScale(0.02, 0, time));
}
return sunColor;
}
vec3 l2_vanillaSunDir(in float time, float zWobble){
// wrap time to account for sunrise
time -= (time >= 0.75) ? 1.0 : 0.0;
// supposed offset of sunset/sunrise from 0/12000 daytime. might get better result with datamining?
float sunHorizonDur = 0.04;
// angle of sun in radians
float angleRad = l2_clampScale(-sunHorizonDur, 0.5+sunHorizonDur, time) * M_PI;
return normalize(vec3(cos(angleRad), sin(angleRad), zWobble));
}
vec3 l2_sunLight(float skyLight, in float time, float intensity, float rainGradient, vec3 diffuseNormal){
// wrap time to account for sunrise
float customTime = (time >= 0.75) ? (time - 1.0) : time;
float customIntensity = l2_clampScale(-0.08, 0.00, customTime);
if(customTime >= 0.25){
customIntensity = l2_clampScale(0.58, 0.5, customTime);
}
customIntensity *= mix(1.0, 0.0, rainGradient);
float sl = l2_skyLight(skyLight, max(customIntensity, intensity));
// direct sun light doesn't reach into dark spot as much as sky ambient
sl = frx_smootherstep(0.5,1.0,sl);
// zWobble is added to make more interesting looking diffuse light
// TODO: might be fun to use frx_worldDay() with sine wave for the zWobble to simulate annual sun position change
sl *= max(0.0, dot(l2_vanillaSunDir(time, hdr_zWobbleDefault), diffuseNormal));
return sl * l2_sunColor(time);
}
vec3 l2_moonLight(float skyLight, float time, float intensity, vec3 diffuseNormal){
float ml = l2_skyLight(skyLight, intensity) * frx_moonSize() * hdr_moonStr;
float aRad = l2_clampScale(0.56, 0.94, time) * M_PI;
ml *= max(0.0, dot(vec3(cos(aRad), sin(aRad), 0), diffuseNormal));
if(time < 0.58){
ml *= l2_clampScale(0.54, 0.58, time);
} else if(time > 0.92){
ml *= l2_clampScale(0.96, 0.92, time);
}
return vec3(ml);
}
float l2_specular(float time, vec3 aNormal, vec3 aPos, vec3 cameraPos, float power)
{
// calculate sun position (0 zWobble to make it look accurate with vanilla sun visuals)
vec3 sunDir = l2_vanillaSunDir(time, 0);
// obtain the direction of the camera
vec3 viewDir = normalize(cameraPos - aPos);
// calculate the specular light
return pow(max(0.0, dot(reflect(-sunDir, aNormal), viewDir)),power);
}
float l2_ao(frx_FragmentData fragData) {
#if AO_SHADING_MODE != AO_MODE_NONE
float ao = fragData.ao ? _cvv_ao : 1.0;
return hdr_gammaAdjust(min(1.0, ao + fragData.emissivity));
#else
return 1.0;
#endif
}
void main() {
frx_FragmentData fragData = frx_FragmentData (
texture2D(frxs_spriteAltas, _cvv_texcoord, _cv_getFlag(_CV_FLAG_UNMIPPED) * -4.0),
_cvv_color,
frx_matEmissive() ? 1.0 : 0.0,
!frx_matDisableDiffuse(),
!frx_matDisableAo(),
_cvv_normal,
_cvv_lightcoord
);
_cv_startFragment(fragData);
vec4 a = fragData.spriteColor * fragData.vertexColor;
float bloom = fragData.emissivity; // separate bloom from emissivity
if(frx_isGui()){
#if DIFFUSE_SHADING_MODE != DIFFUSE_MODE_NONE
if(fragData.diffuse){
float diffuse = mix(_cvv_diffuse, 1, fragData.emissivity);
vec3 shading = mix(vec3(0.5, 0.4, 0.8) * diffuse * diffuse, vec3(1.0), diffuse);
a.rgb *= shading;
}
#endif
} else {
a.rgb = hdr_gammaAdjust(a.rgb);
// If diffuse is disabled (e.g. grass) then the normal points up by default
float ao = l2_ao(fragData);
vec3 diffuseNormal = fragData.diffuse?fragData.vertexNormal * frx_normalModelMatrix():vec3(0,1,0);
vec3 block = l2_blockLight(fragData.light.x);
vec3 sun = l2_sunLight(fragData.light.y, frx_worldTime(), frx_ambientIntensity(), frx_rainGradient(), diffuseNormal);
vec3 moon = l2_moonLight(fragData.light.y, frx_worldTime(), frx_ambientIntensity(), diffuseNormal);
vec3 skyAmbient = l2_skyAmbient(fragData.light.y, frx_worldTime(), frx_ambientIntensity());
vec3 emissive = l2_emissiveLight(fragData.emissivity);
vec3 nether = l2_skylessLight(diffuseNormal);
vec3 light = block + moon + l2_baseAmbient() + skyAmbient + sun + nether;
light *= ao; // AO is supposed to be applied to ambient only, but things look better with AO on everything except for emissive light
light += emissive;
vec3 specular = vec3(0.0);
if (wwv_specPower > 0.01) {
vec3 specularNormal = fragData.vertexNormal * frx_normalModelMatrix();
float skyAccess = smoothstep(0.89, 1.0, fragData.light.y);
vec3 fragPos = frx_var0.xyz;
vec3 cameraPos = frx_var1.xyz;
vec3 sunDir = l2_vanillaSunDir(frx_worldTime(), 0);
vec3 sun = l2_sunLight(fragData.light.y, frx_worldTime(), frx_ambientIntensity(), frx_rainGradient(), sunDir);
float specularAmount = l2_specular(frx_worldTime(), specularNormal, fragPos, cameraPos, wwv_specPower);
specular = sun * specularAmount * skyAccess;
}
a.rgb *= light;
a.rgb += specular;
float specularLuminance = frx_luminance(specular);
a.a += specularLuminance;
bloom += specularLuminance;
a.rgb *= hdr_finalMult;
#if lumi_tonemap == lumi_tonemap_vibrant
a.rgb = pow(hdr_vibrantTonemap(a.rgb), vec3(1.0 / hdr_gamma));
#elif lumi_tonemap == reinhardJodie
a.rgb = pow(hdr_reinhardJodieTonemap(a.rgb), vec3(1.0 / hdr_gamma));
#else
a.rgb = pow(frx_toneMap(a.rgb), vec3(1.0 / hdr_gamma));
#endif
}
// PERF: varyings better here?
if (_cv_getFlag(_CV_FLAG_CUTOUT) == 1.0) {
float t = _cv_getFlag(_CV_FLAG_TRANSLUCENT_CUTOUT) == 1.0 ? _CV_TRANSLUCENT_CUTOUT_THRESHOLD : 0.5;
if (a.a < t) {
discard;
}
}
// PERF: varyings better here?
if (_cv_getFlag(_CV_FLAG_FLASH_OVERLAY) == 1.0) {
a = a * 0.25 + 0.75;
} else if (_cv_getFlag(_CV_FLAG_HURT_OVERLAY) == 1.0) {
a = vec4(0.25 + a.r * 0.75, a.g * 0.75, a.b * 0.75, a.a);
}
// TODO: need a separate fog pass?
gl_FragData[TARGET_BASECOLOR] = _cv_fog(a);
gl_FragDepth = gl_FragCoord.z;
#if TARGET_EMISSIVE > 0
gl_FragData[TARGET_EMISSIVE] = vec4(bloom * a.a, 1.0, 0.0, 1.0);
#endif
}