mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Implement glTF texture wrapping support
This commit is contained in:
parent
2fee37f31b
commit
224066c1d3
3 changed files with 52 additions and 25 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include "dimension2d.h"
|
#include "dimension2d.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -34,6 +35,9 @@ public:
|
||||||
constexpr vector2d(const dimension2d<T> &other) :
|
constexpr vector2d(const dimension2d<T> &other) :
|
||||||
X(other.Width), Y(other.Height) {}
|
X(other.Width), Y(other.Height) {}
|
||||||
|
|
||||||
|
explicit constexpr vector2d(const std::array<T, 2> &arr) :
|
||||||
|
X(arr[0]), Y(arr[1]) {}
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
|
|
||||||
vector2d<T> operator-() const { return vector2d<T>(-X, -Y); }
|
vector2d<T> operator-() const { return vector2d<T>(-X, -Y); }
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "CGLTFMeshFileLoader.h"
|
#include "CGLTFMeshFileLoader.h"
|
||||||
|
|
||||||
|
#include "SMaterialLayer.h"
|
||||||
#include "coreutil.h"
|
#include "coreutil.h"
|
||||||
#include "CSkinnedMesh.h"
|
#include "CSkinnedMesh.h"
|
||||||
#include "ISkinnedMesh.h"
|
#include "ISkinnedMesh.h"
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
#include "matrix4.h"
|
#include "matrix4.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "quaternion.h"
|
#include "quaternion.h"
|
||||||
|
#include "vector2d.h"
|
||||||
#include "vector3d.h"
|
#include "vector3d.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
@ -381,6 +383,20 @@ static std::vector<u16> generateIndices(const std::size_t nVerts)
|
||||||
return indices;
|
return indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using Wrap = tiniergltf::Sampler::Wrap;
|
||||||
|
static video::E_TEXTURE_CLAMP convertTextureWrap(const Wrap wrap) {
|
||||||
|
switch (wrap) {
|
||||||
|
case Wrap::REPEAT:
|
||||||
|
return video::ETC_REPEAT;
|
||||||
|
case Wrap::CLAMP_TO_EDGE:
|
||||||
|
return video::ETC_CLAMP_TO_EDGE;
|
||||||
|
case Wrap::MIRRORED_REPEAT:
|
||||||
|
return video::ETC_MIRROR;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("invalid sampler wrapping mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load up the rawest form of the model. The vertex positions and indices.
|
* Load up the rawest form of the model. The vertex positions and indices.
|
||||||
* Documentation: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes
|
* Documentation: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes
|
||||||
|
@ -415,6 +431,8 @@ void SelfType::MeshExtractor::loadMesh(
|
||||||
|
|
||||||
m_irr_model->addMeshBuffer(
|
m_irr_model->addMeshBuffer(
|
||||||
new SSkinMeshBuffer(std::move(*vertices), std::move(indices)));
|
new SSkinMeshBuffer(std::move(*vertices), std::move(indices)));
|
||||||
|
auto *meshbuf = m_irr_model->getMeshBuffer(m_irr_model->getMeshBufferCount() - 1);
|
||||||
|
auto &irr_mat = meshbuf->getMaterial();
|
||||||
|
|
||||||
if (primitive.material.has_value()) {
|
if (primitive.material.has_value()) {
|
||||||
const auto &material = m_gltf_model.materials->at(*primitive.material);
|
const auto &material = m_gltf_model.materials->at(*primitive.material);
|
||||||
|
@ -423,6 +441,13 @@ void SelfType::MeshExtractor::loadMesh(
|
||||||
if (texture.has_value()) {
|
if (texture.has_value()) {
|
||||||
const auto meshbufNr = m_irr_model->getMeshBufferCount() - 1;
|
const auto meshbufNr = m_irr_model->getMeshBufferCount() - 1;
|
||||||
m_irr_model->setTextureSlot(meshbufNr, static_cast<u32>(texture->index));
|
m_irr_model->setTextureSlot(meshbufNr, static_cast<u32>(texture->index));
|
||||||
|
const auto samplerIdx = m_gltf_model.textures->at(texture->index).sampler;
|
||||||
|
if (samplerIdx.has_value()) {
|
||||||
|
auto &sampler = m_gltf_model.samplers->at(*samplerIdx);
|
||||||
|
auto &layer = irr_mat.TextureLayers[0];
|
||||||
|
layer.TextureWrapU = convertTextureWrap(sampler.wrapS);
|
||||||
|
layer.TextureWrapV = convertTextureWrap(sampler.wrapT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -650,11 +675,19 @@ void SelfType::MeshExtractor::copyTCoords(
|
||||||
const std::size_t accessorIdx,
|
const std::size_t accessorIdx,
|
||||||
std::vector<video::S3DVertex>& vertices) const
|
std::vector<video::S3DVertex>& vertices) const
|
||||||
{
|
{
|
||||||
|
const auto componentType = m_gltf_model.accessors->at(accessorIdx).componentType;
|
||||||
|
if (componentType == tiniergltf::Accessor::ComponentType::FLOAT) {
|
||||||
|
// If floats are used, they need not be normalized: Wrapping may take effect.
|
||||||
|
const auto accessor = Accessor<std::array<f32, 2>>::make(m_gltf_model, accessorIdx);
|
||||||
|
for (std::size_t i = 0; i < accessor.getCount(); ++i) {
|
||||||
|
vertices[i].TCoords = core::vector2d<f32>(accessor.get(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const auto accessor = createNormalizedValuesAccessor<2>(m_gltf_model, accessorIdx);
|
const auto accessor = createNormalizedValuesAccessor<2>(m_gltf_model, accessorIdx);
|
||||||
const auto count = std::visit([](auto &&a) { return a.getCount(); }, accessor);
|
const auto count = std::visit([](auto &&a) { return a.getCount(); }, accessor);
|
||||||
for (std::size_t i = 0; i < count; ++i) {
|
for (std::size_t i = 0; i < count; ++i) {
|
||||||
const auto vals = getNormalizedValues(accessor, i);
|
vertices[i].TCoords = core::vector2d<f32>(getNormalizedValues(accessor, i));
|
||||||
vertices[i].TCoords = core::vector2df(vals[0], vals[1]);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -980,21 +980,16 @@ struct Sampler {
|
||||||
};
|
};
|
||||||
std::optional<MinFilter> minFilter;
|
std::optional<MinFilter> minFilter;
|
||||||
std::optional<std::string> name;
|
std::optional<std::string> name;
|
||||||
enum class WrapS {
|
enum class Wrap {
|
||||||
REPEAT,
|
REPEAT,
|
||||||
CLAMP_TO_EDGE,
|
CLAMP_TO_EDGE,
|
||||||
MIRRORED_REPEAT,
|
MIRRORED_REPEAT,
|
||||||
};
|
};
|
||||||
WrapS wrapS;
|
Wrap wrapS;
|
||||||
enum class WrapT {
|
Wrap wrapT;
|
||||||
REPEAT,
|
|
||||||
CLAMP_TO_EDGE,
|
|
||||||
MIRRORED_REPEAT,
|
|
||||||
};
|
|
||||||
WrapT wrapT;
|
|
||||||
Sampler(const Json::Value &o)
|
Sampler(const Json::Value &o)
|
||||||
: wrapS(WrapS::REPEAT)
|
: wrapS(Wrap::REPEAT)
|
||||||
, wrapT(WrapT::REPEAT)
|
, wrapT(Wrap::REPEAT)
|
||||||
{
|
{
|
||||||
check(o.isObject());
|
check(o.isObject());
|
||||||
if (o.isMember("magFilter")) {
|
if (o.isMember("magFilter")) {
|
||||||
|
@ -1020,21 +1015,16 @@ struct Sampler {
|
||||||
if (o.isMember("name")) {
|
if (o.isMember("name")) {
|
||||||
name = as<std::string>(o["name"]);
|
name = as<std::string>(o["name"]);
|
||||||
}
|
}
|
||||||
if (o.isMember("wrapS")) {
|
static std::unordered_map<Json::UInt64, Wrap> map = {
|
||||||
static std::unordered_map<Json::UInt64, WrapS> map = {
|
{10497, Wrap::REPEAT},
|
||||||
{10497, WrapS::REPEAT},
|
{33071, Wrap::CLAMP_TO_EDGE},
|
||||||
{33071, WrapS::CLAMP_TO_EDGE},
|
{33648, Wrap::MIRRORED_REPEAT},
|
||||||
{33648, WrapS::MIRRORED_REPEAT},
|
|
||||||
};
|
};
|
||||||
|
if (o.isMember("wrapS")) {
|
||||||
const auto &v = o["wrapS"]; check(v.isUInt64());
|
const auto &v = o["wrapS"]; check(v.isUInt64());
|
||||||
wrapS = map.at(v.asUInt64());
|
wrapS = map.at(v.asUInt64());
|
||||||
}
|
}
|
||||||
if (o.isMember("wrapT")) {
|
if (o.isMember("wrapT")) {
|
||||||
static std::unordered_map<Json::UInt64, WrapT> map = {
|
|
||||||
{10497, WrapT::REPEAT},
|
|
||||||
{33071, WrapT::CLAMP_TO_EDGE},
|
|
||||||
{33648, WrapT::MIRRORED_REPEAT},
|
|
||||||
};
|
|
||||||
const auto &v = o["wrapT"]; check(v.isUInt64());
|
const auto &v = o["wrapT"]; check(v.isUInt64());
|
||||||
wrapT = map.at(v.asUInt64());
|
wrapT = map.at(v.asUInt64());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue