You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
11 KiB
394 lines
11 KiB
2 years ago
|
/*
|
||
|
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <array>
|
||
|
|
||
|
#define _USE_MATH_DEFINES
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "primitives.hpp"
|
||
|
|
||
|
|
||
|
namespace nvh {
|
||
|
static uint32_t addPos(PrimitiveMesh& mesh, nvmath::vec3f p)
|
||
|
{
|
||
|
PrimitiveVertex v{};
|
||
|
v.p = p;
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
return static_cast<uint32_t>(mesh.vertices.size()) - 1;
|
||
|
}
|
||
|
|
||
|
static void addTriangle(PrimitiveMesh& mesh, uint32_t a, uint32_t b, uint32_t c)
|
||
|
{
|
||
|
mesh.indices.push_back(a);
|
||
|
mesh.indices.push_back(b);
|
||
|
mesh.indices.push_back(c);
|
||
|
}
|
||
|
|
||
|
static void addTriangle(PrimitiveMesh& mesh, nvmath::vec3f a, nvmath::vec3f b, nvmath::vec3f c)
|
||
|
{
|
||
|
mesh.indices.push_back(addPos(mesh, a));
|
||
|
mesh.indices.push_back(addPos(mesh, b));
|
||
|
mesh.indices.push_back(addPos(mesh, c));
|
||
|
}
|
||
|
|
||
|
static void faceted(PrimitiveMesh& mesh)
|
||
|
{
|
||
|
auto num_indices = static_cast<uint32_t>(mesh.indices.size());
|
||
|
for(uint32_t i = 0; i < num_indices; i += 3)
|
||
|
{
|
||
|
auto& v0 = mesh.vertices[mesh.indices[i + 0]];
|
||
|
auto& v1 = mesh.vertices[mesh.indices[i + 1]];
|
||
|
auto& v2 = mesh.vertices[mesh.indices[i + 2]];
|
||
|
|
||
|
auto n = nvmath::cross(nvmath::normalize(v1.p - v0.p), nvmath::normalize(v2.p - v0.p));
|
||
|
|
||
|
v0.n = n;
|
||
|
v1.n = n;
|
||
|
v2.n = n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PrimitiveMesh tetrahedron()
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
// choose coordinates on the unit sphere
|
||
|
float a = 1.0F / 3.0F;
|
||
|
float b = sqrt(8.0F / 9.0F);
|
||
|
float c = sqrt(2.0F / 9.0F);
|
||
|
float d = sqrt(2.0F / 3.0F);
|
||
|
|
||
|
// 4 vertices
|
||
|
nvmath::vec3f v0 = nvmath::vec3f{0.0F, 1.0F, 0.0F} * 0.5F;
|
||
|
nvmath::vec3f v1 = nvmath::vec3f{-c, -a, d} * 0.5F;
|
||
|
nvmath::vec3f v2 = nvmath::vec3f{-c, -a, -d} * 0.5F;
|
||
|
nvmath::vec3f v3 = nvmath::vec3f{b, -a, 0.0F} * 0.5F;
|
||
|
|
||
|
// 4 triangles
|
||
|
addTriangle(mesh, v0, v2, v1);
|
||
|
addTriangle(mesh, v0, v3, v2);
|
||
|
addTriangle(mesh, v0, v1, v3);
|
||
|
addTriangle(mesh, v3, v1, v2);
|
||
|
|
||
|
faceted(mesh);
|
||
|
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
|
||
|
PrimitiveMesh icosahedron()
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
float sq5 = sqrt(5.0F);
|
||
|
float a = 2.0F / (1.0F + sq5);
|
||
|
float b = sqrt((3.0F + sq5) / (1.0F + sq5));
|
||
|
a /= b;
|
||
|
float r = 0.5F;
|
||
|
|
||
|
std::vector<nvmath::vec3f> v;
|
||
|
v.emplace_back(0.0F, r * a, r / b);
|
||
|
v.emplace_back(0.0F, r * a, -r / b);
|
||
|
v.emplace_back(0.0F, -r * a, r / b);
|
||
|
v.emplace_back(0.0F, -r * a, -r / b);
|
||
|
v.emplace_back(r * a, r / b, 0.0F);
|
||
|
v.emplace_back(r * a, -r / b, 0.0F);
|
||
|
v.emplace_back(-r * a, r / b, 0.0F);
|
||
|
v.emplace_back(-r * a, -r / b, 0.0F);
|
||
|
v.emplace_back(r / b, 0.0F, r * a);
|
||
|
v.emplace_back(r / b, 0.0F, -r * a);
|
||
|
v.emplace_back(-r / b, 0.0F, r * a);
|
||
|
v.emplace_back(-r / b, 0.0F, -r * a);
|
||
|
|
||
|
addTriangle(mesh, v[1], v[6], v[4]);
|
||
|
addTriangle(mesh, v[0], v[4], v[6]);
|
||
|
addTriangle(mesh, v[0], v[10], v[2]);
|
||
|
addTriangle(mesh, v[0], v[2], v[8]);
|
||
|
addTriangle(mesh, v[1], v[9], v[3]);
|
||
|
addTriangle(mesh, v[1], v[3], v[11]);
|
||
|
addTriangle(mesh, v[2], v[7], v[5]);
|
||
|
addTriangle(mesh, v[3], v[5], v[7]);
|
||
|
addTriangle(mesh, v[6], v[11], v[10]);
|
||
|
addTriangle(mesh, v[7], v[10], v[11]);
|
||
|
addTriangle(mesh, v[4], v[8], v[9]);
|
||
|
addTriangle(mesh, v[5], v[9], v[8]);
|
||
|
addTriangle(mesh, v[0], v[6], v[10]);
|
||
|
addTriangle(mesh, v[0], v[8], v[4]);
|
||
|
addTriangle(mesh, v[1], v[11], v[6]);
|
||
|
addTriangle(mesh, v[1], v[4], v[9]);
|
||
|
addTriangle(mesh, v[3], v[7], v[11]);
|
||
|
addTriangle(mesh, v[3], v[9], v[5]);
|
||
|
addTriangle(mesh, v[2], v[10], v[7]);
|
||
|
addTriangle(mesh, v[2], v[5], v[8]);
|
||
|
|
||
|
faceted(mesh);
|
||
|
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
PrimitiveMesh octahedron()
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
std::vector<nvmath::vec3f> v;
|
||
|
v.emplace_back(0.5F, 0.0F, 0.0F);
|
||
|
v.emplace_back(-0.5F, 0.0F, 0.0F);
|
||
|
v.emplace_back(0.0F, 0.5F, 0.0F);
|
||
|
v.emplace_back(0.0F, -0.5F, 0.0F);
|
||
|
v.emplace_back(0.0F, 0.0F, 0.5F);
|
||
|
v.emplace_back(0.0F, 0.0F, -0.5F);
|
||
|
|
||
|
addTriangle(mesh, v[0], v[2], v[4]);
|
||
|
addTriangle(mesh, v[0], v[4], v[3]);
|
||
|
addTriangle(mesh, v[0], v[5], v[2]);
|
||
|
addTriangle(mesh, v[0], v[3], v[5]);
|
||
|
addTriangle(mesh, v[1], v[4], v[2]);
|
||
|
addTriangle(mesh, v[1], v[3], v[4]);
|
||
|
addTriangle(mesh, v[1], v[5], v[3]);
|
||
|
addTriangle(mesh, v[2], v[5], v[1]);
|
||
|
|
||
|
faceted(mesh);
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
PrimitiveMesh plane(uint32_t steps, float width, float depth)
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
float increment = 1.0F / static_cast<float>(steps);
|
||
|
for(uint32_t sz = 0; sz <= steps; sz++)
|
||
|
{
|
||
|
for(uint32_t sx = 0; sx <= steps; sx++)
|
||
|
{
|
||
|
PrimitiveVertex v{};
|
||
|
|
||
|
v.p = nvmath::vec3f(-0.5F + (static_cast<float>(sx) * increment), 0.0F, -0.5F + (static_cast<float>(sz) * increment));
|
||
|
v.p *= nvmath::vec3f(width, 1.0F, depth);
|
||
|
v.n = nvmath::vec3f(0.0F, 1.0F, 0.0F);
|
||
|
v.t = nvmath::vec2f(static_cast<float>(sx) / static_cast<float>(steps),
|
||
|
static_cast<float>(steps - sz) / static_cast<float>(steps));
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for(uint32_t sz = 0; sz < steps; sz++)
|
||
|
{
|
||
|
for(uint32_t sx = 0; sx < steps; sx++)
|
||
|
{
|
||
|
addTriangle(mesh, sx + sz * (steps + 1), sx + 1 + (sz + 1) * (steps + 1), sx + 1 + sz * (steps + 1));
|
||
|
addTriangle(mesh, sx + sz * (steps + 1), sx + (sz + 1) * (steps + 1), sx + 1 + (sz + 1) * (steps + 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
PrimitiveMesh cube(float width /*= 1*/, float height /*= 1*/, float depth /*= 1*/)
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
nvmath::vec3f s = nvmath::vec3f(width, height, depth) * 0.5F;
|
||
|
std::vector<nvmath::vec3f> pnt = {{-s.x, -s.y, -s.z}, {-s.x, -s.y, s.z}, {-s.x, s.y, -s.z}, {-s.x, s.y, s.z},
|
||
|
{s.x, -s.y, -s.z}, {s.x, -s.y, s.z}, {s.x, s.y, -s.z}, {s.x, s.y, s.z}};
|
||
|
std::vector<nvmath::vec3f> nrm = {{-1.0F, 0.0F, 0.0F}, {0.0F, 0.0F, 1.0F}, {1.0F, 0.0F, 0.0F},
|
||
|
{0.0F, 0.0F, -1.0F}, {0.0F, -1.0F, 0.0F}, {0.0F, 1.0F, 0.0F}};
|
||
|
std::vector<nvmath::vec2f> uv = {{0.0F, 0.0F}, {0.0F, 1.0F}, {1.0F, 1.0F}, {1.0F, 0.0F}};
|
||
|
|
||
|
// cube topology
|
||
|
std::vector<std::vector<int>> cube_polygons = {{0, 1, 3, 2}, {1, 5, 7, 3}, {5, 4, 6, 7},
|
||
|
{4, 0, 2, 6}, {4, 5, 1, 0}, {2, 3, 7, 6}};
|
||
|
|
||
|
for(int i = 0; i < 6; ++i)
|
||
|
{
|
||
|
auto index = static_cast<int32_t>(mesh.vertices.size());
|
||
|
for(int j = 0; j < 4; ++j)
|
||
|
mesh.vertices.push_back({pnt[cube_polygons[i][j]], nrm[i], uv[j]});
|
||
|
addTriangle(mesh, index, index + 1, index + 2);
|
||
|
addTriangle(mesh, index, index + 2, index + 3);
|
||
|
}
|
||
|
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
|
||
|
PrimitiveMesh sphere(float radius, int sectors, int stacks)
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
float omega{0.0F}; // rotation around the X axis
|
||
|
float phi{0.0F}; // rotation around the Y axis
|
||
|
float length_inv = 1.0F / radius; // vertex normal
|
||
|
|
||
|
const float math_pi = static_cast<float>(M_PI);
|
||
|
float sector_step = 2.0F * math_pi / static_cast<float>(sectors);
|
||
|
float stack_step = math_pi / static_cast<float>(stacks);
|
||
|
float sector_angle{0.0F};
|
||
|
float stack_angle{0.0F};
|
||
|
|
||
|
for(int i = 0; i <= stacks; ++i)
|
||
|
{
|
||
|
stack_angle = math_pi / 2.0F - static_cast<float>(i) * stack_step; // starting from pi/2 to -pi/2
|
||
|
phi = radius * cosf(stack_angle); // r * cos(u)
|
||
|
omega = radius * sinf(stack_angle); // r * sin(u)
|
||
|
|
||
|
// add (sectorCount+1) vertices per stack
|
||
|
// the first and last vertices have same position and normal, but different tex coords
|
||
|
for(int j = 0; j <= sectors; ++j)
|
||
|
{
|
||
|
PrimitiveVertex v{};
|
||
|
|
||
|
sector_angle = static_cast<float>(j) * sector_step; // starting from 0 to 2pi
|
||
|
|
||
|
// vertex position (x, y, z)
|
||
|
v.p.x = phi * cosf(sector_angle); // r * cos(u) * cos(v)
|
||
|
v.p.z = phi * sinf(sector_angle); // r * cos(u) * sin(v)
|
||
|
v.p.y = omega;
|
||
|
|
||
|
// normalized vertex normal
|
||
|
v.n = v.p * length_inv;
|
||
|
|
||
|
// vertex tex coord (s, t) range between [0, 1]
|
||
|
v.t.x = 1.0F - static_cast<float>(j) / static_cast<float>(sectors);
|
||
|
v.t.y = static_cast<float>(i) / static_cast<float>(stacks);
|
||
|
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// indices
|
||
|
// k2---k2+1
|
||
|
// | \ |
|
||
|
// | \ |
|
||
|
// k1---k1+1
|
||
|
uint32_t k1{0};
|
||
|
uint32_t k2{0};
|
||
|
for(int i = 0; i < stacks; ++i)
|
||
|
{
|
||
|
k1 = i * (sectors + 1); // beginning of current stack
|
||
|
k2 = k1 + sectors + 1; // beginning of next stack
|
||
|
|
||
|
for(int j = 0; j < sectors; ++j, ++k1, ++k2)
|
||
|
{
|
||
|
// 2 triangles per sector excluding 1st and last stacks
|
||
|
if(i != 0)
|
||
|
{
|
||
|
addTriangle(mesh, k1, k1 + 1, k2); // k1---k2---k1+1
|
||
|
}
|
||
|
|
||
|
if(i != (stacks - 1))
|
||
|
{
|
||
|
addTriangle(mesh, k1 + 1, k2 + 1, k2); // k1+1---k2---k2+1
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
PrimitiveMesh cone(float radius, int sectors)
|
||
|
{
|
||
|
PrimitiveMesh mesh;
|
||
|
|
||
|
const float math_pi = static_cast<float>(M_PI);
|
||
|
float sector_step = 2.0F * math_pi / static_cast<float>(sectors);
|
||
|
float sector_angle{0.0F};
|
||
|
|
||
|
// length of the flank of the cone
|
||
|
float flank_len = sqrtf(radius * radius + 1.0F);
|
||
|
// unit vector along the flank of the cone
|
||
|
float cone_x = radius / flank_len;
|
||
|
float cone_y = -1.0F / flank_len;
|
||
|
|
||
|
nvmath::vec3f tip = {0.0F, 0.5F, 0.0F};
|
||
|
|
||
|
// Sides
|
||
|
for(int i = 0; i <= sectors; ++i)
|
||
|
{
|
||
|
PrimitiveVertex v{};
|
||
|
sector_angle = static_cast<float>(i) * sector_step;
|
||
|
|
||
|
// Position
|
||
|
v.p.x = radius * cosf(sector_angle); // r * cos(u) * cos(v)
|
||
|
v.p.z = radius * sinf(sector_angle); // r * cos(u) * sin(v)
|
||
|
v.p.y = -0.5F;
|
||
|
// Normal
|
||
|
v.n.x = -cone_y * cosf(sector_angle);
|
||
|
v.n.y = cone_x;
|
||
|
v.n.z = -cone_y * sinf(sector_angle);
|
||
|
// TexCoord
|
||
|
v.t.x = static_cast<float>(i) / static_cast<float>(sectors);
|
||
|
v.t.y = 0.0F;
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
|
||
|
// Tip point
|
||
|
v.p = tip;
|
||
|
// Normal
|
||
|
sector_angle += 0.5F * sector_step; // Half way to next triangle
|
||
|
v.n.x = -cone_y * cosf(sector_angle);
|
||
|
v.n.y = cone_x;
|
||
|
v.n.z = -cone_y * sinf(sector_angle);
|
||
|
// TexCoord
|
||
|
v.t.x += 0.5F / static_cast<float>(sectors);
|
||
|
v.t.y = 1.0F;
|
||
|
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
}
|
||
|
|
||
|
for(int j = 0; j < sectors; ++j)
|
||
|
{
|
||
|
uint32_t k1 = j * 2;
|
||
|
addTriangle(mesh, k1, k1 + 1, k1 + 2);
|
||
|
}
|
||
|
|
||
|
// Bottom plate (normal are different)
|
||
|
for(int i = 0; i <= sectors; ++i)
|
||
|
{
|
||
|
PrimitiveVertex v{};
|
||
|
sector_angle = static_cast<float>(i) * sector_step; // starting from 0 to 2pi
|
||
|
|
||
|
v.p.x = radius * cosf(sector_angle); // r * cos(u) * cos(v)
|
||
|
v.p.z = radius * sinf(sector_angle); // r * cos(u) * sin(v)
|
||
|
v.p.y = -0.5F;
|
||
|
//
|
||
|
v.n = {0.0F, -1.0F, 0.0F};
|
||
|
//
|
||
|
v.t.x = static_cast<float>(i) / static_cast<float>(sectors);
|
||
|
v.t.y = 0.0F;
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
|
||
|
v.p = -tip;
|
||
|
v.t.x += 0.5F / static_cast<float>(sectors);
|
||
|
v.t.y = 1.0F;
|
||
|
mesh.vertices.emplace_back(v);
|
||
|
}
|
||
|
|
||
|
for(int j = 0; j < sectors; ++j)
|
||
|
{
|
||
|
uint32_t k1 = (j + sectors + 1) * 2;
|
||
|
addTriangle(mesh, k1, k1 + 2, k1 + 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
return mesh;
|
||
|
}
|
||
|
|
||
|
} // namespace nvh
|