Added some basic geometry functionality (only tangent generation for now).

This commit is contained in:
Patrick 2023-12-07 17:16:08 +01:00
parent b89f19ed98
commit 1d8ef0bac8
3 changed files with 242 additions and 0 deletions

View File

@ -0,0 +1,103 @@
#pragma once
#if !defined(MIJIN_GEO_GEOMETRY_TRAITS_HPP_INCLUDED)
#define MIJIN_GEO_GEOMETRY_TRAITS_HPP_INCLUDED 1
#include <concepts>
#include <ranges>
namespace mijin
{
template<typename T>
struct Vector2Traits;
template<typename T>
concept Vector2 = requires(const std::decay_t<T> constObject, std::decay_t<T> nonConstObject)
{
{ mijin::Vector2Traits<std::decay_t<T>>{}.getX(constObject) } -> std::convertible_to<float>;
{ mijin::Vector2Traits<std::decay_t<T>>{}.getY(constObject) } -> std::convertible_to<float>;
{ mijin::Vector2Traits<std::decay_t<T>>{}.setX(nonConstObject, 0.f) };
{ mijin::Vector2Traits<std::decay_t<T>>{}.setY(nonConstObject, 0.f) };
};
template<typename T>
struct Vector3Traits;
template<typename T>
concept Vector3 = requires(const std::decay_t<T> constObject, std::decay_t<T> nonConstObject)
{
{ mijin::Vector3Traits<std::decay_t<T>>{}.getX(constObject) } -> std::convertible_to<float>;
{ mijin::Vector3Traits<std::decay_t<T>>{}.getY(constObject) } -> std::convertible_to<float>;
{ mijin::Vector3Traits<std::decay_t<T>>{}.getZ(constObject) } -> std::convertible_to<float>;
{ mijin::Vector3Traits<std::decay_t<T>>{}.setX(nonConstObject, 0.f) };
{ mijin::Vector3Traits<std::decay_t<T>>{}.setY(nonConstObject, 0.f) };
{ mijin::Vector3Traits<std::decay_t<T>>{}.setZ(nonConstObject, 0.f) };
};
template<typename T>
concept Index = std::convertible_to<T, std::size_t>;
template<typename T>
concept Vector2Iterator = requires(T object)
{
{ std::iterator_traits<T>::value_type } -> Vector2;
};
template<typename T>
concept Vector3Iterator = requires(T object)
{
{ std::iterator_traits<T>::value_type } -> Vector3;
};
template<typename T>
concept Vector2Range = std::ranges::random_access_range<T> && Vector2<std::ranges::range_value_t<T>>;
template<typename T>
concept Vector3Range = std::ranges::random_access_range<T> && Vector3<std::ranges::range_value_t<T>>;
template<typename T>
concept IndexRange = std::ranges::random_access_range<T> && Index<std::ranges::range_value_t<T>>;
template<typename T>
struct Mesh3DTraits;
template<typename T>
concept Mesh3D = requires(const T constObject, T nonConstObject, mijin::Mesh3DTraits<T>::index_t index, mijin::Mesh3DTraits<T>::vector3_t vec3Value)
{
{ typename mijin::Mesh3DTraits<T>::index_t() } -> Index;
{ typename mijin::Mesh3DTraits<T>::vector3_t() } -> Vector3;
{ mijin::Mesh3DTraits<T>{}.getNumFaces(constObject) } -> std::convertible_to<std::size_t>;
{ mijin::Mesh3DTraits<T>{}.getNumVertices(constObject) } -> std::convertible_to<std::size_t>;
{ mijin::Mesh3DTraits<T>{}.getFaceNumVertices(constObject, index) } -> std::convertible_to<std::size_t>;
{ mijin::Mesh3DTraits<T>{}.getPosition(constObject, index, index) } -> Vector3;
{ mijin::Mesh3DTraits<T>{}.setPosition(nonConstObject, index, index, vec3Value) };
};
template<typename T>
concept Mesh3DWithNormals = Mesh3D<T> && requires(const T constObject, T nonConstObject, mijin::Mesh3DTraits<T>::index_t index, mijin::Mesh3DTraits<T>::vector3_t vec3Value)
{
{ mijin::Mesh3DTraits<T>{}.getNormal(constObject, index, index) } -> Vector3;
{ mijin::Mesh3DTraits<T>{}.setNormal(nonConstObject, index, index, vec3Value) };
};
template<typename T>
concept Mesh3DWithTangents = Mesh3D<T> && requires(const T constObject, T nonConstObject, mijin::Mesh3DTraits<T>::index_t index, mijin::Mesh3DTraits<T>::vector3_t vec3Value)
{
{ mijin::Mesh3DTraits<T>{}.getTangent(constObject, index, index) } -> Vector3;
{ mijin::Mesh3DTraits<T>{}.setTangent(nonConstObject, index, index, vec3Value) };
};
template<typename T>
concept Mesh3DWithTexCoords = Mesh3D<T> && requires(const T constObject, T nonConstObject, mijin::Mesh3DTraits<T>::index_t index, mijin::Mesh3DTraits<T>::vector2_t vec2Value)
{
{ mijin::Mesh3DTraits<T>{}.getTexCoord(constObject, index, index) } -> Vector2;
{ mijin::Mesh3DTraits<T>{}.setTexCoord(nonConstObject, index, index, vec2Value) };
};
template<typename T>
concept FullMesh3D = Mesh3DWithNormals<T> && Mesh3DWithTangents<T> && Mesh3DWithTexCoords<T>;
}
#endif // MIJIN_GEO_GEOMETRY_TRAITS_HPP_INCLUDED

