Example #1
0
void copy_face_attributes(Mesh::Ptr mesh,
        std::unique_ptr<draco::Mesh>& draco_mesh) {
    const auto num_faces = mesh->get_num_faces();
    const auto& attribute_names = mesh->get_attribute_names();
    for (const auto& name : attribute_names) {
        const auto& values = mesh->get_attribute(name);
        if (values.size() % num_faces != 0) continue;
        const auto num_rows = num_faces;
        const auto num_cols = values.size() / num_faces;
        draco::GeometryAttribute attr;
        if (name == "face_normal") {
            attr.Init(draco::GeometryAttribute::NORMAL, nullptr,
                    num_cols, draco::DT_FLOAT64, false,
                    sizeof(Float) * num_cols, 0);
        } else if (name.substr(0, 4) == "face"){
            attr.Init(draco::GeometryAttribute::GENERIC, nullptr,
                    num_cols, draco::DT_FLOAT64, false,
                    sizeof(Float) * num_cols, 0);
        } else {
            // Not a face attribute.
            continue;
        }
        const auto id = draco_mesh->AddAttribute(attr, true, num_rows);
        draco_mesh->SetAttributeElementType(id, draco::MESH_FACE_ATTRIBUTE);
        for (size_t i=0; i<num_rows; i++) {
            draco_mesh->attribute(id)->SetAttributeValue(
                    draco::AttributeValueIndex(i), values.data() + i*num_cols);
        }

        std::unique_ptr<draco::AttributeMetadata> metadata =
            std::make_unique<draco::AttributeMetadata>();
        metadata->AddEntryString("name", name);
        draco_mesh->AddAttributeMetadata(id, std::move(metadata));
    }
}
Example #2
0
Elements::Ptr Elements::adapt_boundary(Mesh::Ptr mesh) {
    if (mesh->get_num_voxels() > 0) {
        const size_t vertex_per_voxel = mesh->get_vertex_per_voxel();
        switch (vertex_per_voxel) {
            case 4:
                return Ptr(new TriangleElements(mesh));
            default:
                std::stringstream err_msg;
                err_msg << "Voxel with " << vertex_per_voxel
                    << " vertices is not supported yet.";
                throw NotImplementedError(err_msg.str());
        }
    } else {
        const size_t vertex_per_face = mesh->get_vertex_per_face();
        switch (vertex_per_face) {
            case 3:
                return Ptr(new EdgeElements(mesh));
            default:
                std::stringstream err_msg;
                err_msg << "Face with " << vertex_per_face
                    << " vertices is not supported yet.";
                throw NotImplementedError(err_msg.str());
        }
    }
}
Example #3
0
	std::shared_ptr<Mesh> FbxParser::CreateMesh(GameObjectPtr node, FbxNode * fbxNode)
	{
		Mesh::Ptr mesh = Mesh::Create(fbxNode->GetName());

		FbxMesh* fbxMesh = static_cast<FbxMesh*>(fbxNode->GetNodeAttribute());

		int polygonCount = fbxMesh->GetPolygonCount();
		int indicesCount = polygonCount * 3;
			
		mesh->Positions.Data.reserve(indicesCount * 3);
		mesh->Indices.Data.reserve(indicesCount);
		mesh->Colors.Data.reserve(indicesCount * 3);

		for (int i = 0; i < polygonCount; ++i) {
			ASSERT(fbxMesh->GetPolygonSize(i) <= 3,  "Error: triangulate %s", mesh->GetName());

			for (int jj = 0; jj < 3; ++jj) {
				int ctrPointIdx = fbxMesh->GetPolygonVertex(i, jj);
				// TODO 
				// Use Triangle Strip instead of triangle list
				auto position = fbxMesh->GetControlPointAt(ctrPointIdx);

				mesh->Positions.Data.push_back((double*)&position);

				int indices = i * 3 + jj;
				mesh->Indices.Data.push_back(indices);

				auto color = fbxMesh->GetElementVertexColor(ctrPointIdx);
				mesh->Colors.Data.push_back((double*)&color);
			}
		}
		mesh->UpdateBuffer();
		return mesh;
	}
