Files
filament/libs/geometry/src/MikktspaceImpl.cpp
Powei Feng dea345d28e geometry: fix mikktspace wrapper (#7651)
- Fix missing attributes in TangentSpaceMesh
- Fix missing reference in MikktspaceImpl.cpp
2024-03-11 22:27:46 +00:00

230 lines
9.0 KiB
C++

/*
* Copyright (C) 2023 The Android Open Source Project
*
* 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.
*/
#include "MikktspaceImpl.h"
#include <math/mat3.h>
#include <math/norm.h>
#include <utils/Panic.h>
#include <meshoptimizer.h>
#include <mikktspace/mikktspace.h>
#include <vector>
#include <string.h> // memcpy
namespace filament::geometry {
using namespace filament::math;
int MikktspaceImpl::getNumFaces(SMikkTSpaceContext const* context) noexcept {
auto const wrapper = MikktspaceImpl::getThis(context);
return wrapper->mFaceCount;
}
int MikktspaceImpl::getNumVerticesOfFace(SMikkTSpaceContext const* context,
int const iFace) noexcept {
return 3;
}
void MikktspaceImpl::getPosition(SMikkTSpaceContext const* context, float fvPosOut[],
int const iFace, int const iVert) noexcept {
auto const wrapper = MikktspaceImpl::getThis(context);
float3 const pos = *pointerAdd(wrapper->mPositions, wrapper->getTriangle(iFace)[iVert],
wrapper->mPositionStride);
fvPosOut[0] = pos.x;
fvPosOut[1] = pos.y;
fvPosOut[2] = pos.z;
}
void MikktspaceImpl::getNormal(SMikkTSpaceContext const* context, float fvNormOut[],
int const iFace, int const iVert) noexcept {
auto const wrapper = MikktspaceImpl::getThis(context);
float3 const normal = *pointerAdd(wrapper->mNormals, wrapper->getTriangle(iFace)[iVert],
wrapper->mNormalStride);
fvNormOut[0] = normal.x;
fvNormOut[1] = normal.y;
fvNormOut[2] = normal.z;
}
void MikktspaceImpl::getTexCoord(SMikkTSpaceContext const* context, float fvTexcOut[],
int const iFace, int const iVert) noexcept {
auto const wrapper = MikktspaceImpl::getThis(context);
float2 const texc
= *pointerAdd(wrapper->mUVs, wrapper->getTriangle(iFace)[iVert], wrapper->mUVStride);
fvTexcOut[0] = texc.x;
fvTexcOut[1] = texc.y;
}
void MikktspaceImpl::setTSpaceBasic(SMikkTSpaceContext const* context, float const fvTangent[],
float const fSign, int const iFace, int const iVert) noexcept {
auto const wrapper = MikktspaceImpl::getThis(context);
uint32_t const vertInd = wrapper->getTriangle(iFace)[iVert];
float3 const pos = *pointerAdd(wrapper->mPositions, vertInd, wrapper->mPositionStride);
float3 const n = normalize(*pointerAdd(wrapper->mNormals, vertInd, wrapper->mNormalStride));
float2 const uv = *pointerAdd(wrapper->mUVs, vertInd, wrapper->mUVStride);
float3 const t { fvTangent[0], fvTangent[1], fvTangent[2] };
float3 const b = fSign * normalize(cross(n, t));
// TODO: packTangentFrame actually changes the orientation of b.
quatf const quat = mat3f::packTangentFrame({t, b, n}, sizeof(int32_t));
auto& output = wrapper->mOutputData;
auto const& EMPTY_ELEMENT = wrapper->EMPTY_ELEMENT;
size_t const outputCurSize = output.size();
// Prepare for the next element
output.insert(output.end(), EMPTY_ELEMENT.begin(), EMPTY_ELEMENT.end());
uint8_t* cursor = output.data() + outputCurSize;
*((float3*) (cursor + POS_OFFSET)) = pos;
*((float2*) (cursor + UV_OFFSET)) = uv;
*((quatf*) (cursor + TBN_OFFSET)) = quat;
cursor += BASE_OUTPUT_SIZE;
for (auto const& inputAttrib: wrapper->mInputAttribArrays) {
uint8_t const* input = pointerAdd(inputAttrib.data, vertInd, inputAttrib.stride);
memcpy(cursor, input, inputAttrib.size);
cursor += inputAttrib.size;
}
}
MikktspaceImpl::MikktspaceImpl(const TangentSpaceMeshInput* input) noexcept
: mFaceCount((int) input->triangleCount),
mPositions(input->positions()),
mPositionStride(input->positionsStride()),
mNormals(input->normals()),
mNormalStride(input->normalsStride()),
mUVs(input->uvs()),
mUVStride(input->uvsStride()),
mIsTriangle16(input->triangles16),
mTriangles(
input->triangles16 ? (uint8_t*) input->triangles16 : (uint8_t*) input->triangles32),
mOutputElementSize(BASE_OUTPUT_SIZE) {
// We don't know how many attributes there are so we have to create an ordering of the
// output components. The first three components are
// - float3 positions
// - float2 uv
// - quatf tangent
for (auto attrib: input->getAuxAttributes()) {
size_t const attribSize =input->attributeSize(attrib);
mOutputElementSize += attribSize;
mInputAttribArrays.push_back({
.attrib = attrib,
.data = input->raw(attrib),
.stride = input->stride(attrib),
.size = attribSize,
});
}
mOutputData.reserve(mFaceCount * 3 * mOutputElementSize);
// We will insert 0s to signify a new element being added to the output.
EMPTY_ELEMENT = std::vector<uint8_t>(mOutputElementSize);
}
MikktspaceImpl* MikktspaceImpl::getThis(SMikkTSpaceContext const* context) noexcept {
return (MikktspaceImpl*) context->m_pUserData;
}
inline const uint3 MikktspaceImpl::getTriangle(int const triangleIndex) const noexcept {
const size_t tstride = mIsTriangle16 ? sizeof(ushort3) : sizeof(uint3);
return mIsTriangle16 ? uint3(*(ushort3*) (pointerAdd(mTriangles, triangleIndex, tstride)))
: *(uint3*) (pointerAdd(mTriangles, triangleIndex, tstride));
}
void MikktspaceImpl::run(TangentSpaceMeshOutput* output) noexcept {
SMikkTSpaceInterface interface {
.m_getNumFaces = MikktspaceImpl::getNumFaces,
.m_getNumVerticesOfFace = MikktspaceImpl::getNumVerticesOfFace,
.m_getPosition = MikktspaceImpl::getPosition,
.m_getNormal = MikktspaceImpl::getNormal,
.m_getTexCoord = MikktspaceImpl::getTexCoord,
.m_setTSpaceBasic = MikktspaceImpl::setTSpaceBasic,
};
SMikkTSpaceContext context{.m_pInterface = &interface, .m_pUserData = this};
genTangSpaceDefault(&context);
size_t oVertexCount = mOutputData.size() / mOutputElementSize;
std::vector<unsigned int> remap;
remap.resize(oVertexCount);
size_t vertexCount = meshopt_generateVertexRemap(remap.data(), NULL, remap.size(),
mOutputData.data(), oVertexCount, mOutputElementSize);
std::vector<uint8_t> newVertices(vertexCount * mOutputElementSize);
meshopt_remapVertexBuffer((void*) newVertices.data(), mOutputData.data(), oVertexCount,
mOutputElementSize, remap.data());
uint3* triangles32 = output->triangles32.allocate(mFaceCount);
meshopt_remapIndexBuffer((uint32_t*) triangles32, NULL, remap.size(), remap.data());
float3* outPositions = output->positions().allocate(vertexCount);
float2* outUVs = output->uvs().allocate(vertexCount);
quatf* outQuats = output->tspace().allocate(vertexCount);
uint8_t* const verts = newVertices.data();
std::vector<std::tuple<AttributeImpl, void*, size_t>> attributes;
for (auto const& inputAttrib: mInputAttribArrays) {
auto const attrib = inputAttrib.attrib;
switch(attrib) {
case AttributeImpl::UV1:
attributes.push_back(
{attrib, output->data<DATA_TYPE_UV1>(attrib).allocate(vertexCount),
inputAttrib.size});
break;
case AttributeImpl::COLORS:
attributes.push_back(
{attrib, output->data<DATA_TYPE_COLORS>(attrib).allocate(vertexCount),
inputAttrib.size});
break;
case AttributeImpl::JOINTS:
attributes.push_back(
{attrib, output->data<DATA_TYPE_JOINTS>(attrib).allocate(vertexCount),
inputAttrib.size});
break;
case AttributeImpl::WEIGHTS:
attributes.push_back(
{attrib, output->data<DATA_TYPE_WEIGHTS>(attrib).allocate(vertexCount),
inputAttrib.size});
break;
default:
PANIC_POSTCONDITION("Unexpected attribute=%d", (int) inputAttrib.attrib);
}
}
for (size_t i = 0, vi=0; i < vertexCount; ++i, vi+=mOutputElementSize) {
outPositions[i] = *((float3*) (verts + vi + POS_OFFSET));
outUVs[i] = *((float2*) (verts + vi + UV_OFFSET));
outQuats[i] = *((quatf*) (verts + vi + TBN_OFFSET));
uint8_t* cursor = verts + vi + BASE_OUTPUT_SIZE;
for (auto const [attrib, outdata, size] : attributes) {
memcpy((uint8_t*) outdata + (i * size), cursor, size);
cursor += size;
}
}
output->vertexCount = vertexCount;
output->triangleCount = mFaceCount;
}
}// namespace filament::geometry