View File

@ -0,0 +1,37 @@
#pragma once
#if !defined(MIJIN_GEO_GLM_ADAPTER_HPP_INCLUDED)
#define MIJIN_GEO_GLM_ADAPTER_HPP_INCLUDED 1
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include "./geometry_traits.hpp"
namespace mijin
{
template<>
struct Vector2Traits<glm::vec2>
{
constexpr float getX(const glm::vec2& vector) const noexcept { return vector.x; }
constexpr float getY(const glm::vec2& vector) const noexcept { return vector.y; }
constexpr void setX(glm::vec2& vector, float value) const noexcept { vector.x = value; }
constexpr void setY(glm::vec2& vector, float value) const noexcept { vector.y = value; }
};
static_assert(Vector2<glm::vec2>, "Vector2Adapter not working.");
template<>
struct Vector3Traits<glm::vec3>
{
constexpr float getX(const glm::vec3& vector) const noexcept { return vector.x; }
constexpr float getY(const glm::vec3& vector) const noexcept { return vector.y; }
constexpr float getZ(const glm::vec3& vector) const noexcept { return vector.z; }
constexpr void setX(glm::vec3& vector, float value) const noexcept { vector.x = value; }
constexpr void setY(glm::vec3& vector, float value) const noexcept { vector.y = value; }
constexpr void setZ(glm::vec3& vector, float value) const noexcept { vector.z = value; }
};
static_assert(Vector3<glm::vec3>, "Vector3Adapter not working.");
}
#endif // MIJIN_GEO_GLM_ADAPTER_HPP_INCLUDED

View File