Example #4
0
void copy_faces(Mesh::Ptr mesh, std::unique_ptr<DracoMesh>& draco_mesh) {
    const auto num_faces = mesh->get_num_faces();
    const auto& faces = mesh->get_faces();
    for (int i = 0; i < num_faces; ++i) {
        draco_mesh->AddFace({{
                draco::PointIndex(faces[i*3]),
                draco::PointIndex(faces[i*3+1]),
                draco::PointIndex(faces[i*3+2])
                }});
    }
}
Example #5
0
	std::shared_ptr<Mesh> MeshUtil::CreateQuad(const std::string &name, Vector4 min, Vector4 max)
	{
		Mesh::Ptr mesh = Mesh::Create(name);

		// 1----0
		// |    |
		// 2----3
		mesh->Positions.Data = { max.x, max.y, max.z, min.x, max.y, max.z, min.x, min.y, min.z, max.x, min.y, min.z };
		mesh->Indices.Data = { 0, 1, 2, 2, 3, 0 };
		mesh->UVs.Data = { 1, 1, 0, 1, 0, 0, 1, 0 };

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		mesh->CalculateAABB();

		return mesh;
	}
Example #6
0
	std::shared_ptr<Mesh> MeshUtil::CreateCube(const std::string &name, Vector4 min, Vector4 max)
	{
		Mesh::Ptr mesh = Mesh::Create(name);
		mesh->Positions.Data = {
			// FTR, FTL, FBL, FBR
			max.x, max.y, max.z,
			min.x, max.y, max.z,
			min.x, min.y, max.z,
			max.x, min.y, max.z,
			// BTR, BTL, BBL, BBR
			max.x, max.y, min.z,
			min.x, max.y, min.z,
			min.x, min.y, min.z,
			max.x, min.y, min.z
		};
		mesh->Indices.Data = {
			// front
			//0, 1, 2, 2, 3, 0,
			0, 3, 2, 2, 1, 0,
			// back
			//4, 7, 6, 6, 5, 4,
			4, 5, 6, 6, 7, 4,
			// left
			//2, 1, 5, 5, 6, 2,
			2, 6, 5, 5, 1, 2,
			// right
			//4, 0, 3, 3, 7, 4,
			4, 7, 3, 3, 0, 4,
			// top
			//4, 5, 1, 1, 0, 4,
			4, 0, 1, 1, 5, 4,
			// bottom
			//2, 6, 7, 7, 3, 2
			2, 3, 7, 7, 6, 2
		};

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		mesh->CalculateAABB();

		return mesh;
	}
