Random Buildings - improved texture mapping

Previously the front and side faces of random/OSM buildings
had identical texture coordinates.  This resulted in the sides
of buildings texture mapping being squeezed or stretched.

This change generates a separate texture mapping for the sides
of the buildings.
This commit is contained in:
Stuart Buchanan
2019-11-23 17:05:20 +00:00
parent 595eb3efea
commit d5957b8c5f
2 changed files with 54 additions and 49 deletions
+52 -47
View File
@@ -83,7 +83,8 @@ struct MakeBuildingLeaf
osg::Vec3Array* n = new osg::Vec3Array; osg::Vec3Array* n = new osg::Vec3Array;
osg::Vec4Array* c = new osg::Vec4Array; osg::Vec4Array* c = new osg::Vec4Array;
// Color array is used to identify the different building faces by the // Color array is used to identify the different building faces by the
// vertex shader for texture mapping. // vertex shader for texture mapping:
// (front, roof, roof top vertex, side)
v->reserve(52); v->reserve(52);
t->reserve(52); t->reserve(52);
@@ -174,7 +175,7 @@ struct MakeBuildingLeaf
for (int i=0; i<4; ++i) { for (int i=0; i<4; ++i) {
n->push_back( osg::Vec3(0, -1, 0) ); // normal n->push_back( osg::Vec3(0, -1, 0) ); // normal
c->push_back( osg::Vec4(1, 0, 0, 0) ); // color - used to differentiate wall from roof c->push_back( osg::Vec4(0, 0, 0, 1) ); // color - used to differentiate wall from roof
} }
// Back face // Back face
@@ -206,7 +207,7 @@ struct MakeBuildingLeaf
for (int i=0; i<4; ++i) { for (int i=0; i<4; ++i) {
n->push_back( osg::Vec3(0, 1, 0) ); // normal n->push_back( osg::Vec3(0, 1, 0) ); // normal
c->push_back( osg::Vec4(1, 0, 0, 0) ); // color - used to differentiate wall from roof c->push_back( osg::Vec4(0, 0, 0, 1) ); // color - used to differentiate wall from roof
} }
// ROOF 1 - built as a block. The shader will deform it to the correct shape. // ROOF 1 - built as a block. The shader will deform it to the correct shape.
@@ -369,9 +370,9 @@ struct AddBuildingLeafObject
osg::Vec3Array* positions = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_POSITION_ATTR)); // (x,y,z) osg::Vec3Array* positions = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_POSITION_ATTR)); // (x,y,z)
osg::Vec3Array* scale = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_SCALE_ATTR)); // (width, depth, height) osg::Vec3Array* scale = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_SCALE_ATTR)); // (width, depth, height)
osg::Vec3Array* rot = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_ROT_PITCH_TEX0X_ATTR)); // (rotation, pitch height, wall texture x offset) osg::Vec3Array* rot = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_ROT_PITCH_TEX0X_ATTR)); // (rotation, pitch height, wall texture x0)
osg::Vec3Array* tex = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_TEX0Y_TEX1X_TEX1Y_ATTR)); // (wall texture y offset, wall/roof texture x gain, wall/roof texture y gain) osg::Vec3Array* tex = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_TEX0Y_TEX1X_TEX1Y_ATTR)); // (wall texture y0, front/roof texture x1, front/side/roof texture y1)
osg::Vec3Array* rtex = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_RTEX0X_RTEX0Y_ATTR)); // (roof texture x offset, roof texture y offset, unused) osg::Vec3Array* rtex = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_RTEX0X_RTEX0Y_ATTR)); // (roof texture x0, roof texture y0, side texture x1)
osg::Vec3Array* rooftops = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_ROFFTOPSCALE_ATTR)); // (rooftop scale x, rooftop scale y, unused) osg::Vec3Array* rooftops = static_cast<osg::Vec3Array*> (geom->getVertexAttribArray(BUILDING_ROFFTOPSCALE_ATTR)); // (rooftop scale x, rooftop scale y, unused)
positions->push_back(building.position); positions->push_back(building.position);
@@ -379,7 +380,7 @@ struct AddBuildingLeafObject
scale->push_back(osg::Vec3f(building.depth, building.width, building.height)); scale->push_back(osg::Vec3f(building.depth, building.width, building.height));
rot->push_back(osg::Vec3f(building.rotation, building.pitch_height, building.walltex0.x())); rot->push_back(osg::Vec3f(building.rotation, building.pitch_height, building.walltex0.x()));
tex->push_back(osg::Vec3f(building.walltex0.y(), building.tex1.x(), building.tex1.y())); tex->push_back(osg::Vec3f(building.walltex0.y(), building.tex1.x(), building.tex1.y()));
rtex->push_back(osg::Vec3f(building.rooftex0.x(), building.rooftex0.y(), 0.0f)); rtex->push_back(osg::Vec3f(building.rooftex0.x(), building.rooftex0.y(), building.tex1.z()));
rooftops->push_back(osg::Vec3f(building.rooftop_scale.x(), building.rooftop_scale.y(), 0.0f)); rooftops->push_back(osg::Vec3f(building.rooftop_scale.x(), building.rooftop_scale.y(), 0.0f));
DrawArrays* primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0)); DrawArrays* primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
@@ -439,7 +440,7 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
// H is the building height in meters, excluding any pitched roof // H is the building height in meters, excluding any pitched roof
// P is the pitch height in meters. 0 for a flat roof // P is the pitch height in meters. 0 for a flat roof
// S is the roof shape (Currently the following values are valid: 0, 2, 4, 5) : // S is the roof shape (Currently the following values are valid: 0, 2, 4, 5) :
// 0=flat 1=skillion 2=gabled 3=half-hipped 4=hipped 5=pyramidal 6=gambled // 0=flat 1=skillion 2=gabled 3=half-hipped 4=hipped 5=pyramidal 6=gambrel
// 7=mansard 8=dome 9=onion 10=round 11=saltbox // 7=mansard 8=dome 9=onion 10=round 11=saltbox
// O is the roof ridge orientation : // O is the roof ridge orientation :
// 0 = parallel to the front face of the building // 0 = parallel to the front face of the building
@@ -497,7 +498,8 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
// 32 for the roof. // 32 for the roof.
const float BUILDING_TEXTURE_BLOCK_HEIGHT = 32.0f / 2048.0f; // The height of a single block within the random building texture const float BUILDING_TEXTURE_BLOCK_HEIGHT = 32.0f / 2048.0f; // The height of a single block within the random building texture
const float BUILDING_TEXTURE_BLOCK_WIDTH = 64.0f / 2048.0f; // The width of a single block within the random building texture const float BUILDING_TEXTURE_BLOCK_WIDTH = 64.0f / 2048.0f; // The width of a single block within the random building texture
Vec2f wall_tex0, roof_tex0, tex1; Vec2f wall_tex0, roof_tex0;
Vec3f tex1;
if (buildingtype == SGBuildingBin::SMALL) { if (buildingtype == SGBuildingBin::SMALL) {
// SMALL BUILDINGS // SMALL BUILDINGS
@@ -506,23 +508,24 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
// Each block is 5m wide and 3m high. // Each block is 5m wide and 3m high.
int wall_row = wall_tex_index % 6; int wall_row = wall_tex_index % 6;
int roof_row = roof_tex_index % 6; int roof_row = roof_tex_index % 6;
float wall_offset_x = 0.0f; float wall_x0 = 0.0f;
float wall_offset_y = (float) wall_row * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT; float wall_y0 = (float) wall_row * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT;
float roof_offset_x = 0.0f; float roof_x0 = 0.0f;
float roof_offset_y = (float) roof_row * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT; float roof_y0 = (float) roof_row * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT;
float gain_x = min(0.5f, std::round(width / 5.0f) * BUILDING_TEXTURE_BLOCK_WIDTH); float wall_roof_x1 = min(0.5f, std::round(width / 5.0f) * BUILDING_TEXTURE_BLOCK_WIDTH);
float gain_y = (float) (min(3, floors)) * BUILDING_TEXTURE_BLOCK_HEIGHT; float side_x1 = min(0.5f, std::round(depth / 5.0f) * BUILDING_TEXTURE_BLOCK_WIDTH);
float y1 = (float) (min(3, floors)) * BUILDING_TEXTURE_BLOCK_HEIGHT;
// Checks // Checks
if ((wall_offset_x + gain_x > 0.5f) || if ((wall_x0 + wall_roof_x1 > 0.5f) ||
(wall_offset_y + gain_y > (6.0f * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT))) { (wall_y0 + y1 > (6.0f * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT))) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Small building texture coordinates out of bounds offset (" << wall_offset_x << ", " << wall_offset_y << ") gain (" << gain_x << ", " << gain_y << ")"); SG_LOG(SG_TERRAIN, SG_ALERT, "Small building texture coordinates out of bounds offset (" << wall_x0 << ", " << wall_y0 << ") gain (" << wall_roof_x1 << ", " << y1 << ")");
} }
wall_tex0 = Vec2f(wall_offset_x, wall_offset_y); wall_tex0 = Vec2f(wall_x0, wall_y0);
roof_tex0 = Vec2f(roof_offset_x, roof_offset_y); roof_tex0 = Vec2f(roof_x0, roof_y0);
tex1 = Vec2f(gain_x, gain_y); tex1 = Vec3f(wall_roof_x1, y1, side_x1);
} else if (buildingtype == SGBuildingBin::MEDIUM) { } else if (buildingtype == SGBuildingBin::MEDIUM) {
// MEDIUM BUILDING // MEDIUM BUILDING
// Maximum texture height is 8 stories. // Maximum texture height is 8 stories.
@@ -533,27 +536,28 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
int roof_column = roof_tex_index % 2; int roof_column = roof_tex_index % 2;
int roof_row = roof_tex_index % 3; int roof_row = roof_tex_index % 3;
float wall_offset_x = wall_column * 0.25f; float wall_x0 = wall_column * 0.25f;
// Counting from the bottom, we have 6 rows of small buildings, each 3 blocks high // Counting from the bottom, we have 6 rows of small buildings, each 3 blocks high
float wall_offset_y = (6.0f * 3.0f + wall_row * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT; float wall_y0 = (6.0f * 3.0f + wall_row * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT;
float roof_offset_x = roof_column * 0.25f; float roof_x0 = roof_column * 0.25f;
// Counting from the bottom, we have 6 rows of small buildings, each 3 blocks high // Counting from the bottom, we have 6 rows of small buildings, each 3 blocks high
float roof_offset_y = (6.0f * 3.0f + roof_row * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT; float roof_y0 = (6.0f * 3.0f + roof_row * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT;
float gain_x = min(0.25f, std::ceil(width / 10.0f) * BUILDING_TEXTURE_BLOCK_WIDTH); float wall_roof_x1 = min(0.25f, std::ceil(width / 10.0f) * BUILDING_TEXTURE_BLOCK_WIDTH);
float gain_y = (float) (min(8, floors)) * BUILDING_TEXTURE_BLOCK_HEIGHT; float side_x1 = min(0.5f, std::round(depth / 10.0f) * BUILDING_TEXTURE_BLOCK_WIDTH);
float y1 = (float) (min(8, floors)) * BUILDING_TEXTURE_BLOCK_HEIGHT;
if ((wall_offset_x + gain_x > 0.5f) || if ((wall_x0 + wall_roof_x1 > 0.5f) ||
(wall_offset_y + gain_y < (6.0f * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT)) || (wall_y0 + y1 < (6.0f * 3.0f * BUILDING_TEXTURE_BLOCK_HEIGHT)) ||
(wall_offset_y + gain_y > ((6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT))) { (wall_y0 + y1 > ((6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT))) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Medium building texture coordinates out of bounds offset (" << wall_offset_x << ", " << wall_offset_y << ") gain (" << gain_x << ", " << gain_y << ")"); SG_LOG(SG_TERRAIN, SG_ALERT, "Medium building texture coordinates out of bounds offset (" << wall_x0 << ", " << wall_y0 << ") gain (" << wall_roof_x1 << ", " << y1 << ")");
} }
wall_tex0 = Vec2f(wall_offset_x, wall_offset_y); wall_tex0 = Vec2f(wall_x0, wall_y0);
roof_tex0 = Vec2f(roof_offset_x, roof_offset_y); roof_tex0 = Vec2f(roof_x0, roof_y0);
tex1 = Vec2f(gain_x, gain_y); tex1 = Vec3f(wall_roof_x1, y1, side_x1);
} else { } else {
// LARGE BUILDING // LARGE BUILDING
// Maximum texture height is 22 stories. // Maximum texture height is 22 stories.
@@ -563,22 +567,23 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
int roof_column = roof_tex_index % 4; int roof_column = roof_tex_index % 4;
// Counting from the bottom we have 6 rows of small buildings (3 blocks high), // Counting from the bottom we have 6 rows of small buildings (3 blocks high),
// then 3 rows of medium buildings (8 blocks high). Then the large building texture // then 3 rows of medium buildings (8 blocks high). Then the large building texture
float wall_offset_x = wall_column * 0.125f; float wall_x0 = wall_column * 0.125f;
float wall_offset_y = (6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT; float wall_y0 = (6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT;
float roof_offset_x = roof_column * 0.125f; float roof_x0 = roof_column * 0.125f;
float roof_offset_y = (6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT; float roof_y0 = (6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT;
float gain_x = min(0.125f, std::ceil(width / 20.0f) * BUILDING_TEXTURE_BLOCK_WIDTH); float wall_roof_x1 = min(0.125f, std::ceil(width / 20.0f) * BUILDING_TEXTURE_BLOCK_WIDTH);
float gain_y = (float) min(22, floors) * BUILDING_TEXTURE_BLOCK_HEIGHT; float side_x1 = min(0.5f, std::round(depth / 20.0f) * BUILDING_TEXTURE_BLOCK_WIDTH);
float y1 = (float) min(22, floors) * BUILDING_TEXTURE_BLOCK_HEIGHT;
if ((wall_offset_x + gain_x > 0.5f) || if ((wall_x0 + wall_roof_x1 > 0.5f) ||
(wall_offset_y + gain_y < ((6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT)) || (wall_y0 + y1 < ((6.0f * 3.0f + 3.0f * 8.0f) * BUILDING_TEXTURE_BLOCK_HEIGHT)) ||
(wall_offset_y + gain_y > 1.0) ) { (wall_y0 + y1 > 1.0) ) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Large building texture coordinates out of bounds offset (" << wall_offset_x << ", " << wall_offset_y << ") gain (" << gain_x << ", " << gain_y << ")"); SG_LOG(SG_TERRAIN, SG_ALERT, "Large building texture coordinates out of bounds offset (" << wall_x0 << ", " << wall_y0 << ") gain (" << wall_roof_x1 << ", " << y1 << ")");
} }
wall_tex0 = Vec2f(wall_offset_x, wall_offset_y); wall_tex0 = Vec2f(wall_x0, wall_y0);
roof_tex0 = Vec2f(roof_offset_x, roof_offset_y); roof_tex0 = Vec2f(roof_x0, roof_y0);
tex1 = Vec2f(gain_x, gain_y); tex1 = Vec3f(wall_roof_x1, y1, side_x1);
} }
// Build a scaling factor in the x,y axes for the top of the roof. This allows us to create gabled, hipped, pyramidal roofs. // Build a scaling factor in the x,y axes for the top of the roof. This allows us to create gabled, hipped, pyramidal roofs.
+2 -2
View File
@@ -92,7 +92,7 @@ public:
LARGE }; LARGE };
struct BuildingInstance { struct BuildingInstance {
BuildingInstance(Vec3f p, float w, float d, float h, float ph, float r, Vec2f wt0, Vec2f rt0, Vec2f t1, Vec2f rs) : BuildingInstance(Vec3f p, float w, float d, float h, float ph, float r, Vec2f wt0, Vec2f rt0, Vec3f t1, Vec2f rs) :
position(p), position(p),
width(w), width(w),
depth(d), depth(d),
@@ -128,7 +128,7 @@ public:
Vec2f walltex0; Vec2f walltex0;
Vec2f rooftex0; Vec2f rooftex0;
Vec2f tex1; Vec3f tex1; // Texture gains for the front, roof and sides
Vec2f rooftop_scale; Vec2f rooftop_scale;