I've got a problem with rendering hard shadows in a PBR pipeline.
I believe there is something wrong with PBR calculations because with a Blinn-Phong lighting model everything looks fine.
These are lightning calculations - basic PBR
struct DirectionalLight
{
vec3 direction;
};
layout(std140, binding = 2) uniform Scene
{
DirectionalLight directionalLight;
vec3 viewPosition;
} u_scene;
layout(std140, binding = 4) uniform Material
{
vec4 baseColor;
float roughness;
float metalness;
} u_material;
const float PI = 3.14159265359;
const float epsilon = 0.00001;
int lightCount = 1;
vec3 CalculateDirectionalLight(vec3 N, vec3 V, float NdotV, vec3 F0)
{
vec3 result;
for(int i = 0; i < lightCount; ++i) {
vec3 L = normalize(-u_scene.directionalLight.direction);
float NdotL = max(0.0f, dot(N, L));
vec3 H = normalize(V + L);
float NdotH = max(0.0f, dot(N, H));
vec3 F = FresnelSchlickRoughness(max(0.0f, dot(H, V)), F0, u_material.roughness);
float D = NDFGGX(NdotH, u_material.roughness);
float G = GeometrySmith(NdotL, NdotV, u_material.roughness);
vec3 kd = (1.0f - F) * (1.0f - u_material.metalness);
vec3 diffuse = kd * u_material.baseColor.rgb;
vec3 nominator = F * G * D;
float denominator = max(epsilon, 4.0f * NdotV * NdotL);
vec3 specular = nominator / denominator;
specular = clamp(specular, vec3(0.0f), vec3(10.0f));
result += (diffuse + specular) /* u_material.radiance */ * NdotL;
}
return result;
}
float NDFGGX(float NdotH, float roughness)
{
float alpha = roughness * roughness;
float alphaSq = alpha * alpha;
float denom = (NdotH * NdotH) * (alphaSq - 1.0) + 1.0;
return alphaSq / (PI * denom * denom);
}
float GeometrySchlickGGX(float Ndot, float k)
{
float nom = Ndot;
float denom = Ndot * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(float NdotL, float NdotV, float roughness)
{
float r = (roughness + 1.0f);
float k = (r * r) / 8.0f;
float ggx2 = GeometrySchlickGGX(NdotV, k);
float ggx1 = GeometrySchlickGGX(NdotL, k);
return ggx1 * ggx2;
}
vec3 FresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
{
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
}
shadow functions
layout(binding = 2) uniform sampler2D u_shadowMap;
float ShadowFade = 1.0;
float GetShadowBias()
{
const float MINIMUM_SHADOW_BIAS = 0.002;
float bias = max(MINIMUM_SHADOW_BIAS * (1.0 - dot(normalize(v_normal), -normalize(u_scene.directionalLight.direction))), MINIMUM_SHADOW_BIAS);
return bias;
}
float HardShadows_DirectionalLight(vec4 fragPosLightSpace)
{
vec3 shadowCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
float bias = GetShadowBias();
float shadowMapDepth = texture(u_shadowMap, vec2(shadowCoords.xy * 0.5 + 0.5)).r;
return step(shadowCoords.z, shadowMapDepth + bias) * ShadowFade;
}
and the main function
void main()
{
vec3 F0 = vec3(0.04f);
F0 = mix(F0, u_material.baseColor.rgb, u_material.metalness);
vec3 N = normalize(v_normal);
vec3 V = normalize(u_scene.viewPosition - v_position);
float NdotV = max(0.0f, dot(N, V));
//v_positionFromLight is calculated in a vertex shader like this:
//v_positionFromLight = u_lightViewProjection * vec4(v_position, 1.0f);
//where v_position is modelMatrix * a_position;
//where a_position is a input position of a vertex
float shadow = HardShadows_DirectionalLight(v_positionFromLight);
vec3 ambient = u_material.baseColor.rgb * 0.3f;
vec3 lightContribution = ambient + CalculateDirectionalLight(N, V, NdotV, F0) * shadow;
f_color = vec4(lightContribution, 1.0);
}
and this is how the scene looks like - there should be visible shadows, but there aren't:
I've tested 2 things.
First - Blinn-Phong lighting model - shadows render just fine.
Second - output shadow calculations without PBR lightning
like this:
void main()
{
float shadow = HardShadows_DirectionalLight(v_positionFromLight);
vec3 ambient = u_material.baseColor.rgb * 0.3f;
f_color = vec4(ambient * shadow, 1.0f);
}
and it also works (besides that they're not placed in a good spot, but that is another topic):
Why this PBR model does not work with shadows?
How can I fix it?
I've been following this tutorial to implement my variance shadow mapping feature for point light in deferred rendering.
I'm using GLSL 3.3, left-handed coordinate system. Here is what I've been doing:
I render the scene to dual-paraboloid maps, storing depth and depth * depth.
Result:
Above image contains front and back maps. The point light is at the center of scene, you can see where it glows yellow the most.
Then I set up a full-screen shader pass.
I do this by transforming the tutorial code from FX to GLSL.
Author's .fx code:
float4 TexturePS(float3 normalW : TEXCOORD0, float2 tex0 : TEXCOORD1, float3 pos : TEXCOORD2) : COLOR
{
float4 texColor = tex2D(TexS, tex0 * TexScale);
pos = mul(float4(pos, 1.0f), LightView);
float L = length(pos);
float3 P0 = pos / L;
float alpha = .5f + pos.z / LightAttenuation;
P0.z = P0.z + 1;
P0.x = P0.x / P0.z;
P0.y = P0.y / P0.z;
P0.z = L / LightAttenuation;
P0.x = .5f * P0.x + .5f;
P0.y = -.5f * P0.y + .5f;
float3 P1 = pos / L;
P1.z = 1 - P1.z;
P1.x = P1.x / P1.z;
P1.y = P1.y / P1.z;
P1.z = L / LightAttenuation;
P1.x = .5f * P1.x + .5f;
P1.y = -.5f * P1.y + .5f;
float depth;
float mydepth;
float2 moments;
if(alpha >= 0.5f)
{
moments = tex2D(ShadowFrontS, P0.xy).xy;
depth = moments.x;
mydepth = P0.z;
}
else
{
moments = tex2D(ShadowBackS, P1.xy).xy;
depth = moments.x;
mydepth = P1.z;
}
float lit_factor = (mydepth <= moments[0]);
float E_x2 = moments.y;
float Ex_2 = moments.x * moments.x;
float variance = min(max(E_x2 - Ex_2, 0.0) + SHADOW_EPSILON, 1.0);
float m_d = (moments.x - mydepth);
float p = variance / (variance + m_d * m_d); //Chebychev's inequality
texColor.xyz *= max(lit_factor, p + .2f);
return texColor;
}
My translated GLSL code:
void main() {
vec3 in_vertex = texture(scenePosTexture, texCoord).xyz; // get 3D vertex from 2D screen coordinate
vec4 vert = lightViewMat * vec4(in_vertex, 1); // project vertex to point light space (view from light position, look target is -Z)
float L = length(vert.xyz);
float distance = length(lightPos - in_vertex);
float denom = distance / lightRad + 1;
float attenuation = 1.0 / (denom * denom);
// to determine which paraboloid map to use
float alpha = vert.z / attenuation + 0.5f;
vec3 P0 = vert.xyz / L;
P0.z = P0.z + 1;
P0.x = P0.x / P0.z;
P0.y = P0.y / P0.z;
P0.z = L / attenuation;
P0.x = .5f * P0.x + .5f;
P0.y = -.5f * P0.y + .5f;
vec3 P1 = vert.xyz / L;
P1.z = 1 - P1.z;
P1.x = P1.x / P1.z;
P1.y = P1.y / P1.z;
P1.z = L / attenuation;
P1.x = .5f * P1.x + .5f;
P1.y = -.5f * P1.y + .5f;
// Variance shadow mapping
float depth;
float mydepth;
vec2 moments;
if(alpha >= 0.5f)
{
moments = texture(shadowMapFrontTexture, P0.xy).xy;
depth = moments.x;
mydepth = P0.z;
}
else
{
moments = texture(shadowMapBackTexture, P1.xy).xy;
depth = moments.x;
mydepth = P1.z;
}
// Original .fx code is: float lit_factor = (mydepth <= moments[0]);
// I'm not sure my translated code belew is correct
float lit_factor = 0;
if (mydepth <= moments.x)
lit_factor = mydepth;
else
lit_factor = moments.x;
float E_x2 = moments.y;
float Ex_2 = moments.x * moments.x;
float variance = min(max(E_x2 - Ex_2, 0.0) + SHADOW_EPSILON, 1.0);
float m_d = (moments.x - mydepth);
float p = variance / (variance + m_d * m_d); //Chebychev's inequality
fragColor = texture(sceneTexture, texCoord).rgb; // sample original color
fragColor.rgb *= max(lit_factor, p + .2f);
}
Render result
Right now I'm clueless about where I'm gonna touch to render the shadow correctly. Could someone point it out for me?
Some friend of mine pointed out that the Y component is flipped, that's why shadow looked like up-side down. After adding minus to P0 and P1's Y, it starts to show quite reasonable shadow:
But another problem is the location of shadow is wrong.
Why do you duplicate the paraboloid projection computation ?
You compute it on 'vert', then 'P0' and 'P1', shouldn't you do it only on 'P0' and 'P1' ? (The original code doesn't do this thing on 'pos').
EDIT:
Your lit_factor is wrong, it should be either 0.0 or 1.0.
You could use the step() GLSL intrinsic, in this way :
float lit_factor = step(mydepth, moments[0]);
I copied some files from a few shaders, and it works out for the most part, but I sometimes get graphical glitches like this where faces of grass blocks are completely transparent:
I believe my gbuffers_terrain.fsh or gbuffers_terrain.vsh is what is causing the problem.
gbuffers_terrain.fsh:
#version 120
#extension GL_ARB_shader_texture_lod : enable
/* DRAWBUFFERS:0247 */
/*
RRe36's Shaders, derived from Chocapic13 v4
Place two leading Slashes in front of the following '#define' lines in order to disable an option.
IMPORTANT: Placing Slashes in front of lines like '#define FILTER_LEVEL 15.0' will cause errors!
*/
//-------- Adjustable Variables --------//
//---- Normal Mapping ----//
#define NORMAL_MAPPING
#define NORMAL_MAP_MAX_ANGLE 1.0
//---- End of Normal Mapping ----//
//---- Parallax Displacement aka. POM ----//
//#define POM
#define POM_MAP_RES 128.0
#define POM_DEPTH (1.0/20.0)
const float MAX_OCCLUSION_DISTANCE = 32.0;
const float MIX_OCCLUSION_DISTANCE = 28.0;
const int MAX_OCCLUSION_POINTS = 12;
//---- End of Parallax Displacement ----//
//---- Lightmaps ----//
#define MIN_LIGHTAMOUNT 0.1 //affect the minecraft lightmap (not torches)
#define MINELIGHTMAP_EXP 2.0 //affect the minecraft lightmap (not torches)
//---- End of Lightmaps ----//
//-------- End of Adjustable Variables --------//
/* Here, intervalMult might need to be tweaked per texture pack.
The first two numbers determine how many samples are taken per fragment. They should always be the equal to eachother.
The third number divided by one of the first two numbers is inversely proportional to the range of the height-map. */
const vec3 intervalMult = vec3(1.0, 1.0, 1.0/POM_DEPTH)/POM_MAP_RES * 1.0;
const int RGBA16 = 3;
const int RGB16 = 2;
const int RGB8 = 1;
const int gnormalFormat = RGB16;
const int compositeFormat = RGBA16;
const int gaux2Format = RGBA16;
const int gcolorFormat = RGB8;
const int GL_EXP = 2048;
const int GL_LINEAR = 9729;
const float bump_distance = 64.0; //bump render distance: tiny = 32, short = 64, normal = 128, far = 256
const float pom_distance = 32.0; //POM render distance: tiny = 32, short = 64, normal = 128, far = 256
const float fademult = 0.1;
varying vec2 lmcoord;
varying vec4 color;
varying float translucent;
varying vec4 vtexcoordam; // .st for add, .pq for mul
varying vec4 vtexcoord;
varying float dist;
varying vec3 tangent;
varying vec3 normal;
varying vec3 binormal;
varying vec3 viewVector;
uniform sampler2D texture;
uniform sampler2D normals;
uniform sampler2D specular;
uniform vec3 sunPosition;
uniform vec3 moonPosition;
uniform int fogMode;
uniform int worldTime;
uniform float wetness;
uniform float rainStrength;
float totalspec = 0.0;
float wetx = clamp(wetness, 0.0f, 1.0)/1.0;
const float mincoord = 1.0/4096.0;
const float maxcoord = 1.0-mincoord;
vec2 dcdx = dFdx(vtexcoord.st*vtexcoordam.pq);
vec2 dcdy = dFdy(vtexcoord.st*vtexcoordam.pq);
vec4 readTexture(in vec2 coord){
return texture2DGradARB(texture,fract(coord)*vtexcoordam.pq+vtexcoordam.st,dcdx,dcdy);
}
vec4 readNormal(in vec2 coord){
return texture2DGradARB(normals,fract(coord)*vtexcoordam.pq+vtexcoordam.st,dcdx,dcdy);
}
float normalmap_intensity = NORMAL_MAP_MAX_ANGLE-((NORMAL_MAP_MAX_ANGLE*rainStrength)*0.95);
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
void main() {
vec2 adjustedTexCoord = vtexcoord.st*vtexcoordam.pq+vtexcoordam.st;
#ifdef POM
if (dist < MAX_OCCLUSION_DISTANCE) {
if ( viewVector.z < 0.0 && readNormal(vtexcoord.st).a < 0.99 && readNormal(vtexcoord.st).a > 0.01)
{
vec3 interval = viewVector.xyz * intervalMult;
vec3 coord = vec3(vtexcoord.st, 1.0);
for (int loopCount = 0;
(loopCount < MAX_OCCLUSION_POINTS) && (readNormal(coord.st).a < coord.p);
++loopCount) {
coord = coord+interval;
}
// Don't wrap around top of tall grass/flower
if (coord.t < mincoord) {
if (readTexture(vec2(coord.s,mincoord)).a == 0.0) {
coord.t = mincoord;
discard;
}
}
adjustedTexCoord = mix(fract(coord.st)*vtexcoordam.pq+vtexcoordam.st , adjustedTexCoord , max(dist-MIX_OCCLUSION_DISTANCE,0.0)/(MAX_OCCLUSION_DISTANCE-MIX_OCCLUSION_DISTANCE));
}
}
#endif
vec3 lightVector;
vec3 specularity = texture2DGradARB(specular, adjustedTexCoord.st, dcdx, dcdy).rgb;
float atten = 1.0-(specularity.b)*0.86;
vec4 frag2 = vec4(normal, 1.0f);
vec3 bump = texture2DGradARB(normals, adjustedTexCoord.st, dcdx, dcdy).rgb*2.0-1.0;
float bumpmult = normalmap_intensity*(1.0-wetness*lmcoord.t*0.65)*atten;
bump = bump * vec3(bumpmult, bumpmult, bumpmult) + vec3(0.0f, 0.0f, 1.0f - bumpmult);
mat3 tbnMatrix = mat3(tangent.x, binormal.x, normal.x,
tangent.y, binormal.y, normal.y,
tangent.z, binormal.z, normal.z);
frag2 = vec4(normalize(bump * tbnMatrix) * 0.5 + 0.5, 1.0);
float dirtest = 0.4;
if (worldTime < 12700 || worldTime > 23250) {
lightVector = normalize(sunPosition);
}
else {
lightVector = normalize(moonPosition);
}
dirtest = mix(1.0-0.8*step(dot(frag2.xyz*2.0-1.0,lightVector),-0.02),0.4,float(translucent > 0.01));
/* DRAWBUFFERS:0246 */
gl_FragData[0] = texture2DGradARB(texture, adjustedTexCoord.st, dcdx, dcdy) * color;
gl_FragData[1] = frag2;
gl_FragData[2] = vec4(lmcoord.t, dirtest, lmcoord.s, 1.0);
gl_FragData[3] = texture2DGradARB(specular, adjustedTexCoord.st, dcdx, dcdy);
}
My gbuffers_terrain.vsh:
#version 120
/*
RRe36's Shaders, derived from Chocapic13 v4
Place two leading Slashes in front of the following '#define' lines in order to disable an option.
IMPORTANT: Placing Slashes in front of lines like '#define FILTER_LEVEL 15.0' will cause errors!
*/
//-------- Adjustable Variables --------//
//---- Waving Effects ----//
#define WAVING_LEAVES
#define WAVING_VINES
#define WAVING_GRASS
#define WAVING_WHEAT
#define WAVING_FLOWERS
#define WAVING_FIRE
#define WAVING_LAVA
#define WAVING_LILYPAD
#define WAVING_TALLGRASS
#define WAVING_REEDS
//---- End of Waving Effects ----//
//---- Entity IDs ----//
#define ENTITY_LEAVES 18.0
#define ENTITY_VINES 106.0
#define ENTITY_TALLGRASS 31.0
#define ENTITY_DANDELION 37.0
#define ENTITY_ROSE 38.0
#define ENTITY_WHEAT 59.0
#define ENTITY_LILYPAD 111.0
#define ENTITY_FIRE 51.0
#define ENTITY_LAVAFLOWING 10.0
#define ENTITY_LAVASTILL 11.0
#define ENTITY_SAPLING 6.0
//---- End of Entity IDs ----//
//---- World Effects -----//
//#define WORLD_CURVATURE // will cause bug at high shadowdistances: looks like a dark circle around you
const float WORLD_RADIUS = 6000.0; //Increase for a stronger rounded world
const float WORLD_RADIUS_SQUARED = 15000000.0;
//---- End of World Effects ----//
//-------- End of Adjustable Variables --------//
const float PI = 3.1415927;
varying vec4 color;
varying vec2 lmcoord;
varying float translucent;
varying vec4 vtexcoordam; // .st for add, .pq for mul
varying vec4 vtexcoord;
varying float dist;
varying vec3 tangent;
varying vec3 normal;
varying vec3 binormal;
varying vec3 viewVector;
attribute vec4 mc_Entity;
attribute vec4 mc_midTexCoord;
uniform vec3 cameraPosition;
uniform mat4 gbufferModelView;
uniform mat4 gbufferModelViewInverse;
uniform int worldTime;
uniform float frameTimeCounter;
uniform float rainStrength;
float timefract = worldTime;
//Calculate Time of Day
float TimeSunrise = ((clamp(timefract, 23000.0, 24000.0) - 23000.0) / 1000.0) + (1.0 - (clamp(timefract, 0.0, 4000.0)/4000.0));
float TimeNoon = ((clamp(timefract, 0.0, 4000.0)) / 4000.0) - ((clamp(timefract, 8000.0, 12000.0) - 8000.0) / 4000.0);
float TimeSunset = ((clamp(timefract, 8000.0, 12000.0) - 8000.0) / 4000.0) - ((clamp(timefract, 12000.0, 12750.0) - 12000.0) / 750.0);
float TimeMidnight = ((clamp(timefract, 12000.0, 12750.0) - 12000.0) / 750.0) - ((clamp(timefract, 23000.0, 24000.0) - 23000.0) / 1000.0);
float animationTime = worldTime/20.0f;
float pi2wt = PI*2*(frameTimeCounter*24 + (rainStrength*2));
vec3 calcWave(in vec3 pos, in float fm, in float mm, in float ma, in float f0, in float f1, in float f2, in float f3, in float f4, in float f5) {
vec3 ret;
float magnitude,d0,d1,d2,d3;
magnitude = sin(pi2wt*fm + pos.x*0.5 + pos.z*0.5 + pos.y*0.5) * mm + ma;
d0 = sin(pi2wt*f0)*(rainStrength*2);
d1 = sin(pi2wt*f1)*(rainStrength*1.75);
d2 = sin(pi2wt*f2)*(rainStrength*1.5);
ret.x = sin(pi2wt*f3 + d0 + d1 - pos.x + pos.z + pos.y) * magnitude;
ret.z = sin(pi2wt*f4 + d1 + d2 + pos.x - pos.z + pos.y) * magnitude;
ret.y = sin(pi2wt*f5 + d2 + d0 + pos.z + pos.y - pos.y) * magnitude;
return ret;
}
vec3 calcMove(in vec3 pos, in float f0, in float f1, in float f2, in float f3, in float f4, in float f5, in vec3 amp1, in vec3 amp2) {
vec3 move1 = calcWave(pos , 0.0027, 0.0400, 0.0400, 0.0127, 0.0089, 0.0114, 0.0063, 0.0224, 0.0015) * amp1;
vec3 move2 = calcWave(pos+move1, 0.0348, 0.0400, 0.0400, f0, f1, f2, f3, f4, f5) * amp2;
return move1+move2;
}
vec3 calcWaterMove(in vec3 pos) {
float fy = fract(pos.y + 0.001);
if (fy > 0.002) {
float wave = 0.05 * sin(2 * PI * (worldTime / 86.0 + pos.x / 7.0 + pos.z / 13.0))
+ 0.05 * sin(2 * PI * (worldTime / 60.0 + pos.x / 11.0 + pos.z / 5.0));
return vec3(0, clamp(wave, -fy, 1.0-fy), 0);
}
else {
return vec3(0);
}
}
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
//////////////////////////////main//////////////////////////////
void main() {
vec2 texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st;
vec2 midcoord = (gl_TextureMatrix[0] * mc_midTexCoord).st;
vec2 texcoordminusmid = texcoord-midcoord;
vtexcoordam.pq = abs(texcoordminusmid)*2;
vtexcoordam.st = min(texcoord,midcoord-texcoordminusmid);
vtexcoord.st = sign(texcoordminusmid)*0.5+0.5;
translucent = 0.0f;
float istopv = 0.0;
if (gl_MultiTexCoord0.t < mc_midTexCoord.t) istopv = 1.0;
/* un-rotate */
vec4 position = gbufferModelViewInverse * gl_ModelViewMatrix * gl_Vertex;
vec3 worldpos = position.xyz + cameraPosition;
//initialize per-entity waving parameters
float parm0,parm1,parm2,parm3,parm4,parm5 = rainStrength*4;
vec3 ampl1,ampl2;
ampl1 = vec3(0.0);
ampl2 = vec3(0.0);
#ifdef WAVING_LEAVES
if (( mc_Entity.x == ENTITY_LEAVES || mc_Entity.x == 161 )) {
parm0 = 0.0040;
parm1 = 0.0064;
parm2 = 0.0043;
parm3 = 0.0035;
parm4 = 0.0037;
parm5 = 0.0041;
ampl1 = vec3(1.0,0.2,1.0) + rainStrength/4;
ampl2 = vec3(0.5,0.1,0.5) + rainStrength/4;
}
#endif
#ifdef WAVING_VINES
if ( mc_Entity.x == ENTITY_VINES ) {
parm0 = 0.0040;
parm1 = 0.0064;
parm2 = 0.0043;
parm3 = 0.0035;
parm4 = 0.0037;
parm5 = 0.0041;
ampl1 = vec3(1.0,0.2,1.0);
ampl2 = vec3(0.5,0.1,0.5);
}
#endif
#ifdef WAVING_REEDS
if ( mc_Entity.x == 83 ) {
parm0 = 0.0024;
parm1 = 0.0020;
parm2 = 0.0016;
parm3 = 0.0010;
parm4 = 0.0009;
parm5 = 0.0002;
ampl1 = vec3(0.25,0.05,0.25) + rainStrength/5;
ampl2 = vec3(0.125,0.025,0.125) + rainStrength/5;
}
#endif
if (istopv > 0.9) {
#ifdef WAVING_GRASS
if ( mc_Entity.x == ENTITY_TALLGRASS || mc_Entity.x == ENTITY_SAPLING) {
parm0 = 0.0041;
parm1 = 0.0070;
parm2 = 0.0044;
parm3 = 0.0038;
parm4 = 0.0063;
parm5 = 0.0;
ampl1 = vec3(0.8,0.0,0.8) + 0.2 + rainStrength/3;
ampl2 = vec3(0.4,0.0,0.4) + 0.2 + rainStrength/3;
}
#endif
#ifdef WAVING_FLOWERS
if ((mc_Entity.x == ENTITY_DANDELION || mc_Entity.x == ENTITY_ROSE)) {
parm0 = 0.0041;
parm1 = 0.005;
parm2 = 0.0044;
parm3 = 0.0038;
parm4 = 0.0240;
parm5 = 0.0;
ampl1 = vec3(0.8,0.0,0.8) + rainStrength/3;
ampl2 = vec3(0.4,0.0,0.4) + rainStrength/3;
}
#endif
#ifdef WAVING_WHEAT
if ( mc_Entity.x == ENTITY_WHEAT || mc_Entity.x == 141 || mc_Entity.x == 142) {
parm0 = 0.0041;
parm1 = 0.0070;
parm2 = 0.0044;
parm3 = 0.0240;
parm4 = 0.0063;
parm5 = 0.0;
ampl1 = vec3(0.6,0.0,0.8) + rainStrength/3;
ampl2 = vec3(0.4,0.0,0.5) + rainStrength/3;
}
#endif
#ifdef WAVING_FIRE
if ( mc_Entity.x == ENTITY_FIRE) {
parm0 = 0.0105;
parm1 = 0.0096;
parm2 = 0.0087;
parm3 = 0.0063;
parm4 = 0.0097;
parm5 = 0.0156;
ampl1 = vec3(1.2,0.4,1.2) + rainStrength*1.8;
ampl2 = vec3(0.8,0.8,0.8) + rainStrength*1.8;
}
#endif
}
float movemult = 0.0;
#ifdef WAVING_LAVA
if ( mc_Entity.x == ENTITY_LAVAFLOWING || mc_Entity.x == ENTITY_LAVASTILL ) movemult = 0.25;
#endif
#ifdef WAVING_LILYPAD
if ( mc_Entity.x == ENTITY_LILYPAD ) movemult = 1.0 + (rainStrength*0.5);
#endif
#ifdef WAVING_TALLGRASS
if ( mc_Entity.x == 175) {
parm0 = 0.0031;
parm1 = 0.004;
parm2 = 0.0034;
parm3 = 0.0028;
parm4 = 0.0163;
parm5 = 0.0;
ampl1 = vec3(0.4,0.0,0.4);
ampl2 = vec3(0.2,0.0,0.2);
}
#endif
#ifdef WORLD_CURVATURE
if (gl_Color.a != 0.8) {
float distanceSquared = position.x * position.x + position.z * position.z;
position.y -= WORLD_RADIUS - sqrt(max(1.0 - distanceSquared / WORLD_RADIUS_SQUARED, 0.0)) * WORLD_RADIUS;
}
#endif
position.xyz += calcWaterMove(worldpos.xyz) * movemult;
position.xyz += calcMove(worldpos.xyz, parm0, parm1, parm2, parm3, parm4, parm5, ampl1, ampl2);
if ( mc_Entity.x == 37 || mc_Entity.x == 31 || mc_Entity.x == 175 || mc_Entity.x == 59 || mc_Entity.x == 141 || mc_Entity.x == 142 || mc_Entity.x == 31 )
translucent = 1.0;
/* re-rotate */
/* projectify */
gl_Position = gl_ProjectionMatrix * gbufferModelView * position;
color = gl_Color;
lmcoord = (gl_TextureMatrix[1] * gl_MultiTexCoord1).xy;
normal = normalize(gl_NormalMatrix * gl_Normal);
tangent = vec3(0.0);
binormal = vec3(0.0);
normal = normalize(gl_NormalMatrix * gl_Normal);
if (gl_Normal.x > 0.5) {
// 1.0, 0.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
} else if (gl_Normal.x < -0.5) {
// -1.0, 0.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
} else if (gl_Normal.y > 0.5) {
// 0.0, 1.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
} else if (gl_Normal.y < -0.5) {
// 0.0, -1.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
} else if (gl_Normal.z > 0.5) {
// 0.0, 0.0, 1.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
} else if (gl_Normal.z < -0.5) {
// 0.0, 0.0, -1.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
}
mat3 tbnMatrix = mat3(tangent.x, binormal.x, normal.x,
tangent.y, binormal.y, normal.y,
tangent.z, binormal.z, normal.z);
viewVector = ( gl_ModelViewMatrix * gl_Vertex).xyz;
viewVector = normalize(tbnMatrix * viewVector);
dist = 0.0;
dist = length(gbufferModelView *gbufferModelViewInverse * gl_ModelViewMatrix * gl_Vertex);
}
My composite.fsh:
#version 120
//------------------------------------
//datLax' OnlyWater v2.0
//
//If you have questions, suggestions or bugs you want to report, please comment on my minecraftforum.net thread:
//http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/2381727-shader-pack-datlax-onlywater-only-water
//
//This code is free to use,
//but don't forget to give credits! :)
//------------------------------------
uniform sampler2D gcolor;
uniform sampler2D depthtex0;
uniform sampler2D gaux1;
varying vec4 texcoord;
varying vec3 ambient_color;
varying float TimeMidnight;
uniform int worldTime;
uniform mat4 gbufferProjection;
uniform mat4 gbufferProjectionInverse;
uniform mat4 gbufferModelViewInverse;
uniform float near;
uniform float far;
uniform float viewWidth;
uniform float viewHeight;
float ld(float depth) {
return (2.0 * near) / (far + near - depth * (far - near));
}
vec3 aux = texture2D(gaux1, texcoord.st).rgb;
float land = aux.b;
float torch_lightmap = aux.b;
float sky_lightmap = aux.g;
float landx = 1.0-step(land, 0.01);
float iswater = 0.0;
float pixeldepth = texture2D(depthtex0,texcoord.xy).x;
float pw = 1.0/ viewWidth;
float ph = 1.0/ viewHeight;
float callwaves(vec2 pos) {
float wsize = 2.9;
float wspeed = 0.025f;
float rs0 = abs(sin((worldTime*wspeed/5.0) + (pos.s*wsize) * 20.0)+0.2);
float rs1 = abs(sin((worldTime*wspeed/7.0) + (pos.t*wsize) * 27.0));
float rs2 = abs(sin((worldTime*wspeed/2.0) + (pos.t*wsize) * 60.0 - sin(pos.s*wsize) * 13.0)+0.4);
float rs3 = abs(sin((worldTime*wspeed/1.0) - (pos.s*wsize) * 20.0 + cos(pos.t*wsize) * 83.0)+0.1);
float wsize2 = 1.7;
float wspeed2 = 0.017f;
float rs0a = abs(sin((worldTime*wspeed2/4.0) + (pos.s*wsize2) * 24.0));
float rs1a = abs(sin((worldTime*wspeed2/11.0) + (pos.t*wsize2) * 77.0 )+0.3);
float rs2a = abs(sin((worldTime*wspeed2/6.0) + (pos.s*wsize2) * 50.0 - (pos.t*wsize2) * 23.0)+0.12);
float rs3a = abs(sin((worldTime*wspeed2/14.0) - (pos.t*wsize2) * 4.0 + (pos.s*wsize2) * 98.0));
float wsize3 = 0.3;
float wspeed3 = 0.03f;
float rs0b = abs(sin((worldTime*wspeed3/4.0) + (pos.s*wsize3) * 14.0));
float rs1b = abs(sin((worldTime*wspeed3/11.0) + (pos.t*wsize3) * 37.0));
float rs2b = abs(sin((worldTime*wspeed3/6.0) + (pos.t*wsize3) * 47.0 - cos(pos.s*wsize3) * 33.0 + rs0a + rs0b));
float rs3b = abs(sin((worldTime*wspeed3/14.0) - (pos.s*wsize3) * 13.0 + sin(pos.t*wsize3) * 98.0 + rs0 + rs1));
float waves = (rs1 * rs0 + rs2 * rs3)/2.0f;
float waves2 = (rs0a * rs1a + rs2a * rs3a)/2.0f;
float waves3 = (rs0b + rs1b + rs2b + rs3b)*0.25;
return (waves + waves2 + waves3)/3.0f;
}
//----------------MAIN------------------
void main() {
if(aux.g > 0.01 && aux.g < 0.07) {
iswater = 1.0;
}
vec4 fragposition = gbufferProjectionInverse * vec4(texcoord.s * 2.0f - 1.0f, texcoord.t * 2.0f - 1.0f, 2.0f * pixeldepth - 1.0f, 1.0f);
fragposition /= fragposition.w;
float dist = length(fragposition.xyz);
vec4 worldposition = vec4(0.0);
worldposition = gbufferModelViewInverse * fragposition;
vec3 color = texture2D(gcolor, texcoord.st).rgb;
const float rspread = 0.30f;
float wave = 0.0;
if (iswater == 1.0) {
wave = callwaves(worldposition.xz*0.02)*2.0-1.0;
wave = wave;
const float wnormalclamp = 0.05f;
float rdepth = pixeldepth;
float waves = wave;
float wnormal_x1 = texture2D(depthtex0, texcoord.st + vec2(pw, 0.0f)).x - texture2D(depthtex0, texcoord.st).x;
float wnormal_x2 = texture2D(depthtex0, texcoord.st).x - texture2D(depthtex0, texcoord.st + vec2(-pw, 0.0f)).x;
float wnormal_x = 0.0f;
if(abs(wnormal_x1) > abs(wnormal_x2)){
wnormal_x = wnormal_x2;
} else {
wnormal_x = wnormal_x1;
}
wnormal_x /= 1.0f - rdepth;
wnormal_x = clamp(wnormal_x, -wnormalclamp, wnormalclamp);
wnormal_x *= rspread;
float wnormal_y1 = texture2D(depthtex0, texcoord.st + vec2(0.0f, ph)).x - texture2D(depthtex0, texcoord.st).x;
float wnormal_y2 = texture2D(depthtex0, texcoord.st).x - texture2D(depthtex0, texcoord.st + vec2(0.0f, -ph)).x;
float wnormal_y;
if(abs(wnormal_y1) > abs(wnormal_y2)){
wnormal_y = wnormal_y2;
} else {
wnormal_y = wnormal_y1;
}
wnormal_y /= 1.0f - rdepth;
wnormal_y = clamp(wnormal_y, -wnormalclamp, wnormalclamp);
wnormal_y *= rspread;
//Calculate distance of objects behind water
float refractdist = 0.2 * 10.0f;
//Perform refraction
float refractamount = 500.1154f*0.35f*refractdist;
float refractamount2 = 0.0214f*0.05f*refractdist;
float refractamount3 = 0.214f*0.15f*refractdist;
float waberration = 0.105;
vec3 refracted = vec3(0.0f);
float refractedmask = 0.0;
float bigWaveRefract = 0.0;
float bigWaveRefractScale = 0.0;
vec2 bigRefract = vec2(wnormal_x*bigWaveRefract, wnormal_y*bigWaveRefract);
vec2 refractcoord_r = texcoord.st;
vec2 refractcoord_g = texcoord.st;
vec2 refractcoord_b = texcoord.st;
for (int i = 0; i < 1; ++i) {
refractcoord_r = texcoord.st * (1.0f + waves*refractamount3) - (waves*refractamount3/2.0f) + vec2( waves*refractamount2 + (-wnormal_x*0.4f) - bigRefract.x, waves*refractamount2 + (-wnormal_y*0.4f) - bigRefract.y) * (waberration * 2.0f + 1.0f);
refractcoord_r = refractcoord_r * vec2(1.0f - abs(wnormal_x) * bigWaveRefractScale, 1.0f - abs(wnormal_y) * bigWaveRefractScale) + vec2(abs(wnormal_x) * bigWaveRefractScale * 0.5f, abs(wnormal_y) * bigWaveRefractScale * 0.5f);
refractcoord_r.s = clamp(refractcoord_r.s, 0.001f, 0.999f);
refractcoord_r.t = clamp(refractcoord_r.t, 0.001f, 0.999f);
if (refractcoord_r.s > 1.0 || refractcoord_r.s < 0.0 || refractcoord_r.t > 1.0 || refractcoord_r.t < 0.0) {
break;
}
refracted.rgb = texture2D(gcolor, refractcoord_r).rgb;
refractedmask = texture2D(gaux1, refractcoord_r).g;
if(refractedmask > 0.01 && refractedmask < 0.07) {
refractedmask = 1.0;
}else refractedmask = 0.0;
}
color.rgb = mix(color.rgb, refracted.rgb, vec3(refractedmask));
}
wave = wave*0.5+0.5;
if (iswater > 0.9){
wave += 0.02;
}else{
wave = 0.0;
}
if (landx == 1.0) {
//vec3 torchcolor = vec3(1.0, 0.675, 0.415);
vec3 torchcolor = vec3(0.8, 0.7, 0.3);
vec3 torchlight_lightmap = torch_lightmap * torchcolor;
color = color * torchlight_lightmap * TimeMidnight + color * ambient_color;
}
/* DRAWBUFFERS:3 */
gl_FragData[0] = vec4(color, 1.0);
/* DRAWBUFFERS:NNN3N5 */
gl_FragData[5] = vec4(0.0, wave, 0.0, 0.0);
gl_FragData[3] = vec4(color, land);
}
My composite.vsh:
#version 120
//------------------------------------
//datLax' OnlyWater v2.0
//
//If you have questions, suggestions or bugs you want to report, please comment on my minecraftforum.net thread:
//http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/2381727-shader-pack-datlax-onlywater-only-water
//
//This code is free to use,
//but don't forget to give credits! :)
//------------------------------------
varying vec4 texcoord;
varying float TimeMidnight;
varying float TimeSunset;
varying float TimeNoon;
varying float TimeSunrise;
varying vec3 ambient_color;
uniform int worldTime;
void main() {
gl_Position = ftransform();
texcoord = gl_MultiTexCoord0;
float timefract = float(worldTime);
TimeSunrise = ((clamp(timefract, 23000.0, 24000.0) - 23000.0) / 1000.0) + (1.0-(clamp(timefract, 0.0, 6000.0)/6000.0));
TimeNoon = ((clamp(timefract, 0.0, 6000.0)) / 6000.0) - ((clamp(timefract, 6000.0, 12000.0) - 6000.0) / 6000.0);
TimeSunset = ((clamp(timefract, 6000.0, 12000.0) - 6000.0) / 6000.0) - ((clamp(timefract, 12000.0, 12750.0) - 12000.0) / 750.0);
TimeMidnight = ((clamp(timefract, 12000.0, 12750.0) - 12000.0) / 750.0) - ((clamp(timefract, 23000.0, 24000.0) - 23000.0) / 1000.0);
vec3 sunrise_amb;
sunrise_amb.r = TimeSunrise;
sunrise_amb.g = TimeSunrise;
sunrise_amb.b = TimeSunrise;
vec3 noon_amb;
noon_amb.r = TimeNoon;
noon_amb.g = TimeNoon;
noon_amb.b = TimeNoon;
vec3 sunset_amb;
sunset_amb.r = 0.95*TimeSunset;
sunset_amb.g = 0.95*TimeSunset;
sunset_amb.b = 0.95*TimeSunset;
vec3 midnight_amb;
midnight_amb.r = 0.45*TimeMidnight;
midnight_amb.g = 0.45*TimeMidnight;
midnight_amb.b = 0.7*TimeMidnight;
ambient_color.r = sunrise_amb.r + noon_amb.r + sunset_amb.r + midnight_amb.r;
ambient_color.g = sunrise_amb.g + noon_amb.g + sunset_amb.g + midnight_amb.g;
ambient_color.b = sunrise_amb.b + noon_amb.b + sunset_amb.b + midnight_amb.b;
}
I am using a 128x128 resource pack, and I don't know much about shaders. Why are faces of grass blocks flickering, and is there a way to fix this? Also, when recording from OBS screen capture, the video turns out flashing. Reminder: I pulled gbuffers_terrain from a completely different shaderpack.
Specs:
OS: Ubuntu 16.04 LTS 64-bit
RAM: 8GB
CPU: Intel® Core™ i5-4460 CPU # 3.20GHz × 4
GPU: Intel® Haswell Desktop
OpenGL:
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) Haswell Desktop
OpenGL core profile version string: 3.3 (Core Profile) Mesa 12.1.0-devel
OpenGL core profile shading language version string: 3.30
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 3.0 Mesa 12.1.0-devel
OpenGL shading language version string: 1.30
OpenGL context flags: (none)
OpenGL extensions:
OpenGL ES profile version string: OpenGL ES 3.0 Mesa 12.1.0-devel
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00
OpenGL ES profile extensions:
I am currently designing a fragment shader that shall display a page curl effect as a transition between two images. So I looked it up on the Internet and found this code that works as I want:
varying vec2 texCoord;
uniform sampler2D sourceTex;
uniform sampler2D targetTex;
uniform float time; // Ranges from 0.0 to 1.0
const float MIN_AMOUNT = -0.16;
const float MAX_AMOUNT = 1.3;
float amount = time * (MAX_AMOUNT - MIN_AMOUNT) + MIN_AMOUNT;
const float PI = 3.141592653589793;
const float scale = 512.0;
const float sharpness = 3.0;
float cylinderCenter = amount;
// 360 degrees * amount
float cylinderAngle = 2.0 * PI * amount;
const float cylinderRadius = 1.0 / PI / 2.0;
vec3 hitPoint(float hitAngle, float yc, vec3 point, mat3 rrotation) {
float hitPoint = hitAngle / (2.0 * PI);
point.y = hitPoint;
return rrotation * point;
}
vec4 antiAlias(vec4 color1, vec4 color2, float distance) {
distance *= scale;
if (distance < 0.0) return color2;
if (distance > 2.0) return color1;
float dd = pow(1.0 - distance / 2.0, sharpness);
return ((color2 - color1) * dd) + color1;
}
float distanceToEdge(vec3 point) {
float dx = abs(point.x > 0.5 ? 1.0 - point.x : point.x);
float dy = abs(point.y > 0.5 ? 1.0 - point.y : point.y);
if (point.x < 0.0) dx = -point.x;
if (point.x > 1.0) dx = point.x - 1.0;
if (point.y < 0.0) dy = -point.y;
if (point.y > 1.0) dy = point.y - 1.0;
if ((point.x < 0.0 || point.x > 1.0) && (point.y < 0.0 || point.y > 1.0)) return sqrt(dx * dx + dy * dy);
return min(dx, dy);
}
vec4 seeThrough(float yc, vec2 p, mat3 rotation, mat3 rrotation) {
float hitAngle = PI - (acos(yc / cylinderRadius) - cylinderAngle);
vec3 point = hitPoint(hitAngle, yc, rotation * vec3(p, 1.0), rrotation);
if (yc <= 0.0 && (point.x < 0.0 || point.y < 0.0 || point.x > 1.0 || point.y > 1.0)) {
return texture2D(targetTex, texCoord);
}
if (yc > 0.0) return texture2D(sourceTex, p);
vec4 color = texture2D(sourceTex, point.xy);
vec4 tcolor = vec4(0.0);
return antiAlias(color, tcolor, distanceToEdge(point));
}
vec4 seeThroughWithShadow(float yc, vec2 p, vec3 point, mat3 rotation, mat3 rrotation) {
float shadow = distanceToEdge(point) * 30.0;
shadow = (1.0 - shadow) / 3.0;
if (shadow < 0.0) shadow = 0.0;
else shadow *= amount;
vec4 shadowColor = seeThrough(yc, p, rotation, rrotation);
shadowColor.r -= shadow;
shadowColor.g -= shadow;
shadowColor.b -= shadow;
return shadowColor;
}
vec4 backside(float yc, vec3 point) {
vec4 color = texture2D(sourceTex, point.xy);
float gray = (color.r + color.b + color.g) / 15.0;
gray += (8.0 / 10.0) * (pow(1.0 - abs(yc / cylinderRadius), 2.0 / 10.0) / 2.0 + (5.0 / 10.0));
color.rgb = vec3(gray);
return color;
}
vec4 behindSurface(float yc, vec3 point, mat3 rrotation) {
float shado = (1.0 - ((-cylinderRadius - yc) / amount * 7.0)) / 6.0;
shado *= 1.0 - abs(point.x - 0.5);
yc = (-cylinderRadius - cylinderRadius - yc);
float hitAngle = (acos(yc / cylinderRadius) + cylinderAngle) - PI;
point = hitPoint(hitAngle, yc, point, rrotation);
if (yc < 0.0 && point.x >= 0.0 && point.y >= 0.0 && point.x <= 1.0 && point.y <= 1.0 && (hitAngle < PI || amount > 0.5)){
shado = 1.0 - (sqrt(pow(point.x - 0.5, 2.0) + pow(point.y - 0.5, 2.0)) / (71.0 / 100.0));
shado *= pow(-yc / cylinderRadius, 3.0);
shado *= 0.5;
} else
shado = 0.0;
return vec4(texture2D(targetTex, texCoord).rgb - shado, 1.0);
}
void main(void) {
const float angle = 30.0 * PI / 180.0;
float c = cos(-angle);
float s = sin(-angle);
mat3 rotation = mat3(
c, s, 0,
-s, c, 0,
0.12, 0.258, 1
);
c = cos(angle);
s = sin(angle);
mat3 rrotation = mat3(
c, s, 0,
-s, c, 0,
0.15, -0.5, 1
);
vec3 point = rotation * vec3(texCoord, 1.0);
float yc = point.y - cylinderCenter;
if (yc < -cylinderRadius) {
// Behind surface
gl_FragColor = behindSurface(yc, point, rrotation);
return;
}
if (yc > cylinderRadius) {
// Flat surface
gl_FragColor = texture2D(sourceTex, texCoord);
return;
}
float hitAngle = (acos(yc / cylinderRadius) + cylinderAngle) - PI;
float hitAngleMod = mod(hitAngle, 2.0 * PI);
if ((hitAngleMod > PI && amount < 0.5) || (hitAngleMod > PI/2.0 && amount < 0.0)) {
gl_FragColor = seeThrough(yc, texCoord, rotation, rrotation);
return;
}
point = hitPoint(hitAngle, yc, point, rrotation);
if (point.x < 0.0 || point.y < 0.0 || point.x > 1.0 || point.y > 1.0) {
gl_FragColor = seeThroughWithShadow(yc, texCoord, point, rotation, rrotation);
return;
}
vec4 color = backside(yc, point);
vec4 otherColor;
if (yc < 0.0) {
float shado = 1.0 - (sqrt(pow(point.x - 0.5, 2.0) + pow(point.y - 0.5, 2.0)) / 0.71);
shado *= pow(-yc / cylinderRadius, 3.0);
shado *= 0.5;
otherColor = vec4(0.0, 0.0, 0.0, shado);
} else {
otherColor = texture2D(sourceTex, texCoord);
}
color = antiAlias(color, otherColor, cylinderRadius - abs(yc));
vec4 cl = seeThroughWithShadow(yc, texCoord, point, rotation, rrotation);
float dist = distanceToEdge(point);
gl_FragColor = antiAlias(color, cl, dist);
}
I just want to modify the angle of the curl but it seems like there are too many dependencies that are not made dynamicly, does anybody know the math behind it well enough to help me or knows maybe even a better code sample to use?