Example #7
0
void InflatorEngine::save_mesh(const std::string& filename,
        const MatrixFr& vertices, const MatrixIr& faces, VectorF debug) {
    VectorF flattened_vertices(vertices.rows() * vertices.cols());
    std::copy(vertices.data(), vertices.data() + vertices.rows() *
            vertices.cols(), flattened_vertices.data());
    VectorI flattened_faces(faces.rows() * faces.cols());
    std::copy(faces.data(), faces.data() + faces.rows() * faces.cols(),
            flattened_faces.data());
    VectorI voxels = VectorI::Zero(0);

    Mesh::Ptr mesh = MeshFactory().load_data(
            flattened_vertices, flattened_faces, voxels,
            vertices.cols(), faces.cols(), 0).create_shared();
    mesh->add_attribute("debug");
    mesh->set_attribute("debug", debug);

    MeshWriter::Ptr writer = MeshWriter::create(filename);
    writer->with_attribute("debug");
    writer->write_mesh(*mesh);
}
Example #8
0
std::unique_ptr<draco::PointCloud> to_draco_point_cloud(Mesh::Ptr mesh,
        bool with_attributes=true) {
    std::unique_ptr<draco::PointCloud> draco_mesh(new draco::PointCloud());
    assert(mesh->get_num_faces() == 0);
    copy_vertices(mesh, draco_mesh);

    if (with_attributes) {
        copy_vertex_attributes(mesh, draco_mesh);
    }

    return draco_mesh;
}
Example #9
0
GeoMeshPtr GeogramMeshUtils::mesh_to_geomesh(const Mesh::Ptr mesh) {
    const size_t dim = mesh->get_dim();
    const size_t vertex_per_face = mesh->get_vertex_per_face();
    const size_t num_vertices = mesh->get_num_vertices();
    const size_t num_faces = mesh->get_num_faces();
    const auto& vertices = mesh->get_vertices();
    const auto& faces = mesh->get_faces();

    if (vertex_per_face != 3) {
        throw NotImplementedError("Converting non-triangle mesh to "
                "Geogram mesh is not yet implemented");
    }

    auto geo_mesh = std::make_shared<GeoMesh>(dim, false);
    geo_mesh->vertices.clear();
    geo_mesh->vertices.create_vertices(num_vertices);
    geo_mesh->facets.clear();
    geo_mesh->facets.create_triangles(num_faces);

    for (size_t i=0; i<num_vertices; i++) {
        auto& p = geo_mesh->vertices.point(i);
        for (size_t j=0; j<dim; j++) {
            p[j] = vertices[i*dim+j];
        }
    }

    for (size_t i=0; i<num_faces; i++) {
        geo_mesh->facets.set_vertex(i, 0, faces[i*3]);
        geo_mesh->facets.set_vertex(i, 1, faces[i*3+1]);
        geo_mesh->facets.set_vertex(i, 2, faces[i*3+2]);
    }

    return geo_mesh;
}
Example #10
0
void copy_vertices(Mesh::Ptr mesh, std::unique_ptr<DracoMesh>& draco_mesh) {
    const auto dim = mesh->get_dim();
    const auto num_vertices = mesh->get_num_vertices();
    draco_mesh->set_num_points(num_vertices);
    draco::GeometryAttribute positions;
    positions.Init(draco::GeometryAttribute::POSITION, // Attribute type
            nullptr,                                   // data buffer
            dim,                                       // number of components
            draco::DT_FLOAT64,                         // data type
            false,                                     // normalized
            sizeof(Float) * dim,                       // byte stride
            0);                                        // byte offset
    auto pos_att_id = draco_mesh->AddAttribute(
            positions,      // attribute object
            true,           // identity mapping
            num_vertices);  // num attribute values

    for (int i = 0; i < num_vertices; ++i) {
        draco_mesh->attribute(pos_att_id)->SetAttributeValue(
                draco::AttributeValueIndex(i), mesh->get_vertex(i).data());
    }
}
Example #11
0
CellPartition::Ptr CellPartition::create(const Mesh::Ptr& mesh) {
    const MatrixFr vertices = MatrixUtils::reshape<MatrixFr>(
            mesh->get_vertices(), mesh->get_num_vertices(), mesh->get_dim());
    const MatrixIr faces = MatrixUtils::reshape<MatrixIr>(
            mesh->get_faces(), mesh->get_num_faces(),
            mesh->get_vertex_per_face());
    return CellPartition::Ptr(new CellPartition(vertices, faces));
}
Example #12
0
void copy_metadata(std::unique_ptr<DracoMesh>& draco_mesh, Mesh::Ptr mesh) {
    const auto metadata = draco_mesh->GetMetadata();
    if (metadata == nullptr) return;
    const auto& attr_metadatas = metadata->attribute_metadatas();
    for (const auto& attr_metadata : attr_metadatas) {
        std::string name="";
        attr_metadata->GetEntryString("name", &name);
        if (name == "") continue;
        auto uid = attr_metadata->att_unique_id();

        const auto attr = draco_mesh->GetAttributeByUniqueId(uid);
        const auto num_rows = attr->size();
        const auto num_cols = attr->num_components();

        VectorF data(num_rows * num_cols);
        for (size_t i=0; i<num_rows; i++) {
            attr->ConvertValue(draco::AttributeValueIndex(i),
                    data.data() + i*num_cols);
        }
        mesh->add_empty_attribute(name);
        mesh->set_attribute(name, data);
    }
}
Example #13
0
std::unique_ptr<draco::Mesh> to_draco_mesh(Mesh::Ptr mesh,
        bool with_attributes=true) {
    std::unique_ptr<draco::Mesh> draco_mesh(new draco::Mesh());

    const size_t vertex_per_face = mesh->get_vertex_per_face();
    if (vertex_per_face != 3) {
        throw NotImplementedError(
                "Draco encoding only supports triangle mesh.");
    }

    copy_vertices(mesh, draco_mesh);
    copy_faces(mesh, draco_mesh);

    if (with_attributes) {
        copy_vertex_attributes(mesh, draco_mesh);
        //copy_face_attributes(mesh, draco_mesh);
    }

    return draco_mesh;
}
Example #14
0
std::string DracoCompressionEngine::compress(Mesh::Ptr mesh) const {
    const size_t num_faces = mesh->get_num_faces();

    draco::EncoderBuffer buffer;
    draco::Encoder encoder;
    if (num_faces > 0) {
        auto draco_mesh = DracoCompressionEngineHelper::to_draco_mesh(mesh);
        const auto status = encoder.EncodeMeshToBuffer(*draco_mesh, &buffer);
        if (!status.ok()) {
            throw RuntimeError("Draco encoding error!");
        }
        return std::string(buffer.data(), buffer.size());
    } else {
        auto draco_mesh = DracoCompressionEngineHelper::to_draco_point_cloud(mesh);
        const auto status = encoder.EncodePointCloudToBuffer(*draco_mesh, &buffer);
        if (!status.ok()) {
            throw RuntimeError("Draco encoding error!");
        }
        return std::string(buffer.data(), buffer.size());
    }
}
Example #15
0
	std::shared_ptr<Mesh> FbxUtil::CreateMesh(FbxMesh *fbxMesh)
	{
		Mesh::Ptr mesh = Mesh::Create(fbxMesh->GetName());

		// read physical data.

		int polygonCount = fbxMesh->GetPolygonCount();
		int indicesCount = polygonCount * 3;

		mesh->Positions.Data.reserve(indicesCount * 3);
		mesh->Indices.Data.reserve(indicesCount);

		if ((m_Options & Options::UV) && fbxMesh->GetElementUVCount() > 0)
			mesh->UVs.Data.reserve(indicesCount * 2);

		if ((m_Options & Options::NORMAL) && fbxMesh->GetElementNormalCount() > 0)
			mesh->Normals.Data.reserve(indicesCount * 3);

		if ((m_Options & Options::TANGENT) && fbxMesh->GetElementTangent() > 0)
			mesh->Tangents.Data.reserve(indicesCount * 3);

		int normalCounter = 0, uvCounter = 0, tangentCounter = 0;

		for (int i = 0; i < polygonCount; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				int ctrPtrIndex = fbxMesh->GetPolygonVertex(i, j);

				auto position = fbxMesh->GetControlPointAt(ctrPtrIndex);
				mesh->Positions.Data.push_back((float)position.mData[0]);
				mesh->Positions.Data.push_back((float)position.mData[1]);
				mesh->Positions.Data.push_back((float)position.mData[2]);

				// uv
				if ((m_Options & Options::UV) && fbxMesh->GetElementUVCount() > 0)
				{
					int uvIndex = 0;
					FbxGeometryElementUV* vertexUV = fbxMesh->GetElementUV();

					if (vertexUV->GetMappingMode() == FbxGeometryElement::eByControlPoint)
					{
						if (vertexUV->GetReferenceMode() == FbxGeometryElement::eDirect)
							uvIndex = ctrPtrIndex;
						else if (vertexUV->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							uvIndex = vertexUV->GetIndexArray().GetAt(ctrPtrIndex);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");
					}
					else if (vertexUV->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
					{
						if (vertexUV->GetReferenceMode() == FbxGeometryElement::eDirect)
							uvIndex = uvCounter;
						else if (vertexUV->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							uvIndex = vertexUV->GetIndexArray().GetAt(uvCounter);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");

						uvCounter++;
					}

					auto uv = vertexUV->GetDirectArray().GetAt(uvIndex);
					mesh->UVs.Data.push_back((float)uv.mData[0]);
					mesh->UVs.Data.push_back(1.0f - (float)uv.mData[1]);
				}

				// normal
				if ((m_Options & Options::NORMAL) && fbxMesh->GetElementNormalCount() > 0)
				{
					int normalIndex = 0;
					FbxGeometryElementNormal* vertexNormal = fbxMesh->GetElementNormal();

					if (vertexNormal->GetMappingMode() == FbxGeometryElement::eByControlPoint)
					{
						if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eDirect)
							normalIndex = ctrPtrIndex;
						else if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							normalIndex = vertexNormal->GetIndexArray().GetAt(ctrPtrIndex);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");
					}
					else if (vertexNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
					{
						if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eDirect)
							normalIndex = normalCounter;
						else if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							normalIndex = vertexNormal->GetIndexArray().GetAt(normalCounter);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");

						normalCounter++;
					}

					auto normal = vertexNormal->GetDirectArray().GetAt(normalIndex);
					mesh->Normals.Data.push_back((float)normal.mData[0]);
					mesh->Normals.Data.push_back((float)normal.mData[1]);
					mesh->Normals.Data.push_back((float)normal.mData[2]);
				}

				// tangent
				if ((m_Options & Options::TANGENT) && fbxMesh->GetElementNormalCount() > 0)
				{
					int tangentIndex = 0;
					FbxGeometryElementTangent* vertexTangent = fbxMesh->GetElementTangent();

					if (vertexTangent->GetMappingMode() == FbxGeometryElement::eByControlPoint)
					{
						if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eDirect)
							tangentIndex = ctrPtrIndex;
						else if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							tangentIndex = vertexTangent->GetIndexArray().GetAt(ctrPtrIndex);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");
					}
					else if (vertexTangent->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
					{
						if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eDirect)
							tangentIndex = tangentCounter;
						else if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							tangentIndex = vertexTangent->GetIndexArray().GetAt(tangentCounter);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");

						tangentCounter++;
					}

					auto tangent = vertexTangent->GetDirectArray().GetAt(tangentIndex);
					mesh->Tangents.Data.push_back((float)tangent.mData[0]);
					mesh->Tangents.Data.push_back((float)tangent.mData[1]);
					mesh->Tangents.Data.push_back((float)tangent.mData[2]);
				}

				mesh->Indices.Data.push_back(i * 3 + j);
			}
		}

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		if(m_Options & Options::OPTIMIZE_MESH)
			MeshUtil::Instance()->OptimizeMesh(mesh);

		mesh->CalculateAABB();

		return mesh;
	}