@ -0,0 +1,102 @@
#pragma once
#if !defined(MIJIN_GEO_TANGENT_GENERATION_HPP_INCLUDED)
#define MIJIN_GEO_TANGENT_GENERATION_HPP_INCLUDED 1
#include <mikktspace.h>
#include "./geometry_traits.hpp"
namespace mijin
{
namespace impl
{
template<FullMesh3D TMesh>
struct MikktData
{
Mesh3DTraits<TMesh> traits;
Vector2Traits<typename TMesh::vector2_t> vec2Traits;
Vector3Traits<typename TMesh::vector3_t> vec3Traits;
TMesh* mesh;
};
template<FullMesh3D TMesh>
int mikktGetNumFaces(const SMikkTSpaceContext* context)
{
const MikktData<TMesh>& data = *static_cast<MikktData<TMesh>*>(context->m_pUserData);
return static_cast<int>(data.traits.getNumFaces(*data.mesh));
}
template<FullMesh3D TMesh>
int mikktGetNumVerticesOfFace(const SMikkTSpaceContext* context, const int face)
{
const MikktData<TMesh>& data = *static_cast<MikktData<TMesh>*>(context->m_pUserData);
return static_cast<int>(data.traits.getFaceNumVertices(*data.mesh, face));
}
template<FullMesh3D TMesh>
void mikktGetPosition(const SMikkTSpaceContext* context, float posOut[], const int face, const int vert) // NOLINT
{
const MikktData<TMesh>& data = *static_cast<MikktData<TMesh>*>(context->m_pUserData);
const auto position = data.traits.getPosition(*data.mesh, face, vert);
posOut[0] = data.vec3Traits.getX(position);
posOut[1] = data.vec3Traits.getY(position);
posOut[2] = data.vec3Traits.getZ(position);
}
template<FullMesh3D TMesh>
void mikktGetNormal(const SMikkTSpaceContext* context, float normOut[], const int face, const int vert) // NOLINT
{
const MikktData<TMesh>& data = *static_cast<MikktData<TMesh>*>(context->m_pUserData);
const auto normal = data.traits.getNormal(*data.mesh, face, vert);
normOut[0] = data.vec3Traits.getX(normal);
normOut[1] = data.vec3Traits.getY(normal);
normOut[2] = data.vec3Traits.getZ(normal);
}
template<FullMesh3D TMesh>
void mikktGetTexCoord(const SMikkTSpaceContext* context, float texcOut[], const int face, const int vert) // NOLINT
{
const MikktData<TMesh>& data = *static_cast<MikktData<TMesh>*>(context->m_pUserData);
const auto texCoord = data.traits.getTexCoord(*data.mesh, face, vert);
texcOut[0] = data.vec2Traits.getX(texCoord);
texcOut[1] = data.vec2Traits.getY(texCoord);
}
template<FullMesh3D TMesh>
void mikktSetTSpaceBasic(const SMikkTSpaceContext* context, const float resultTangent[], const float sign, const int face, const int vert) // NOLINT
{
// TODO: what do we do with sign? (it should be used for the direction of the bitangent)
(void) sign;
const MikktData<TMesh>& data = *static_cast<MikktData<TMesh>*>(context->m_pUserData);
typename Mesh3DTraits<TMesh>::vector3_t tangent;
data.vec3Traits.setX(tangent, resultTangent[0]);
data.vec3Traits.setY(tangent, resultTangent[1]);
data.vec3Traits.setZ(tangent, resultTangent[2]);
data.traits.setTangent(*data.mesh, face, vert, tangent);
}
}
template<FullMesh3D TMesh>
bool generateTangentsMikkt(TMesh& mesh)
{
SMikkTSpaceInterface mikktInterface = {
.m_getNumFaces = &impl::mikktGetNumFaces<TMesh>,
.m_getNumVerticesOfFace = &impl::mikktGetNumVerticesOfFace<TMesh>,
.m_getPosition = &impl::mikktGetPosition<TMesh>,
.m_getNormal = &impl::mikktGetNormal<TMesh>,
.m_getTexCoord = &impl::mikktGetTexCoord<TMesh>,
.m_setTSpaceBasic = &impl::mikktSetTSpaceBasic<TMesh>
};
impl::MikktData<TMesh> data = {
.mesh = &mesh
};
const SMikkTSpaceContext context = {
.m_pInterface = &mikktInterface,
.m_pUserData = &data
};
return genTangSpaceDefault(&context);
}
}
#endif // MIJIN_GEO_TANGENT_GENERATION_HPP_INCLUDED