Selaa lähdekoodia

Fix constant texture indexing and add workaround for gl_FrontFacing

Daniel Salvadori 6 vuotta sitten
vanhempi
commit
a6db6017ca

+ 8 - 17
renderer/shaders/include/material.glsl

@@ -24,25 +24,16 @@ uniform vec3 Material[6];
     #define MatTexRepeat(a)		MatTexinfo[(3*a)+1]
     #define MatTexFlipY(a)		bool(MatTexinfo[(3*a)+2].x)
     #define MatTexVisible(a)	bool(MatTexinfo[(3*a)+2].y)
-    #define MatTex(a)           MatTexture[a]
-
-// GLSL 3.30 does not allow indexing texture sampler with non constant values.
-// This function is used to mix the texture with the specified index with the material color.
-// It should be called for each texture index. It uses two externally defined variables:
-// vec4 texColor
-// vec4 texMixed
-vec4 MIX_TEXTURE(vec4 texMixed, vec2 FragTexcoord, int i) {
-    if (MatTexVisible(i)) {
-        vec4 texColor = texture(MatTex(i), FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
-        if (i == 0) {
-            texMixed = texColor;
-        } else {
-            texMixed = mix(texMixed, texColor, texColor.a);
+    // Alpha compositing (see here: https://ciechanow.ski/alpha-compositing/)
+    vec4 Blend(vec4 texMixed, vec4 texColor) {
+        texMixed.rgb *= texMixed.a;
+        texColor.rgb *= texColor.a;
+        texMixed = texColor + texMixed * (1 - texColor.a);
+        if (texMixed.a > 0.0) {
+            texMixed.rgb /= texMixed.a;
         }
+        return texMixed;
     }
-    return texMixed;
-}
-
 #endif
 
 // TODO for alpha blending dont use mix use implementation below (similar to one in panel shader)

+ 5 - 4
renderer/shaders/panel_fragment.glsl

@@ -85,19 +85,20 @@ void main() {
             // Note that doing a simple linear interpolation (e.g. using mix()) is not correct!
             // The right formula can be found here: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
             // For a more in-depth discussion: http://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha.html#toc4
+            // Another great discussion here: https://ciechanow.ski/alpha-compositing/
 
-            // Pre-multiply the content color
+            // Alpha premultiply the content color
             vec4 contentPre = ContentColor;
             contentPre.rgb *= contentPre.a;
 
-            // Pre-multiply the texture color
+            // Alpha premultiply the content color
             vec4 texPre = texColor;
             texPre.rgb *= texPre.a;
 
-            // Combine colors the premultiplied final color
+            // Combine colors to obtain the alpha premultiplied final color
             color = texPre + contentPre * (1.0 - texPre.a);
 
-            // Un-pre-multiply (pre-divide? :P)
+            // Un-alpha-premultiply
             color.rgb /= color.a;
 		}
 

+ 53 - 33
renderer/shaders/sources.go

@@ -125,25 +125,16 @@ uniform vec3 Material[6];
     #define MatTexRepeat(a)		MatTexinfo[(3*a)+1]
     #define MatTexFlipY(a)		bool(MatTexinfo[(3*a)+2].x)
     #define MatTexVisible(a)	bool(MatTexinfo[(3*a)+2].y)
-    #define MatTex(a)           MatTexture[a]
-
-// GLSL 3.30 does not allow indexing texture sampler with non constant values.
-// This function is used to mix the texture with the specified index with the material color.
-// It should be called for each texture index. It uses two externally defined variables:
-// vec4 texColor
-// vec4 texMixed
-vec4 MIX_TEXTURE(vec4 texMixed, vec2 FragTexcoord, int i) {
-    if (MatTexVisible(i)) {
-        vec4 texColor = texture(MatTex(i), FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
-        if (i == 0) {
-            texMixed = texColor;
-        } else {
-            texMixed = mix(texMixed, texColor, texColor.a);
+    // Alpha compositing (see here: https://ciechanow.ski/alpha-compositing/)
+    vec4 Blend(vec4 texMixed, vec4 texColor) {
+        texMixed.rgb *= texMixed.a;
+        texColor.rgb *= texColor.a;
+        texMixed = texColor + texMixed * (1 - texColor.a);
+        if (texMixed.a > 0.0) {
+            texMixed.rgb /= texMixed.a;
         }
+        return texMixed;
     }
-    return texMixed;
-}
-
 #endif
 
 // TODO for alpha blending dont use mix use implementation below (similar to one in panel shader)
@@ -390,19 +381,20 @@ void main() {
             // Note that doing a simple linear interpolation (e.g. using mix()) is not correct!
             // The right formula can be found here: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
             // For a more in-depth discussion: http://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha.html#toc4
+            // Another great discussion here: https://ciechanow.ski/alpha-compositing/
 
-            // Pre-multiply the content color
+            // Alpha premultiply the content color
             vec4 contentPre = ContentColor;
             contentPre.rgb *= contentPre.a;
 
-            // Pre-multiply the texture color
+            // Alpha premultiply the content color
             vec4 texPre = texColor;
             texPre.rgb *= texPre.a;
 
-            // Combine colors the premultiplied final color
+            // Combine colors to obtain the alpha premultiplied final color
             color = texPre + contentPre * (1.0 - texPre.a);
 
-            // Un-pre-multiply (pre-divide? :P)
+            // Un-alpha-premultiply
             color.rgb /= color.a;
 		}
 
@@ -1008,17 +1000,41 @@ out vec4 FragColor;
 
 void main() {
 
-    // Mix material color with textures colors
+    // Compute final texture color
     vec4 texMixed = vec4(1);
-    #if MAT_TEXTURES==1
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 0);
-    #elif MAT_TEXTURES==2
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 0);
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 1);
-    #elif MAT_TEXTURES==3
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 0);
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 1);
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 2);
+    #if MAT_TEXTURES > 0
+        bool firstTex = true;
+        if (MatTexVisible(0)) {
+            vec4 texColor = texture(MatTexture[0], FragTexcoord * MatTexRepeat(0) + MatTexOffset(0));
+            if (firstTex) {
+                texMixed = texColor;
+                firstTex = false;
+            } else {
+                texMixed = Blend(texMixed, texColor);
+            }
+        }
+        #if MAT_TEXTURES > 1
+            if (MatTexVisible(1)) {
+                vec4 texColor = texture(MatTexture[1], FragTexcoord * MatTexRepeat(1) + MatTexOffset(1));
+                if (firstTex) {
+                    texMixed = texColor;
+                    firstTex = false;
+                } else {
+                    texMixed = Blend(texMixed, texColor);
+                }
+            }
+            #if MAT_TEXTURES > 2
+                if (MatTexVisible(2)) {
+                    vec4 texColor = texture(MatTexture[2], FragTexcoord * MatTexRepeat(2) + MatTexOffset(2));
+                    if (firstTex) {
+                        texMixed = texColor;
+                        firstTex = false;
+                    } else {
+                        texMixed = Blend(texMixed, texColor);
+                    }
+                }
+            #endif
+        #endif
     #endif
 
     // Combine material with texture colors
@@ -1031,8 +1047,12 @@ void main() {
     // Calculate the direction vector from the fragment to the camera (origin)
     vec3 camDir = normalize(-Position.xyz);
 
-    // Invert the fragment normal if not FrontFacing
-    if (!gl_FrontFacing) {
+    // Workaround for gl_FrontFacing
+    #extension GL_OES_standard_derivatives : enable
+    vec3 fdx = dFdx(Position.xyz);
+    vec3 fdy = dFdy(Position.xyz);
+    vec3 faceNormal = normalize(cross(fdx,fdy));
+    if (dot(fragNormal, faceNormal) < 0.0) { // Back-facing
         fragNormal = -fragNormal;
     }
 

+ 40 - 12
renderer/shaders/standard_fragment.glsl

@@ -14,17 +14,41 @@ out vec4 FragColor;
 
 void main() {
 
-    // Mix material color with textures colors
+    // Compute final texture color
     vec4 texMixed = vec4(1);
-    #if MAT_TEXTURES==1
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 0);
-    #elif MAT_TEXTURES==2
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 0);
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 1);
-    #elif MAT_TEXTURES==3
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 0);
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 1);
-        texMixed = MIX_TEXTURE(texMixed, FragTexcoord, 2);
+    #if MAT_TEXTURES > 0
+        bool firstTex = true;
+        if (MatTexVisible(0)) {
+            vec4 texColor = texture(MatTexture[0], FragTexcoord * MatTexRepeat(0) + MatTexOffset(0));
+            if (firstTex) {
+                texMixed = texColor;
+                firstTex = false;
+            } else {
+                texMixed = Blend(texMixed, texColor);
+            }
+        }
+        #if MAT_TEXTURES > 1
+            if (MatTexVisible(1)) {
+                vec4 texColor = texture(MatTexture[1], FragTexcoord * MatTexRepeat(1) + MatTexOffset(1));
+                if (firstTex) {
+                    texMixed = texColor;
+                    firstTex = false;
+                } else {
+                    texMixed = Blend(texMixed, texColor);
+                }
+            }
+            #if MAT_TEXTURES > 2
+                if (MatTexVisible(2)) {
+                    vec4 texColor = texture(MatTexture[2], FragTexcoord * MatTexRepeat(2) + MatTexOffset(2));
+                    if (firstTex) {
+                        texMixed = texColor;
+                        firstTex = false;
+                    } else {
+                        texMixed = Blend(texMixed, texColor);
+                    }
+                }
+            #endif
+        #endif
     #endif
 
     // Combine material with texture colors
@@ -37,8 +61,12 @@ void main() {
     // Calculate the direction vector from the fragment to the camera (origin)
     vec3 camDir = normalize(-Position.xyz);
 
-    // Invert the fragment normal if not FrontFacing
-    if (!gl_FrontFacing) {
+    // Workaround for gl_FrontFacing
+    #extension GL_OES_standard_derivatives : enable
+    vec3 fdx = dFdx(Position.xyz);
+    vec3 fdy = dFdy(Position.xyz);
+    vec3 faceNormal = normalize(cross(fdx,fdy));
+    if (dot(fragNormal, faceNormal) < 0.0) { // Back-facing
         fragNormal = -fragNormal;
     }