Example #16
0
	std::shared_ptr<Mesh> MeshUtil::CreateIcoSphere(const std::string &name, float radius, int level)
	{
		Mesh::Ptr mesh = Mesh::Create(name);

		std::unordered_map<long long, unsigned int> middlePointIndexCache;
		unsigned int index = 0;

		auto AddVertex = [&mesh, &index, &radius](float x, float y, float z) -> unsigned int
		{
			float inverse_length = radius / std::sqrt(x * x + y * y + z * z);
			mesh->Positions.Data.insert(mesh->Positions.Data.end(), { x * inverse_length, y * inverse_length, z * inverse_length });
			return index++;
		};

		auto GetMidPoint = [&mesh, &middlePointIndexCache, &AddVertex](int p1, int p2) -> unsigned int
		{
			// first check if we have it already
			bool firstIsSmaller = p1 < p2;
			long long smallerIndex = firstIsSmaller ? p1 : p2;
			long long greaterIndex = firstIsSmaller ? p2 : p1;
			long long key = (smallerIndex << 32) + greaterIndex;

			auto it = middlePointIndexCache.find(key);
			if (it != middlePointIndexCache.end())
				return it->second;

			// not in cache, calculate it
			float p1x = mesh->Positions.Data[p1 * 3];
			float p1y = mesh->Positions.Data[p1 * 3 + 1];
			float p1z = mesh->Positions.Data[p1 * 3 + 2];
			float p2x = mesh->Positions.Data[p2 * 3];
			float p2y = mesh->Positions.Data[p2 * 3 + 1];
			float p2z = mesh->Positions.Data[p2 * 3 + 2];

			// add middle vertex makes sure point is on unit sphere
			unsigned int i = AddVertex((p1x + p2x) * 0.5f, (p1y + p2y) * 0.5f, (p1z + p2z) * 0.5f);

			// store it, return index
			middlePointIndexCache.emplace(key, i);
			return i;
		};

		// create 12 vertices of a icosahedron
		float t = (1 + std::sqrt(5.0f)) * 0.5f;

		AddVertex(-1, t, 0);
		AddVertex(1, t, 0);
		AddVertex(-1, -t, 0);
		AddVertex(1, -t, 0);

		AddVertex(0, -1, t);
		AddVertex(0, 1, t);
		AddVertex(0, -1, -t);
		AddVertex(0, 1, -t);

		AddVertex(t, 0, -1);
		AddVertex(t, 0, 1);
		AddVertex(-t, 0, -1);
		AddVertex(-t, 0, 1);

		// create 20 triangles of the icosahedron
		mesh->Indices.Data = {
			// 5 faces around point 0
			0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
			// 5 adjacent faces 
			1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
			// 5 faces around point 3
			3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
			// 5 adjacent faces 
			4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
		};

		// refine triangles
		std::vector<unsigned int> newIndices;
		unsigned int oldSize = mesh->Indices.Data.size();

		for (int i = 0; i < level; i++)
		{
			// allocate memory
			newIndices.reserve(oldSize * 4);
			newIndices.erase(newIndices.begin(), newIndices.end());

			unsigned int numIndices = mesh->Indices.Data.size() / 3;
			for (unsigned int j = 0; j < numIndices; j++)
			{
				unsigned int index1 = mesh->Indices.Data[j * 3];
				unsigned int index2 = mesh->Indices.Data[j * 3 + 1];
				unsigned int index3 = mesh->Indices.Data[j * 3 + 2];

				unsigned int a = GetMidPoint(index1, index2);
				unsigned int b = GetMidPoint(index2, index3);
				unsigned int c = GetMidPoint(index3, index1);

				newIndices.insert(newIndices.end(), { index1, a, c, index2, b, a, index3, c, b, a, b, c });
			}

			oldSize = newIndices.size();
			mesh->Indices.Data = newIndices;
		}

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		mesh->CalculateAABB();

		return mesh;
	}
