mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-08 18:13:52 +00:00
feat(editor): add --gen-mesh-pyramid N-sided polygonal pyramid
N-sided polygonal pyramid with apex at +Y. 3 sides → tetrahedron- like shape; 4 → classic square pyramid; 8+ → faceted approximation of a cone. Different from --gen-mesh cone: cone has smooth curved sides with per-vertex radial-ish normals; pyramid has flat per-face normals on each triangular side, giving a clearly faceted look. Args: <wom-base> [sides] [baseRadius] [height] Defaults: 4 / 1.0 / 1.0. Sides hard-capped at 256. Useful for monuments, witch hats, gem props, treasure piles, dunce caps. Brings the procedural primitive set to 13. Verified: 4-sided pyramid → 17 verts / 8 tris (4 side + 4 base); 3-sided → 13 verts / 6 tris.
This commit is contained in:
parent
7a43e4eb3b
commit
525b48ade7
1 changed files with 113 additions and 0 deletions
|
|
@ -559,6 +559,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Capsule along Y axis: cylinder body with hemispherical caps (default 0.5/1.0/16/8)\n");
|
||||
std::printf(" --gen-mesh-arch <wom-base> [openingWidth] [openingHeight] [thickness] [depth] [segments]\n");
|
||||
std::printf(" Doorway arch: two columns + semicircular top (default 1.0/1.5/0.2/0.3, 12 segs)\n");
|
||||
std::printf(" --gen-mesh-pyramid <wom-base> [sides] [baseRadius] [height]\n");
|
||||
std::printf(" N-sided polygonal pyramid with apex at +Y (default 4 sides, 1.0/1.0)\n");
|
||||
std::printf(" --displace-mesh <wom-base> <heightmap.png> [scale]\n");
|
||||
std::printf(" Offset each vertex along its normal by heightmap brightness × scale (default 1.0)\n");
|
||||
std::printf(" --gen-mesh-from-heightmap <wom-base> <heightmap.png> [scaleXZ] [scaleY]\n");
|
||||
|
|
@ -1043,6 +1045,7 @@ int main(int argc, char* argv[]) {
|
|||
"--add-texture-to-mesh", "--add-texture-to-zone",
|
||||
"--gen-mesh-stairs", "--gen-mesh-grid", "--gen-mesh-disc",
|
||||
"--gen-mesh-tube", "--gen-mesh-capsule", "--gen-mesh-arch",
|
||||
"--gen-mesh-pyramid",
|
||||
"--gen-texture-gradient",
|
||||
"--gen-mesh-from-heightmap", "--export-mesh-heightmap",
|
||||
"--displace-mesh",
|
||||
|
|
@ -19152,6 +19155,116 @@ int main(int argc, char* argv[]) {
|
|||
wom.boundMin.x, wom.boundMin.y, wom.boundMin.z,
|
||||
wom.boundMax.x, wom.boundMax.y, wom.boundMax.z);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--gen-mesh-pyramid") == 0 && i + 1 < argc) {
|
||||
// N-sided polygonal pyramid with apex at +Y. 4 sides
|
||||
// gives a square pyramid; 3 gives a tetrahedron-like
|
||||
// shape; 8+ approaches a cone.
|
||||
//
|
||||
// Different from --gen-mesh cone: cone has smooth
|
||||
// round sides with per-vertex radial-ish normals;
|
||||
// pyramid has flat per-face normals on N triangular
|
||||
// sides + a flat polygonal base.
|
||||
std::string womBase = argv[++i];
|
||||
int sides = 4;
|
||||
float baseR = 1.0f;
|
||||
float height = 1.0f;
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { sides = std::stoi(argv[++i]); } catch (...) {}
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { baseR = std::stof(argv[++i]); } catch (...) {}
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { height = std::stof(argv[++i]); } catch (...) {}
|
||||
}
|
||||
if (sides < 3 || sides > 256 || baseR <= 0 || height <= 0) {
|
||||
std::fprintf(stderr,
|
||||
"gen-mesh-pyramid: sides 3..256, baseR > 0, height > 0\n");
|
||||
return 1;
|
||||
}
|
||||
if (womBase.size() >= 4 &&
|
||||
womBase.substr(womBase.size() - 4) == ".wom") {
|
||||
womBase = womBase.substr(0, womBase.size() - 4);
|
||||
}
|
||||
wowee::pipeline::WoweeModel wom;
|
||||
wom.name = std::filesystem::path(womBase).stem().string();
|
||||
wom.version = 3;
|
||||
const float pi = 3.14159265358979f;
|
||||
auto addV = [&](glm::vec3 p, glm::vec3 n, glm::vec2 uv) -> uint32_t {
|
||||
wowee::pipeline::WoweeModel::Vertex vtx;
|
||||
vtx.position = p;
|
||||
vtx.normal = n;
|
||||
vtx.texCoord = uv;
|
||||
wom.vertices.push_back(vtx);
|
||||
return static_cast<uint32_t>(wom.vertices.size() - 1);
|
||||
};
|
||||
// Build base ring vertices (one per side).
|
||||
std::vector<glm::vec3> basePts;
|
||||
for (int k = 0; k < sides; ++k) {
|
||||
float a = static_cast<float>(k) / sides * 2.0f * pi;
|
||||
basePts.push_back(glm::vec3(baseR * std::cos(a), 0,
|
||||
baseR * std::sin(a)));
|
||||
}
|
||||
glm::vec3 apex(0, height, 0);
|
||||
// Side faces: per-face flat normals (cross of two edges).
|
||||
for (int k = 0; k < sides; ++k) {
|
||||
glm::vec3 a = basePts[k];
|
||||
glm::vec3 b = basePts[(k + 1) % sides];
|
||||
glm::vec3 e1 = b - a;
|
||||
glm::vec3 e2 = apex - a;
|
||||
glm::vec3 n = glm::normalize(glm::cross(e1, e2));
|
||||
float u0 = static_cast<float>(k) / sides;
|
||||
float u1 = static_cast<float>(k + 1) / sides;
|
||||
uint32_t i0 = addV(a, n, glm::vec2(u0, 1));
|
||||
uint32_t i1 = addV(b, n, glm::vec2(u1, 1));
|
||||
uint32_t i2 = addV(apex, n, glm::vec2(0.5f * (u0 + u1), 0));
|
||||
wom.indices.push_back(i0);
|
||||
wom.indices.push_back(i1);
|
||||
wom.indices.push_back(i2);
|
||||
}
|
||||
// Base: fan from a center vertex (normal -Y).
|
||||
uint32_t baseCenter = addV(glm::vec3(0, 0, 0),
|
||||
glm::vec3(0, -1, 0),
|
||||
glm::vec2(0.5f, 0.5f));
|
||||
uint32_t baseRingStart = static_cast<uint32_t>(wom.vertices.size());
|
||||
for (int k = 0; k < sides; ++k) {
|
||||
float a = static_cast<float>(k) / sides * 2.0f * pi;
|
||||
addV(basePts[k], glm::vec3(0, -1, 0),
|
||||
glm::vec2(0.5f + 0.5f * std::cos(a),
|
||||
0.5f - 0.5f * std::sin(a)));
|
||||
}
|
||||
for (int k = 0; k < sides; ++k) {
|
||||
wom.indices.push_back(baseCenter);
|
||||
wom.indices.push_back(baseRingStart + (k + 1) % sides);
|
||||
wom.indices.push_back(baseRingStart + k);
|
||||
}
|
||||
wom.boundMin = glm::vec3(-baseR, 0, -baseR);
|
||||
wom.boundMax = glm::vec3( baseR, height, baseR);
|
||||
wom.boundRadius = glm::length(wom.boundMax - wom.boundMin) * 0.5f;
|
||||
wowee::pipeline::WoweeModel::Batch b;
|
||||
b.indexStart = 0;
|
||||
b.indexCount = static_cast<uint32_t>(wom.indices.size());
|
||||
b.textureIndex = 0;
|
||||
b.blendMode = 0;
|
||||
b.flags = 0;
|
||||
wom.batches.push_back(b);
|
||||
wom.texturePaths.push_back("");
|
||||
std::filesystem::path womPath(womBase);
|
||||
std::filesystem::create_directories(womPath.parent_path());
|
||||
if (!wowee::pipeline::WoweeModelLoader::save(wom, womBase)) {
|
||||
std::fprintf(stderr,
|
||||
"gen-mesh-pyramid: failed to save %s.wom\n", womBase.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Wrote %s.wom\n", womBase.c_str());
|
||||
std::printf(" sides : %d\n", sides);
|
||||
std::printf(" base R : %.3f\n", baseR);
|
||||
std::printf(" height : %.3f\n", height);
|
||||
std::printf(" vertices : %zu (%d side tris × 3 + 1 base center + %d base ring)\n",
|
||||
wom.vertices.size(), sides, sides);
|
||||
std::printf(" triangles : %zu (%d sides + %d base)\n",
|
||||
wom.indices.size() / 3, sides, sides);
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--displace-mesh") == 0 && i + 2 < argc) {
|
||||
// Displaces each vertex along its current normal by the
|
||||
// heightmap brightness × scale. UVs determine where each
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue