Browse Source

premultiplied alpha support

Sean Barrett 10 years ago
parent
commit
ba49d37e6a
2 changed files with 130 additions and 18 deletions
  1. 123 14
      stb_voxel_render.h
  2. 7 4
      tests/caveview/cave_mesher.c

+ 123 - 14
stb_voxel_render.h

@@ -1,7 +1,6 @@
 // @TODO
 //
 //   - API for texture rotation on side faces (& top&bottom ?)
-//   - premultiplied alpha
 //   - edge clamp
 //   - better culling of vheight faces with vheight neighbors
 //   - better culling of non-vheight faces with fheight neighbors
@@ -280,6 +279,7 @@ STBVXDEC void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_byt
 STBVXDEC stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm);
 STBVXDEC char *stbvox_get_vertex_shader(void);
 STBVXDEC char *stbvox_get_fragment_shader(void);
+STBVXDEC char *stbvox_get_fragment_shader_alpha_only(void);
 STBVXDEC void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh);
 STBVXDEC int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh);
 STBVXDEC void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3]);
@@ -754,7 +754,7 @@ static char *stbvox_vertex_encoderogram =
 
       // fragment output data
       "flat out uvec4  facedata;\n"
-      "     out  vec3  objectspace_pos;\n"
+      "     out  vec3  voxelspace_pos;\n"
       "     out  vec3  vnormal;\n"
       "     out float  texlerp;\n"
       "     out float  amb_occ;\n"
@@ -778,8 +778,8 @@ static char *stbvox_vertex_encoderogram =
       "   texlerp  = float( (attr_vertex >> 29u)        ) /  7.0;\n"      // a[29..31]
 
       "   vnormal = normal_table[(facedata.w>>2) & 31u];\n"
-      "   objectspace_pos = offset * transform[0];\n"  // object-to-world scale
-      "   vec3 position  = objectspace_pos + transform[1];\n"  // object-to-world translate
+      "   voxelspace_pos = offset * transform[0];\n"  // mesh-to-object scale
+      "   vec3 position  = voxelspace_pos + transform[1];\n"  // mesh-to-object translate
 
       #ifdef STBVOX_DEBUG_TEST_NORMALS
          "   if ((facedata.w & 28u) == 16u || (facedata.w & 28u) == 24u)\n"
@@ -812,7 +812,7 @@ static char *stbvox_fragment_program =
 
       // vertex-shader output data
       "flat in uvec4  facedata;\n"
-      "     in  vec3  objectspace_pos;\n"
+      "     in  vec3  voxelspace_pos;\n"
       "     in  vec3  vnormal;\n"
       "     in float  texlerp;\n"
       "     in float  amb_occ;\n"
@@ -847,7 +847,7 @@ static char *stbvox_fragment_program =
       "vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient);\n"
       #endif
       #if defined(STBVOX_CONFIG_FOG) || defined(STBVOX_CONFIG_FOG_SMOOTHSTEP)
-      "vec3 compute_fog(vec3 color, vec3 relative_pos);\n"
+      "vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha);\n"
       #endif
 
       "void main()\n"
@@ -878,7 +878,7 @@ static char *stbvox_fragment_program =
             "   vec4 color = texelFetch(color_table, int(color_id & 63u));\n"
          #endif
          "   vec2 texcoord;\n"
-         "   vec3 texturespace_pos = objectspace_pos + transform[2].xyz;\n"
+         "   vec3 texturespace_pos = voxelspace_pos + transform[2].xyz;\n"
          "   texcoord.s = dot(texturespace_pos, texgen_s);\n"
          "   texcoord.t = dot(texturespace_pos, texgen_t);\n"
 
@@ -893,13 +893,24 @@ static char *stbvox_fragment_program =
          "   if ((color_id &  64u) != 0u) tex1.xyz *= color.xyz;\n"
          "   if ((color_id & 128u) != 0u) tex2.xyz *= color.xyz;\n"
 
+         #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
+         "   tex2.rgba *= texlerp;\n"
+         #else
          "   tex2.a *= texlerp;\n"
+         #endif
 
          //  @TODO: could use a separate lookup table keyed on tex2 to determine this
          "   if (texblend_mode)\n"
          "      albedo = tex2.xyz * rlerp(tex2.a, 2.0*tex1.xyz, vec3(1.0,1.0,1.0));\n"