Example #17
0
	std::shared_ptr<Mesh> MeshUtil::CreateSphere(const std::string &name, float radius, int segH, int segV)
	{
		if (segH < 2 || segV < 3)
		{
			LOGW << "SegH or SegV tooooo small!";
			return nullptr;
		}

		Mesh::Ptr mesh = Mesh::Create(name);

		float avgRadianH = Angle::PI / (segH - 1);
		float avgRadianV = Angle::PI * 2.0f / segV;

		float currentHeight = radius;
		float currentRadius = 0.0f;

		std::vector<unsigned int> previousRing;
		previousRing.reserve(segV * 3);

		std::vector<unsigned int> currentRing;
		currentRing.reserve(segV * 3);

		/*if (inclusive)
			radius = radius / std::cos(avgRadianH * 0.5f);*/

		unsigned int index = 0;
		auto AddVertex = [&currentRing, &mesh, &index](float x, float y, float z) -> unsigned int
		{
			mesh->Positions.Data.insert(mesh->Positions.Data.end(), { x, y, z });
			return index++;
		};

		for (int h = 0; h < segH; h++)
		{
			currentRadius = std::sin(h * avgRadianH) * radius;
			currentHeight = std::cos(h * avgRadianH) * radius;

			// fill current ring
			for (int v = 0; v < segV; v++)
			{
				float radian = avgRadianV * v;
				currentRing.push_back(AddVertex(
					cos(radian) * currentRadius, currentHeight, sin(radian) * currentRadius));
			}

			if (previousRing.size() > 0)
			{
				// has previous ring, we connect them to triangles.
				for (unsigned int i = 0; i < currentRing.size() - 1; i++)
				{
					mesh->Indices.Data.insert(mesh->Indices.Data.end(), {
						previousRing[i], previousRing[i + 1], currentRing[i + 1],
						currentRing[i + 1], currentRing[i], previousRing[i]
					});
				}
				mesh->Indices.Data.insert(mesh->Indices.Data.end(), {
					previousRing.back(), previousRing.front(), currentRing.front(),
					currentRing.front(), currentRing.back(), previousRing.back()
				});
			}
			else
			{
				// don't have previous ring, then we're on top.
				// close this ring.
				unsigned int center = AddVertex(0, currentHeight, 0);
				for (unsigned int i = 0; i < currentRing.size() - 1; i++)
				{
					mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing[i + 1], currentRing[i] });
				}
				mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing.front(), currentRing.back() });
			}

			previousRing = currentRing;
			currentRing.erase(currentRing.begin(), currentRing.end());
		}

		// close bottom ring
		unsigned int center = AddVertex(0, -radius, 0);
		for (unsigned int i = 0; i < previousRing.size() - 1; i++)
		{
			mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing[i], previousRing[i + 1] });
		}
		mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing.back(), previousRing.front() });

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		OptimizeMesh(mesh);

		mesh->CalculateAABB();

		return mesh;
	}
