correct normals for vheight floors

This commit is contained in:
Sean Barrett 2015-03-14 15:02:51 -07:00
parent c10b3fefae
commit 00810b7d11
3 changed files with 473 additions and 116 deletions

View File

@ -327,10 +327,10 @@ enum
STBVOX_GEOM_force, // all faces always visible, e.g. minecraft fancy leaves
// these access vheight input
STBVOX_GEOM_floor_vheight_02 = 12, // diagonal is SW-NE -- assuming index buffer 0,1,2,0,2,3
STBVOX_GEOM_floor_vheight_13, // diagonal is SE-NW -- assuming index buffer 0,1,2,0,2,3
STBVOX_GEOM_ceil_vheight_02,
STBVOX_GEOM_ceil_vheight_13,
STBVOX_GEOM_floor_vheight_03 = 12, // diagonal is SW-NE
STBVOX_GEOM_floor_vheight_12, // diagonal is SE-NW
STBVOX_GEOM_ceil_vheight_03,
STBVOX_GEOM_ceil_vheight_12,
STBVOX_GEOM_count, // number of geom cases
};
@ -551,51 +551,62 @@ struct stbvox_mesh_maker
// mode, and all the bits to choose the normal.
// Thus the bottom 3 bits have to be:
// e, n, w, s, u, d, u, d
//
// These use compact names so tables are readable
enum
{
STBVOX_EFACE_east,
STBVOX_EFACE_north,
STBVOX_EFACE_west,
STBVOX_EFACE_south,
STBVOX_EFACE_up,
STBVOX_EFACE_down,
STBVOX_EFACE_east_up,
STBVOX_EFACE_east_down,
STBVF_e,
STBVF_n,
STBVF_w,
STBVF_s,
STBVF_u,
STBVF_d,
STBVF_eu,
STBVF_ed,
STBVOX_EFACE_east_up_wall,
STBVOX_EFACE_north_up_wall,
STBVOX_EFACE_west_up_wall,
STBVOX_EFACE_south_up_wall,
STBVOX_EFACE_dummy_up_2,
STBVOX_EFACE_dummy_down_2,
STBVOX_EFACE_north_up,
STBVOX_EFACE_north_down,
STBVF_eu_wall,
STBVF_nu_wall,
STBVF_wu_wall,
STBVF_su_wall,
STBVF_ne_u,
STBVF_ne_d,
STBVF_nu,
STBVF_nd,
STBVOX_EFACE_ne_up,
STBVOX_EFACE_nw_up,
STBVOX_EFACE_sw_up,
STBVOX_EFACE_se_up,
STBVOX_EFACE_dummy_up_3,
STBVOX_EFACE_dummy_down_3,
STBVOX_EFACE_west_up,
STBVOX_EFACE_west_down,
STBVF_ed_wall,
STBVF_nd_wall,
STBVF_wd_wall,
STBVF_sd_wall,
STBVF_nw_u,
STBVF_nw_d,
STBVF_wu,
STBVF_wd,
STBVOX_EFACE_ne_down,
STBVOX_EFACE_nw_down,
STBVOX_EFACE_sw_down,
STBVOX_EFACE_se_down,
STBVOX_EFACE_dummy_up_4,
STBVOX_EFACE_dummy_down_4,
STBVOX_EFACE_south_up,
STBVOX_EFACE_south_down,
STBVF_ne_u_cross,
STBVF_nw_u_cross,
STBVF_sw_u_cross,
STBVF_se_u_cross,
STBVF_sw_u,
STBVF_sw_d,
STBVF_su,
STBVF_sd,
// @TODO either we need more than 5 bits to encode the normal to fit these, or we can replace 'dummy' above with them but need to use full-size texgen table
// so for now we just texture them with the wrong projection
STBVOX_EFACE_east_down_wall = STBVOX_EFACE_east_down,
STBVOX_EFACE_north_down_wall = STBVOX_EFACE_north_down,
STBVOX_EFACE_west_down_wall = STBVOX_EFACE_west_down,
STBVOX_EFACE_south_down_wall = STBVOX_EFACE_south_down,
// @TODO we need more than 5 bits to encode the normal to fit the following
// so for now we use the right projection but the wrong normal
STBVF_se_u = STBVF_su,
STBVF_se_d = STBVF_sd,
STBVF_count,
};
// get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
static unsigned char stbvox_reverse_face[STBVF_count] =
{
STBVF_w, STBVF_s, STBVF_e, STBVF_n, STBVF_d , STBVF_u , STBVF_wd, STBVF_wu,
0, 0, 0, 0, STBVF_sw_d, STBVF_sw_u, STBVF_sd, STBVF_su,
0, 0, 0, 0, STBVF_se_d, STBVF_se_u, STBVF_ed, STBVF_eu,
0, 0, 0, 0, STBVF_ne_d, STBVF_ne_d, STBVF_nd, STBVF_nu
};
static float stbvox_default_texgen[2][32][3] =
@ -638,26 +649,26 @@ static float stbvox_default_normals[32][3] =
{ 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
{ -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
{ 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
{ 0,0,1 }, // up
{ 0,0,-1 }, // down
{ STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // ne & up
{ STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // ne & down
{ 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
{ 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
{ STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NE & up
{ -STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NW & up
{ -STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SW & up
{ STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SE & up
{ 0,0,1 }, // up
{ 0,0,-1 }, // down
{ STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
{ 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
{ -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
{ 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
{ -STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // NW & up
{ -STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NW & down
{ -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
{ -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
{ STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NE & down
{ -STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NW & down
{ -STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SW & down
{ STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SE & down
{ 0,0,1 }, // up
{ 0,0,-1 }, // down
{ STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NE & up crossed
{ -STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NW & up crossed
{ -STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SW & up crossed
{ STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SE & up crossed
{ -STBVOX_RSQRT3,-STBVOX_RSQRT3, STBVOX_RSQRT3 }, // SW & up
{ -STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SW & up
{ 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
{ 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
};
@ -758,6 +769,9 @@ stbvox_tagged_string stbvox_vertex_program[] =
// per-buffer data
"uniform vec3 transform[3];\n"
// per-frame data
"uniform vec4 camera_pos;\n" // 4th value is used for arbitrary hacking
// to simplify things, we avoid using more than 256 uniform vectors
// in fragment shader to avoid possible 1024 component limit, so
// we access this table in the fragment shader.
@ -802,6 +816,10 @@ stbvox_tagged_string stbvox_vertex_program[] =
" 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
#if 0 // normal debugging
" if ((facedata.w & 28u) == 16u || (facedata.w & 28u) == 24u)\n"
" position += vnormal.xyz * camera_pos.w;\n"
#endif
},
{ STBVOX_TAG_NOT | STBVOX_TAG_gl_modelview,
@ -846,7 +864,7 @@ stbvox_tagged_string stbvox_fragment_program[] =
"uniform vec3 transform[3];\n"
// per-frame data
"uniform vec3 camera_pos;\n"
"uniform vec4 camera_pos;\n" // 4th value is used for arbitrary hacking
// probably constant data
"uniform vec3 ambient[4];\n"
@ -955,7 +973,7 @@ stbvox_tagged_string stbvox_fragment_program[] =
" amb_color *= amb_occ;\n"
" vec3 lit_color;\n"
" vec3 lighting = compute_lighting(objectspace_pos + transform[1], normal) + amb_color * 0.25;\n"
" vec3 lighting = compute_lighting(objectspace_pos + transform[1], normal) + amb_color;\n"
" if (!emissive)\n"
" lit_color = lighting * albedo;\n"
" else\n"
@ -967,7 +985,7 @@ stbvox_tagged_string stbvox_fragment_program[] =
// smoothstep fog:
#if 1
" vec3 dist = objectspace_pos + (transform[1] - camera_pos);\n"
" vec3 dist = objectspace_pos + (transform[1] - camera_pos.xyz);\n"
" float f = sqrt(dot(dist,dist))/1320.0;\n"
" f = clamp(f, 0.0, 1.0);\n"
" f = 3.0*f*f - 2.0*f*f*f;\n" // smoothstep
@ -985,7 +1003,7 @@ stbvox_tagged_string stbvox_fragment_program[] =
"{\n"
" vec3 light_dir = light_source[0] - pos;\n"
" float lambert = dot(light_dir, norm) / dot(light_dir, light_dir);\n"
" return light_source[1] * clamp(lambert, 0.0, 1.0);\n"
" return clamp(light_source[1] * clamp(lambert, 0.0, 1.0), 0.0, 1.0);\n"
"}\n"
},
};
@ -1052,7 +1070,7 @@ stbvox_uniform_info stbvox_uniforms[] =
{ STBVOX_UNIFORM_TYPE_vec3 , 12, 64, "texgen" , stbvox_default_texgen[0][0] , STBVOX_TAG_textured },
{ STBVOX_UNIFORM_TYPE_vec3 , 12, 4, "ambient" , 0 , STBVOX_TAG_all },
{ STBVOX_UNIFORM_TYPE_vec3 , 12, 1, "camera_pos" , stbvox_dummy_transform[0] , STBVOX_TAG_all },
{ STBVOX_UNIFORM_TYPE_vec4 , 12, 1, "camera_pos" , stbvox_dummy_transform[0] , STBVOX_TAG_all },
};
stbvox_uniform_info *stbvox_get_uniform_info(stbvox_mesh_maker *mm, int uniform)
@ -1458,31 +1476,54 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
}
}
static stbvox_face_up_normal_012[4][4][4];
static stbvox_face_up_normal_013[4][4][4];
static stbvox_face_up_normal_023[4][4][4];
static stbvox_face_up_normal_123[4][4][4];
// render non-planar quads by splitting into two triangles, rendering each as a degenerate quad
void stbvox_make_02_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face1, int face2, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh)
void stbvox_make_12_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
{
stbvox_mesh_vertex v[4];
v[0] = face_coord[0];
v[1] = face_coord[1];
v[2] = face_coord[2];
v[3] = face_coord[0];
stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh, face1);
v[1] = face_coord[2];
v[2] = face_coord[3];
stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh, face2);
unsigned char normal1 = stbvox_face_up_normal_012[ht[2]][ht[1]][ht[0]];
unsigned char normal2 = stbvox_face_up_normal_123[ht[3]][ht[2]][ht[1]];
if (face == STBVOX_FACE_down) {
normal1 = stbvox_reverse_face[normal1];
normal2 = stbvox_reverse_face[normal2];
}
// the floor side face_coord is stored in order NW,NE,SE,SW, but ht[] is stored SW,SE,NW,NE
v[0] = face_coord[2];
v[1] = face_coord[3];
v[2] = face_coord[0];
v[3] = face_coord[2];
stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal1);
v[1] = face_coord[0];
v[2] = face_coord[1];
stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2);
}
void stbvox_make_13_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face1, int face2, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh)
void stbvox_make_03_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
{
stbvox_mesh_vertex v[4];
unsigned char normal1 = stbvox_face_up_normal_013[ht[3]][ht[1]][ht[0]];
unsigned char normal2 = stbvox_face_up_normal_023[ht[3]][ht[2]][ht[0]];
if (face == STBVOX_FACE_down) {
normal1 = stbvox_reverse_face[normal1];
normal2 = stbvox_reverse_face[normal2];
}
v[0] = face_coord[1];
v[1] = face_coord[2];
v[2] = face_coord[3];
v[3] = face_coord[1];
stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh, face1);
stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal1);
v[1] = face_coord[3];
v[2] = face_coord[0];
stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh, face2);
stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2); // this one is correct!
}
// simple case for mesh generation: we have only solid and empty blocks
@ -1624,18 +1665,18 @@ static unsigned char stbvox_facetype[STBVOX_GEOM_count][6] =
// @TODO this could be done with math given the current arrangement of the enum, but let's not require it
static unsigned char stbvox_floor_slope_for_rot[4] =
{
STBVOX_EFACE_south_up,
STBVOX_EFACE_west_up, // @TODO: why is this reversed from what it should be? this is a north-is-up face, so slope should be south&up
STBVOX_EFACE_north_up,
STBVOX_EFACE_east_up,
STBVF_su,
STBVF_wu, // @TODO: why is this reversed from what it should be? this is a north-is-up face, so slope should be south&up
STBVF_nu,
STBVF_eu,
};
static unsigned char stbvox_ceil_slope_for_rot[4] =
{
STBVOX_EFACE_south_down,
STBVOX_EFACE_east_down,
STBVOX_EFACE_north_down,
STBVOX_EFACE_west_down,
STBVF_sd,
STBVF_ed,
STBVF_nd,
STBVF_wd,
};
// this table indicates whether, for each pair of types above, a face is visible.
@ -1693,6 +1734,233 @@ static unsigned char stbvox_rotate_vertex[8][4] =
{ 7,6,4,5 }, // zyx=111
};
#ifdef STBVOX_OPTIMIZED_VHEIGHT
// optimized vheight generates a single normal over the entire face, even if it's not planar
static stbvox_optimized_face_up_normal[4][4][4][4] =
{
{
{
{ STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_nu , },
},{
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
{ STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
},{
{ STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
{ STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
},{
{ STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
{ STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
},
},{
{
{ STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
{ STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
{ STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
},{
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
},{
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
},
},{
{
{ STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
{ STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
{ STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
{ STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
},{
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
{ STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
{ STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
{ STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
},
},{
{
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
{ STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
{ STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
{ STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
},{
{ STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
{ STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
{ STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
},{
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
{ STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
},{
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
},
},
};
#else
// which normal to use for a given vheight that's planar
// @TODO: this table was constructed by hand and may have bugs
// nw se sw
static stbvox_planar_face_up_normal[4][4][4] =
{
{ // sw,se,nw,ne
{ STBVF_u , 0 , 0 , 0 }, // 0,0,0,0; 1,0,0,-1; 2,0,0,-2; 3,0,0,-3;
{ STBVF_u , STBVF_u , 0 , 0 }, // 0,1,0,1; 1,1,0, 0; 2,1,0,-1; 3,1,0,-2;
{ STBVF_wu , STBVF_nw_u, STBVF_nu , 0 }, // 0,2,0,2; 1,2,0, 1; 2,2,0, 0; 3,2,0,-1;
{ STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu }, // 0,3,0,3; 1,3,0, 2; 2,3,0, 1; 3,3,0, 0;
},{
{ STBVF_u , STBVF_u , 0 , 0 }, // 0,0,1,1; 1,0,1, 0; 2,0,1,-1; 3,0,1,-2;
{ STBVF_sw_u, STBVF_u , STBVF_ne_u, 0 }, // 0,1,1,2; 1,1,1, 1; 2,1,1, 0; 3,1,1,-1;
{ STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,2,1,3; 1,2,1, 2; 2,2,1, 1; 3,2,1, 0;
{ 0 , STBVF_w , STBVF_nw_u, STBVF_nu }, // 0,3,1,4; 1,3,1, 3; 2,3,1, 2; 3,3,1, 1;
},{
{ STBVF_su , STBVF_se_u, STBVF_eu , 0 }, // 0,0,2,2; 1,0,2, 1; 2,0,2, 0; 3,0,2,-1;
{ STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,1,2,3; 1,1,2, 2; 2,1,2, 1; 3,1,2, 0;
{ 0 , STBVF_sw_u, STBVF_u , STBVF_ne_u }, // 0,2,2,4; 1,2,2, 3; 2,2,2, 2; 3,2,2, 1;
{ 0 , 0 , STBVF_u , STBVF_u }, // 0,3,2,5; 1,3,2, 4; 2,3,2, 3; 3,3,2, 2;
},{
{ STBVF_su , STBVF_se_u, STBVF_se_u, STBVF_eu }, // 0,0,3,3; 1,0,3, 2; 2,0,3, 1; 3,0,3, 0;
{ 0 , STBVF_su , STBVF_se_u, STBVF_eu }, // 0,1,3,4; 1,1,3, 3; 2,1,3, 2; 3,1,3, 1;
{ 0 , 0 , STBVF_u , STBVF_u }, // 0,2,3,5; 1,2,3, 4; 2,2,3, 3; 3,2,3, 2;
{ 0 , 0 , 0 , STBVF_u }, // 0,3,3,6; 1,3,3, 5; 2,3,3, 4; 3,3,3, 3;
}
};
// these tables were constructed automatically using a variant of the code
// below; however, they seem wrong, so who knows
static stbvox_face_up_normal_012[4][4][4] =
{
{
{ STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
{ STBVF_wu , STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
{ STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_sw_u, STBVF_wu , STBVF_nu , STBVF_ne_u, },
{ STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
{ STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_ne_u, },
{ STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
{ STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nu , },
},{
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
}
};
static stbvox_face_up_normal_013[4][4][4] =
{
{
{ STBVF_u , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_nw_u, STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
{ STBVF_wu , STBVF_u , STBVF_eu , STBVF_eu , },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
{ STBVF_wu , STBVF_wu , STBVF_u , STBVF_eu , },
{ STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
},{
{ STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
{ STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
{ STBVF_wu , STBVF_wu , STBVF_wu , STBVF_u , },
}
};
static stbvox_face_up_normal_023[4][4][4] =
{
{
{ STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
{ STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
{ STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
},{
{ STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
{ STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
},{
{ STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
{ STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
{ STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
{ STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
},{
{ STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
{ STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
{ STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
{ STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
}
};
static stbvox_face_up_normal_123[4][4][4] =
{
{
{ STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
{ STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
{ STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
{ STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
},{
{ STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
{ STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
{ STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
{ STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
},{
{ STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
{ STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
{ STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
{ STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
},{
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
{ STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
{ STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
}
};
#endif
void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off)
{
int ns_off = mm->y_stride_in_bytes;
@ -1911,7 +2179,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
if (visible_faces & (1 << STBVOX_FACE_west))
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
}
if (geo >= STBVOX_GEOM_floor_vheight_02) {
if (geo >= STBVOX_GEOM_floor_vheight_03) {
// this case can also be generated with regular block gen with special vmesh,
// except:
// if we want to generate middle diagonal for 'weird' blocks
@ -1951,7 +2219,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
// our visible_faces test was wrong
extreme = (ht[0] == 3 || ht[1] == 3 || ht[2] == 3 || ht[3] == 3);
if (geo >= STBVOX_GEOM_ceil_vheight_02) {
if (geo >= STBVOX_GEOM_ceil_vheight_03) {
cube[0] = stbvox_vertex_p(0,0,ht[0],0,0);
cube[1] = stbvox_vertex_p(0,0,ht[1],0,0);
cube[2] = stbvox_vertex_p(0,0,ht[2],0,0);
@ -1992,30 +2260,44 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
// @TODO generate split faces
if (visible_faces & (1 << STBVOX_FACE_up)) {
#ifndef STBVOX_OPTIMIZED_VHEIGHT
// check if it's planar
if (geo < STBVOX_GEOM_ceil_vheight_02 && cube[5] + cube[6] != cube[4] + cube[7]) {
// not planar, split along diagonal and make degenerate
if (geo == STBVOX_GEOM_floor_vheight_02)
stbvox_make_02_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
else
stbvox_make_13_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
} else
#endif
if (geo >= STBVOX_GEOM_ceil_vheight_03)
// flat
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
else {
#ifndef STBVOX_OPTIMIZED_VHEIGHT
// check if it's non-planar
if (cube[5] + cube[6] != cube[4] + cube[7]) {
// not planar, split along diagonal and make degenerate quads
if (geo == STBVOX_GEOM_floor_vheight_03)
stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
else
stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
} else
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]);
#else
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]);
#endif
}
}
if (visible_faces & (1 << STBVOX_FACE_down)) {
#ifndef STBVOX_OPTIMIZED_VHEIGHT
// check if it's planar
if (geo >= STBVOX_GEOM_ceil_vheight_02 && cube[1] + cube[2] != cube[0] + cube[3]) {
// not planar, split along diagonal and make degenerate
if (geo == STBVOX_GEOM_ceil_vheight_02)
stbvox_make_02_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
else
stbvox_make_13_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
} else
#endif
if (geo < STBVOX_GEOM_ceil_vheight_03)
// flat
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
else {
#ifndef STBVOX_OPTIMIZED_VHEIGHT
// check if it's non-planar
if (cube[1] + cube[2] != cube[0] + cube[3]) {
// not planar, split along diagonal and make degenerate quads
if (geo == STBVOX_GEOM_ceil_vheight_03)
stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
else
stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
} else
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]]);
#else
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]]);
#endif
}
}
if (mm->input.rotate) {
@ -2067,10 +2349,10 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
}
rot.facerot = 0;
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh, STBVOX_EFACE_ne_up);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh, STBVOX_EFACE_sw_up);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh, STBVOX_EFACE_se_up);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh, STBVOX_EFACE_nw_up);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh, STBVF_ne_u_cross);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh, STBVF_sw_u_cross);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh, STBVF_se_u_cross);
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh, STBVF_nw_u_cross);
}
@ -2357,4 +2639,57 @@ void stbvox_config_set_z_precision(stbvox_mesh_maker *mm, int z_fractional_bits)
}
/////////////////////////////////////////////////////////////////////////////
//
// offline computation
//
#if 0
// compute optimized vheight table
static char *normal_names[32] =
{
0,0,0,0,"u ",0, "eu ",0,
0,0,0,0,"ne_u",0, "nu ",0,
0,0,0,0,"nw_u",0, "wu ",0,
0,0,0,0,"sw_u",0, "su ",0,
};
static char *find_best_normal(float x, float y, float z)
{
int best_slot = 4;
float best_dot = 0;
int i;
for (i=0; i < 32; ++i) {
if (normal_names[i]) {
float dot = x * stbvox_default_normals[i].x + y * stbvox_default_normals[i].y + z * stbvox_default_normals[i].z;
if (dot > best_dot) {
best_dot = dot;
best_slot = i;
}
}
}
return normal_names[best_slot];
}
int main(int argc, char **argv)
{
int sw,se,nw,ne;
for (ne=0; ne < 4; ++ne) {
for (nw=0; nw < 4; ++nw) {
for (se=0; se < 4; ++se) {
printf(" { ");
for (sw=0; sw < 4; ++sw) {
float x = (float) (nw + sw - ne - se);
float y = (float) (sw + se - nw - ne);
float z = 2;
printf("STBVF_%s, ", find_best_normal(x,y,z));
}
printf("},\n");
}
}
}
return 0;
}
#endif
#endif // STB_VOXEL_RENDER_IMPLEMENTATION

View File

@ -13,8 +13,11 @@
#include "sdl_thread.h"
#include <math.h>
#define STB_VOXEL_RENDER_IMPLEMENTATION
//#define VHEIGHT_TEST
//#define STBVOX_OPTIMIZED_VHEIGHT
#define STBVOX_ROTATION_IN_LIGHTING
#define STB_VOXEL_RENDER_IMPLEMENTATION
#include "stb_voxel_render.h"
extern void ods(char *fmt, ...);
@ -585,7 +588,9 @@ void build_chunk(int chunk_x, int chunk_y, fast_chunk *fc_table[4][4], raw_mesh
int a,b,z;
stbvox_input_description *map;
//unsigned char vheight[34][34][18];
#ifdef VHEIGHT_TEST
unsigned char vheight[34][34][18];
#endif
assert((chunk_x & 1) == 0);
assert((chunk_y & 1) == 0);
@ -632,7 +637,7 @@ void build_chunk(int chunk_x, int chunk_y, fast_chunk *fc_table[4][4], raw_mesh
map->blocktype = &rm->sv_blocktype[1][1][1-z]; // specify location of 0,0,0 so that accessing z0..z1 gets right data
map->lighting = &rm->sv_lighting[1][1][1-z];
#if 0
#ifdef VHEIGHT_TEST
// hacky test of vheight
for (a=0; a < 34; ++a) {
for (b=0; b < 34; ++b) {
@ -640,8 +645,12 @@ void build_chunk(int chunk_x, int chunk_y, fast_chunk *fc_table[4][4], raw_mesh
for (c=0; c < 17; ++c) {
if (rm->sv_blocktype[a][b][c] != 0 && rm->sv_blocktype[a][b][c+1] == 0) {
// topmost block
rm->sv_blocktype[a][b][c] = 168;
vheight[a][b][c] = rand() & 255;
rm->sv_blocktype[a][b][c] = 168;
} else if (c > 0 && rm->sv_blocktype[a][b][c] != 0 && rm->sv_blocktype[a][b][c-1] == 0) {
// bottommost block
vheight[a][b][c] = ((rand() % 3) << 6) + ((rand() % 3) << 4) + ((rand() % 3) << 2) + (rand() % 3);
rm->sv_blocktype[a][b][c] = 169;
}
}
vheight[a][b][c] = STBVOX_MAKE_VHEIGHT(2,2,2,2); // flat top
@ -792,7 +801,7 @@ void mesh_init(void)
minecraft_color_for_blocktype[11][i] = 63; // emissive
}
#if 0 // vheight test
#ifdef VHEIGHT_TEST
effective_blocktype[168] = 168;
minecraft_tex1_for_blocktype[168][0] = 1;
minecraft_tex1_for_blocktype[168][1] = 1;
@ -800,7 +809,15 @@ void mesh_init(void)
minecraft_tex1_for_blocktype[168][3] = 1;
minecraft_tex1_for_blocktype[168][4] = 1;
minecraft_tex1_for_blocktype[168][5] = 1;
minecraft_geom_for_blocktype[168] = STBVOX_GEOM_floor_vheight_02;
minecraft_geom_for_blocktype[168] = STBVOX_GEOM_floor_vheight_12;
effective_blocktype[169] = 169;
minecraft_tex1_for_blocktype[169][0] = 1;
minecraft_tex1_for_blocktype[169][1] = 1;
minecraft_tex1_for_blocktype[169][2] = 1;
minecraft_tex1_for_blocktype[169][3] = 1;
minecraft_tex1_for_blocktype[169][4] = 1;
minecraft_tex1_for_blocktype[169][5] = 1;
minecraft_geom_for_blocktype[169] = STBVOX_GEOM_ceil_vheight_03;
#endif
remap[53] = 1;

View File

@ -184,9 +184,12 @@ GLint uniform_loc[16];
float table3[128][3];
GLint tablei[2];
float step=0;
void setup_uniforms(float pos[3])
{
int i,j;
step += 1.0f/60.0f;
for (i=0; i < STBVOX_UNIFORM_count; ++i) {
stbvox_uniform_info *ui = stbvox_get_uniform_info(&g_mesh_maker, i);
uniform_loc[i] = -1;
@ -224,9 +227,11 @@ void setup_uniforms(float pos[3])
table3[0][0] = pos[0];
table3[0][1] = pos[1];
table3[0][2] = pos[2];
table3[0][3] = stb_max(0,(float)sin(step*2)*0.125f);
break;
case STBVOX_UNIFORM_ambient: {
float bright = 0.75;
float amb[3][3];
// ambient direction is sky-colored upwards
@ -245,8 +250,8 @@ void setup_uniforms(float pos[3])
// amb[1] + (amb[2] - amb[1]) * dot/2 + (amb[2]-amb[1])/2
for (j=0; j < 3; ++j) {
table3[1][j] = (amb[2][j] - amb[1][j])/2;
table3[2][j] = (amb[1][j] + amb[2][j])/2;
table3[1][j] = (amb[2][j] - amb[1][j])/2 * bright;
table3[2][j] = (amb[1][j] + amb[2][j])/2 * bright;
}
// fog color
@ -783,7 +788,7 @@ void render_caves(float campos[3])
{
float lighting[2][3] = { { campos[0],campos[1],campos[2] }, { 0.75,0.75,0.65f } };
float bright = 15;
float bright = 8;
lighting[1][0] *= bright;
lighting[1][1] *= bright;
lighting[1][2] *= bright;