-         "   else\n"
-         "      albedo = rlerp(tex2.a, tex1.xyz, tex2.xyz);\n" // @TODO premultiplied alpha
+         "   else {\n"
+         #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
+         "      albedo = (1.0-tex2.a)*tex1.xyz + tex2.xyz;\n"
+         "      fragment_alpha = tex1.a;\n"
+         #else
+         "      albedo = rlerp(tex2.a, tex1.xyz, tex2.xyz);\n"
+         "      fragment_alpha = tex1.a*(1-tex2.a)+tex2.a;\n"
+         #endif
+         "   }\n"
 
          "   fragment_alpha = tex1.a;\n"
       #else // UNTEXTURED
@@ -926,7 +937,7 @@ static char *stbvox_fragment_program =
       "   vec3 lit_color;\n"
       "   if (!emissive)\n"
       #if defined(STBVOX_ICONFIG_LIGHTING) || defined(STBVOX_CONFIG_LIGHTING_SIMPLE)
-         "      lit_color = compute_lighting(objectspace_pos + transform[1], normal, albedo, ambient_color);\n"
+         "      lit_color = compute_lighting(voxelspace_pos + transform[1], normal, albedo, ambient_color);\n"
       #else
          "      lit_color = albedo * ambient_color ;\n"
       #endif
@@ -934,11 +945,15 @@ static char *stbvox_fragment_program =
       "      lit_color = albedo;\n"
 
       #if defined(STBVOX_ICONFIG_FOG) || defined(STBVOX_CONFIG_FOG_SMOOTHSTEP)
-         "   vec3 dist = objectspace_pos + (transform[1] - camera_pos.xyz);\n"
-         "   lit_color = compute_fog(lit_color, dist);\n"
+         "   vec3 dist = voxelspace_pos + (transform[1] - camera_pos.xyz);\n"
+         "   lit_color = compute_fog(lit_color, dist, fragment_alpha);\n"
       #endif
-
+      
+      #ifdef STBVOX_CONFIG_UNPREMULTIPLY
+      "   vec4 final_color = vec4(lit_color/fragment_alpha, fragment_alpha);\n"
+      #else
       "   vec4 final_color = vec4(lit_color, fragment_alpha);\n"
+      #endif
       "   outcolor = final_color;\n"
       "}\n"
 
@@ -956,17 +971,106 @@ static char *stbvox_fragment_program =
 
    #ifdef STBVOX_CONFIG_FOG_SMOOTHSTEP
       "\n"
-      "vec3 compute_fog(vec3 color, vec3 relative_pos)\n"
+      "vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha)\n"
       "{\n"
       "   float f = sqrt(dot(relative_pos,relative_pos))/1320.0;\n"
       "   f = clamp(f, 0.0, 1.0);\n" 
       "   f = 3.0*f*f - 2.0*f*f*f;\n" // smoothstep
       "   f = f*f;\n"  // fade in more smoothly
+      #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
+      "   return rlerp(f, color.xyz, ambient[3]*fragment_alpha);\n"
+      #else
       "   return rlerp(f, color.xyz, ambient[3]);\n"
+      #endif
       "}\n"
    #endif
 };
 