Example #18
0
	std::shared_ptr<Mesh> MeshUtil::CreateCylinder(const std::string &name, float topR, float bottomR, float height, int segH, int segV)
	{
		if (segH < 2 || segV < 3)
		{
			LOGW << "SegH or SegV tooooo small!";
			return nullptr;
		}

		Mesh::Ptr mesh = Mesh::Create(name);

		// allocate some space.
		mesh->Positions.Data.reserve((segV * segH + 2) * 3);
		mesh->Indices.Data.reserve((segV * segH * 2) * 3);

		float avgRadian = Angle::PI * 2.0f / segV;

		/*if (inclusive)
		{
		topR = topR / std::cos(avgRadian * 0.5f);
		bottomR = bottomR / std::cos(avgRadian * 0.5f);
		}*/

		float currentHeight = height / 2.0f;
		float currentRadius = topR;

		float heightStep = height / (segH - 1);
		float radiusSetp = (topR - bottomR) / (segH - 1);

		std::vector<unsigned int> previousRing;
		previousRing.reserve(segV * 3);

		std::vector<unsigned int> currentRing;
		currentRing.reserve(segV * 3);

		unsigned int index = 0;
		auto AddVertex = [&currentRing, &mesh, &index](float x, float y, float z) -> unsigned int
		{
			mesh->Positions.Data.insert(mesh->Positions.Data.end(), { x, y, z });
			return index++;
		};

		for (int h = 0; h < segH; h++)
		{
			// fill current ring
			for (int v = 0; v < segV; v++)
			{
				float radian = avgRadian * v;
				currentRing.push_back(AddVertex(
					cos(radian) * currentRadius, currentHeight, sin(radian) * currentRadius));
			}

			if (previousRing.size() > 0)
			{
				// has previous ring, we connect them to triangles.
				for (unsigned int i = 0; i < currentRing.size() - 1; i++)
				{
					mesh->Indices.Data.insert(mesh->Indices.Data.end(), {
						previousRing[i], previousRing[i + 1], currentRing[i + 1],
						currentRing[i + 1], currentRing[i], previousRing[i]
					});
				}
				mesh->Indices.Data.insert(mesh->Indices.Data.end(), {
					previousRing.back(), previousRing.front(), currentRing.front(),
					currentRing.front(), currentRing.back(), previousRing.back()
				});
			}
			else
			{
				// don't have previous ring, then we're on top.
				// close this ring.
				unsigned int center = AddVertex(0, currentHeight, 0);
				for (unsigned int i = 0; i < currentRing.size() - 1; i++)
				{
					mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing[i + 1], currentRing[i] });
				}
				mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing.front(), currentRing.back() });
			}

			previousRing = currentRing;
			currentRing.erase(currentRing.begin(), currentRing.end());
			currentHeight -= heightStep;
			currentRadius -= radiusSetp;
		}

		// close bottom ring
		unsigned int center = AddVertex(0, -height / 2.0f, 0);
		for (unsigned int i = 0; i < previousRing.size() - 1; i++)
		{
			mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing[i], previousRing[i + 1] });
		}
		mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing.back(), previousRing.front() });

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		if (topR == 0 || bottomR == 0)
			OptimizeMesh(mesh);

		mesh->CalculateAABB();

		return mesh;
	}