Пример #1
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;
	}
Пример #2
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;
	}
Пример #3
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;
	}
Пример #4
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;
	}
Пример #5
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;
	}
Пример #6
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;
	}