+
+static char *stbvox_fragment_program_alpha_only =
+{
+   STBVOX_SHADER_VERSION
+
+   // vertex-shader output data
+   "flat in uvec4  facedata;\n"
+   "     in  vec3  voxelspace_pos;\n"
+   "     in float  texlerp;\n"
+
+   // per-buffer data
+   "uniform vec3 transform[3];\n"
+
+   #ifndef STBVOX_ICONFIG_UNTEXTURED
+      // generally constant data
+      "uniform sampler2DArray tex_array[2];\n"
+
+      #ifdef STBVOX_CONFIG_PREFER_TEXBUFFER
+         "uniform samplerBuffer texscale;\n"
+         "uniform samplerBuffer texgen;\n"
+      #else
+         "uniform vec2 texscale[64];\n" // instead of 128, to avoid running out of uniforms
+         "uniform vec3 texgen[64];\n"
+      #endif
+   #endif
+
+   "out vec4  outcolor;\n"
+
+   "void main()\n"
+   "{\n"
+   "   vec3 albedo;\n"
+   "   float fragment_alpha;\n"
+
+   #ifndef STBVOX_ICONFIG_UNTEXTURED
+      // unpack the values
+      "   uint tex1_id = facedata.x;\n"
+      "   uint tex2_id = facedata.y;\n"
+      "   uint texprojid = facedata.w & 31u;\n"
+      "   bool texblend_mode = ((facedata.w & 128u) != 0u);\n"
+
+      #ifndef STBVOX_CONFIG_PREFER_TEXBUFFER
+         // load from uniforms / texture buffers 
+         "   vec3 texgen_s = texgen[texprojid];\n"
+         "   vec3 texgen_t = texgen[texprojid+32u];\n"
+         "   float tex1_scale = texscale[tex1_id & 63u].x;\n"
+         "   float tex2_scale = texscale[tex2_id & 63u].y;\n"
+      #else
+         "   vec3 texgen_s = texelFetch(texgen, int(texprojid)).xyz;\n"
+         "   vec3 texgen_t = texelFetch(texgen, int(texprojid+32u)).xyz;\n"
+         "   float tex1_scale = texelFetch(texscale, int(tex1_id & 127u)).x;\n"
+         "   float tex2_scale = texelFetch(texscale, int(tex2_id & 127u)).y;\n"
+      #endif
+      "   vec2 texcoord;\n"
+      "   vec3 texturespace_pos = voxelspace_pos + transform[2].xyz;\n"
+      "   texcoord.s = dot(texturespace_pos, texgen_s);\n"
+      "   texcoord.t = dot(texturespace_pos, texgen_t);\n"
+
+      // @TODO: use 2 bits of facedata.w to enable animation of facedata.x & y?
+
+      "   vec4 tex1 = texture(tex_array[0], vec3(tex1_scale * texcoord, float(tex1_id)));\n"
+      "   vec4 tex2 = texture(tex_array[1], vec3(tex2_scale * texcoord, float(tex2_id)));\n"
+
+      "   tex2.a *= texlerp;\n"
+
+      //  @TODO: could use a separate lookup table keyed on tex2 to determine this
+      "   if (texblend_mode)\n"
+      "      ;\n"
+      "   else {\n"
+      #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
+      "      fragment_alpha = tex1.a;\n"
+      #else
+      "      fragment_alpha = tex1.a*(1-tex2.a)+tex2.a;\n"
+      #endif
+      "   }\n"
+
+   #else // UNTEXTURED
+      "   vec4 color;"
+      "   fragment_alpha = 1.0;\n"
+   #endif
+
+   "   outcolor = vec4(0.0, 0.0, 0.0, fragment_alpha);\n"
+   "}\n"
+};
+
+
 STBVXDEC char *stbvox_get_vertex_shader(void)
 {
    return stbvox_vertex_encoderogram;
@@ -977,6 +1081,11 @@ STBVXDEC char *stbvox_get_fragment_shader(void)
    return stbvox_fragment_program;
 }
 
+STBVXDEC char *stbvox_get_fragment_shader_alpha_only(void)
+{
+   return stbvox_fragment_program_alpha_only;
+}
+
 static float stbvox_dummy_transform[3][3];
 
 #ifdef STBVOX_CONFIG_PREFER_TEXBUFFER

+ 7 - 4
tests/caveview/cave_mesher.c

@@ -21,7 +21,8 @@
 #define STBVOX_CONFIG_PREFER_TEXBUFFER
 //#define STBVOX_CONFIG_LIGHTING_SIMPLE
 #define STBVOX_CONFIG_FOG_SMOOTHSTEP
-
+#define STBVOX_CONFIG_PREMULTIPLIED_ALPHA  // use this even though it doesn't really work for alpha test without next #define
+//#define STBVOX_CONFIG_UNPREMULTIPLY  // slower, makes windows & fancy leaves look better
 
 #define STBVOX_ROTATION_IN_LIGHTING
 #define STB_VOXEL_RENDER_IMPLEMENTATION
@@ -33,7 +34,9 @@ extern void ods(char *fmt, ...);
 #define FAST_CHUNK
 #define IN_PLACE
 
-#define SKIP_TERRAIN   0 // must be a multiple of 16; doesn't build some underground stuff
+#define SKIP_TERRAIN   0 // use to avoid building underground stuff
+                         // allows you to see what perf would be like if underground was efficiently culled,
+                         // or if you were making a game without underground
 
 enum
 {
@@ -189,7 +192,7 @@ unsigned char minecraft_info[256][7] =
    { C_empty },
    { C_solid, 54,54,54,54,54,54 },
    { C_solid, 125,125,125,125,125,125 },
-   { C_solid, 124,124,124,124,124,124 },
+   { C_solid, 126,126,126,126,126,126 },
    { C_empty }, // bars
    { C_trans, 49,49,49,49,49,49 }, // glass pane
    { C_solid, 136,136,136,136,137,137 }, // melon
@@ -227,7 +230,7 @@ unsigned char minecraft_info[256][7] =
    // 128
    { C_solid, 192,192,192,192,176,176 }, // sandstone stairs
    { C_solid, 32,32,32,32,32,32 }, // emerald ore
-   { C_empty }, // ender chest
+   { C_solid, 26,26,26,27,25,25 }, // ender chest
    { C_empty },
    { C_empty },
    { C_solid, 23,23,23,23,23,23 }, // emerald block