mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
get tangent generation working again
This commit is contained in:
parent
6d726e6501
commit
b06403ff32
@ -36,6 +36,8 @@ set(SRC_FILES
|
|||||||
"src/libs/stb_impl.cpp"
|
"src/libs/stb_impl.cpp"
|
||||||
"src/libs/tiny_gltf.h"
|
"src/libs/tiny_gltf.h"
|
||||||
"src/libs/tiny_gltf_impl.cpp"
|
"src/libs/tiny_gltf_impl.cpp"
|
||||||
|
"src/libs/weldmesh.c"
|
||||||
|
"src/libs/weldmesh.h"
|
||||||
"src/renderer.cpp"
|
"src/renderer.cpp"
|
||||||
"src/resources/font.cpp"
|
"src/resources/font.cpp"
|
||||||
"src/resources/material.cpp"
|
"src/resources/material.cpp"
|
||||||
|
@ -268,7 +268,7 @@ void Application::GameLoop()
|
|||||||
int depth = find_depth(i, 0);
|
int depth = find_depth(i, 0);
|
||||||
for (int j = 0; j < depth; ++j) tabs += std::string{" "};
|
for (int j = 0; j < depth; ++j) tabs += std::string{" "};
|
||||||
ImGui::Text("%s%s", tabs.c_str(), t->tag.c_str());
|
ImGui::Text("%s%s", tabs.c_str(), t->tag.c_str());
|
||||||
ImGui::Text("%.1f %.1f %.1f", t->position.x, t->position.y, t->position.z);
|
//ImGui::Text("%.1f %.1f %.1f", t->position.x, t->position.y, t->position.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
194
src/libs/weldmesh.c
Normal file
194
src/libs/weldmesh.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2011 by Morten S. Mikkelsen
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "weldmesh.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <stdlib.h> /* OSX gets its malloc stuff through here */
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void MergeVertsFast(int * piCurNrUniqueVertices, int * piRemapTable, float * pfVertexDataOut, int * piVertexIDs,
|
||||||
|
const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert,
|
||||||
|
const int iL_in, const int iR_in, const int iChannelNum);
|
||||||
|
|
||||||
|
int WeldMesh(int * piRemapTable, float * pfVertexDataOut,
|
||||||
|
const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert)
|
||||||
|
{
|
||||||
|
int iUniqueVertices = 0, i=0;
|
||||||
|
int * piVertexIDs = NULL;
|
||||||
|
if(iNrVerticesIn<=0) return 0;
|
||||||
|
|
||||||
|
|
||||||
|
iUniqueVertices = 0;
|
||||||
|
piVertexIDs = (int *) malloc(sizeof(int)*iNrVerticesIn);
|
||||||
|
if(piVertexIDs!=NULL)
|
||||||
|
{
|
||||||
|
for(i=0; i<iNrVerticesIn; i++)
|
||||||
|
{
|
||||||
|
piRemapTable[i] = -1;
|
||||||
|
piVertexIDs[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
MergeVertsFast(&iUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
|
||||||
|
pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, 0, iNrVerticesIn-1, 0);
|
||||||
|
|
||||||
|
free(piVertexIDs);
|
||||||
|
|
||||||
|
// debug check
|
||||||
|
for(i=0; i<iUniqueVertices; i++)
|
||||||
|
assert(piRemapTable[i]>=0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return iUniqueVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void MergeVertsFast(int * piCurNrUniqueVertices, int * piRemapTable, float * pfVertexDataOut, int * piVertexIDs,
|
||||||
|
const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert,
|
||||||
|
const int iL_in, const int iR_in, const int iChannelNum)
|
||||||
|
{
|
||||||
|
const int iCount = iR_in-iL_in+1;
|
||||||
|
int l=0;
|
||||||
|
float fMin, fMax, fAvg;
|
||||||
|
assert(iCount>0);
|
||||||
|
// make bbox
|
||||||
|
fMin = pfVertexDataIn[ piVertexIDs[iL_in]*iFloatsPerVert + iChannelNum]; fMax = fMin;
|
||||||
|
for(l=(iL_in+1); l<=iR_in; l++)
|
||||||
|
{
|
||||||
|
const int index = piVertexIDs[l]*iFloatsPerVert + iChannelNum;
|
||||||
|
const float fVal = pfVertexDataIn[index];
|
||||||
|
if(fMin>fVal) fMin=fVal;
|
||||||
|
else if(fMax<fVal) fMax=fVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate recursion when the separation/average value
|
||||||
|
// is no longer strictly between fMin and fMax values.
|
||||||
|
fAvg = 0.5f*(fMax + fMin);
|
||||||
|
if(fAvg<=fMin || fAvg>=fMax || iCount==1)
|
||||||
|
{
|
||||||
|
if((iChannelNum+1) == iFloatsPerVert || iCount==1) // we are done, weld by hand
|
||||||
|
{
|
||||||
|
int iUniqueNewVertices = 0;
|
||||||
|
float * pfNewUniVertsOut = &pfVertexDataOut[ piCurNrUniqueVertices[0]*iFloatsPerVert ];
|
||||||
|
|
||||||
|
for(l=iL_in; l<=iR_in; l++)
|
||||||
|
{
|
||||||
|
const int index = piVertexIDs[l]*iFloatsPerVert;
|
||||||
|
|
||||||
|
int iFound = 0; // didn't find copy yet.
|
||||||
|
int l2=0;
|
||||||
|
while(l2<iUniqueNewVertices && iFound==0)
|
||||||
|
{
|
||||||
|
const int index2 = l2*iFloatsPerVert;
|
||||||
|
|
||||||
|
int iAllSame = 1;
|
||||||
|
int c=0;
|
||||||
|
while(iAllSame!=0 && c<iFloatsPerVert)
|
||||||
|
{
|
||||||
|
iAllSame &= (pfVertexDataIn[index+c] == pfNewUniVertsOut[index2+c] ? 1 : 0);
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
|
||||||
|
iFound = iAllSame;
|
||||||
|
if(iFound==0) ++l2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate new entry
|
||||||
|
if(iFound==0)
|
||||||
|
{
|
||||||
|
memcpy(pfNewUniVertsOut+iUniqueNewVertices*iFloatsPerVert, pfVertexDataIn+index, sizeof(float)*iFloatsPerVert);
|
||||||
|
++iUniqueNewVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(piRemapTable[piVertexIDs[l]] == -1); // has not yet been assigned
|
||||||
|
piRemapTable[piVertexIDs[l]] = piCurNrUniqueVertices[0] + l2;
|
||||||
|
}
|
||||||
|
|
||||||
|
piCurNrUniqueVertices[0] += iUniqueNewVertices;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
|
||||||
|
pfVertexDataIn, iNrVerticesIn, iFloatsPerVert,
|
||||||
|
iL_in, iR_in, iChannelNum+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int iL=iL_in, iR=iR_in, index;
|
||||||
|
|
||||||
|
// seperate (by fSep) all points between iL_in and iR_in in pTmpVert[]
|
||||||
|
while(iL < iR)
|
||||||
|
{
|
||||||
|
int iReadyLeftSwap = 0;
|
||||||
|
int iReadyRightSwap = 0;
|
||||||
|
while(iReadyLeftSwap==0 && iL<iR)
|
||||||
|
{
|
||||||
|
assert(iL>=iL_in && iL<=iR_in);
|
||||||
|
index = piVertexIDs[iL]*iFloatsPerVert+iChannelNum;
|
||||||
|
iReadyLeftSwap = !(pfVertexDataIn[index]<fAvg) ? 1 : 0;
|
||||||
|
if(iReadyLeftSwap==0) ++iL;
|
||||||
|
}
|
||||||
|
while(iReadyRightSwap==0 && iL<iR)
|
||||||
|
{
|
||||||
|
assert(iR>=iL_in && iR<=iR_in);
|
||||||
|
index = piVertexIDs[iR]*iFloatsPerVert+iChannelNum;
|
||||||
|
iReadyRightSwap = pfVertexDataIn[index]<fAvg ? 1 : 0;
|
||||||
|
if(iReadyRightSwap==0) --iR;
|
||||||
|
}
|
||||||
|
assert( (iL<iR) || (iReadyLeftSwap==0 || iReadyRightSwap==0));
|
||||||
|
|
||||||
|
if(iReadyLeftSwap!=0 && iReadyRightSwap!=0)
|
||||||
|
{
|
||||||
|
int iID=0;
|
||||||
|
assert(iL<iR);
|
||||||
|
iID = piVertexIDs[iL];
|
||||||
|
piVertexIDs[iL] = piVertexIDs[iR];
|
||||||
|
piVertexIDs[iR] = iID;
|
||||||
|
++iL; --iR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(iL==(iR+1) || (iL==iR));
|
||||||
|
if(iL==iR)
|
||||||
|
{
|
||||||
|
const int index = piVertexIDs[iR]*iFloatsPerVert+iChannelNum;
|
||||||
|
const int iReadyRightSwap = pfVertexDataIn[index]<fAvg ? 1 : 0;
|
||||||
|
if(iReadyRightSwap!=0) ++iL;
|
||||||
|
else --iR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
if(iL_in <= iR)
|
||||||
|
MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
|
||||||
|
pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, iL_in, iR, iChannelNum); // weld all left of fSep
|
||||||
|
if(iL <= iR_in)
|
||||||
|
MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
|
||||||
|
pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, iL, iR_in, iChannelNum); // weld all right of (or equal to) fSep
|
||||||
|
}
|
||||||
|
}
|
49
src/libs/weldmesh.h
Normal file
49
src/libs/weldmesh.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2011 by Morten S. Mikkelsen
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __WELDMESH_H__
|
||||||
|
#define __WELDMESH_H__
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// piRemapTable must be initialized and point to an area in memory
|
||||||
|
// with the byte size: iNrVerticesIn * sizeof(int).
|
||||||
|
// pfVertexDataOut must be initialized and point to an area in memory
|
||||||
|
// with the byte size: iNrVerticesIn * iFloatsPerVert * sizeof(float).
|
||||||
|
// At the end of the WeldMesh() call the array pfVertexDataOut will contain
|
||||||
|
// unique vertices only. Each entry in piRemapTable contains the index to
|
||||||
|
// the new location of the vertex in pfVertexDataOut in units of iFloatsPerVert.
|
||||||
|
// Note that this code is suitable for welding both unindexed meshes but also
|
||||||
|
// indexed meshes which need to have duplicates removed. In the latter case
|
||||||
|
// one simply uses the remap table to convert the old index list to the new vertex array.
|
||||||
|
// Finally, the return value is the number of unique vertices found.
|
||||||
|
int WeldMesh(int * piRemapTable, float * pfVertexDataOut,
|
||||||
|
const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -4,6 +4,7 @@
|
|||||||
#include "util/files.h"
|
#include "util/files.h"
|
||||||
|
|
||||||
#include "libs/mikktspace.h"
|
#include "libs/mikktspace.h"
|
||||||
|
#include "libs/weldmesh.h"
|
||||||
#include "libs/tiny_gltf.h"
|
#include "libs/tiny_gltf.h"
|
||||||
|
|
||||||
#include "components/mesh_renderable.h"
|
#include "components/mesh_renderable.h"
|
||||||
@ -160,6 +161,19 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
|||||||
|
|
||||||
/* load all materials found in model */
|
/* load all materials found in model */
|
||||||
|
|
||||||
|
// store some 1x1 colour textures as a hack to render solid colours
|
||||||
|
struct Color {
|
||||||
|
uint8_t r, g, b, a;
|
||||||
|
Color(const double* doubles)
|
||||||
|
{
|
||||||
|
r = static_cast<uint8_t>(lround(doubles[0] * 255.0));
|
||||||
|
g = static_cast<uint8_t>(lround(doubles[1] * 255.0));
|
||||||
|
b = static_cast<uint8_t>(lround(doubles[2] * 255.0));
|
||||||
|
a = static_cast<uint8_t>(lround(doubles[3] * 255.0));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//std::unordered_map<Color, std::shared_ptr<Texture>> colour_textures;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Material>> materials{};
|
std::vector<std::shared_ptr<Material>> materials{};
|
||||||
materials.reserve(model.materials.size());
|
materials.reserve(model.materials.size());
|
||||||
for (const tg::Material& material : model.materials) {
|
for (const tg::Material& material : model.materials) {
|
||||||
@ -182,11 +196,16 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
|||||||
}
|
}
|
||||||
const auto& baseColorFactor4 = material.pbrMetallicRoughness.baseColorFactor;
|
const auto& baseColorFactor4 = material.pbrMetallicRoughness.baseColorFactor;
|
||||||
if (baseColorFactor4[0] != 1.0 || baseColorFactor4[1] != 1.0 || baseColorFactor4[2] != 1.0 || baseColorFactor4[3] != 1.0) {
|
if (baseColorFactor4[0] != 1.0 || baseColorFactor4[1] != 1.0 || baseColorFactor4[2] != 1.0 || baseColorFactor4[3] != 1.0) {
|
||||||
LOG_WARN("Material {} contains a base color value which isn't supported yet.", material.name);
|
|
||||||
if (material.pbrMetallicRoughness.baseColorTexture.index == -1) {
|
if (material.pbrMetallicRoughness.baseColorTexture.index == -1) {
|
||||||
LOG_WARN("Material will be created with a white base color texture.");
|
LOG_INFO("Making color texture!");
|
||||||
|
throw std::runtime_error("TODO");
|
||||||
|
// convert double colors to integers
|
||||||
|
//Color col(baseColorFactor4.data());
|
||||||
|
//if (colour_textures.contains(col)) {
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
LOG_WARN("Material {} contains a base color multiplier which isn't supported yet.", material.name);
|
||||||
LOG_WARN("The material's base color texture will be used as-is.");
|
LOG_WARN("The material's base color texture will be used as-is.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,6 +262,8 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
|||||||
|
|
||||||
const size_t num_vertices = pos_accessor.count;
|
const size_t num_vertices = pos_accessor.count;
|
||||||
|
|
||||||
|
bool generate_tangents = false; // generating tangents creates a new index list and therefore all attribute accessors must be reassigned
|
||||||
|
|
||||||
// these checks are probably unneccesary assuming a valid glTF file
|
// these checks are probably unneccesary assuming a valid glTF file
|
||||||
// if (pos_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) throw std::runtime_error("Position att. must be float!");
|
// if (pos_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) throw std::runtime_error("Position att. must be float!");
|
||||||
// if (pos_accessor.type != 3) throw std::runtime_error("Position att. dim. must be 3!");
|
// if (pos_accessor.type != 3) throw std::runtime_error("Position att. dim. must be 3!");
|
||||||
@ -279,7 +300,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: use MikkTSpace to generate tangents
|
// TODO: use MikkTSpace to generate tangents
|
||||||
throw std::runtime_error(std::string("No tangents found in primitive from ") + mesh.name);
|
generate_tangents = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// UV0
|
// UV0
|
||||||
@ -326,13 +347,105 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
|||||||
throw std::runtime_error(std::string("Invalid index buffer in primtive from: ") + mesh.name);
|
throw std::runtime_error(std::string("Invalid index buffer in primtive from: ") + mesh.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// combine vertices into one array
|
|
||||||
std::vector<Vertex> vertices;
|
std::vector<Vertex> vertices;
|
||||||
|
|
||||||
|
if (generate_tangents) {
|
||||||
|
// generate tangents if they're not in the file
|
||||||
|
struct MeshData {
|
||||||
|
Attribute<glm::vec3>* positions;
|
||||||
|
Attribute<glm::vec3>* normals;
|
||||||
|
Attribute<glm::vec2>* uvs;
|
||||||
|
const uint32_t* indices;
|
||||||
|
size_t num_indices;
|
||||||
|
std::vector<Vertex>* new_vertices;
|
||||||
|
};
|
||||||
|
|
||||||
|
MeshData meshData{};
|
||||||
|
meshData.positions = &positions;
|
||||||
|
meshData.normals = &normals;
|
||||||
|
meshData.uvs = &uv0s;
|
||||||
|
meshData.indices = indices.data();
|
||||||
|
meshData.num_indices = num_indices;
|
||||||
|
meshData.new_vertices = &vertices;
|
||||||
|
vertices.resize(num_indices);
|
||||||
|
|
||||||
|
SMikkTSpaceInterface mts_interface{};
|
||||||
|
mts_interface.m_getNumFaces = [](const SMikkTSpaceContext* pContext) -> int {
|
||||||
|
const MeshData* meshData = static_cast<const MeshData*>(pContext->m_pUserData);
|
||||||
|
assert(meshData->num_indices % 3 == 0);
|
||||||
|
return meshData->num_indices / 3;
|
||||||
|
};
|
||||||
|
mts_interface.m_getNumVerticesOfFace = [](const SMikkTSpaceContext*, const int) -> int { return 3; };
|
||||||
|
mts_interface.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) -> void {
|
||||||
|
const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData);
|
||||||
|
const size_t i = iFace * 3 + iVert;
|
||||||
|
assert(i < meshData->num_indices);
|
||||||
|
const size_t vertex_index = meshData->indices[i];
|
||||||
|
const glm::vec3 pos = meshData->positions->operator[](vertex_index);
|
||||||
|
fvPosOut[0] = pos.x;
|
||||||
|
fvPosOut[1] = pos.y;
|
||||||
|
fvPosOut[2] = pos.z;
|
||||||
|
};
|
||||||
|
mts_interface.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) -> void {
|
||||||
|
const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData);
|
||||||
|
const size_t i = iFace * 3 + iVert;
|
||||||
|
assert(i < meshData->num_indices);
|
||||||
|
const size_t vertex_index = meshData->indices[i];
|
||||||
|
const glm::vec3 norm = meshData->normals->operator[](vertex_index);
|
||||||
|
fvNormOut[0] = norm.x;
|
||||||
|
fvNormOut[1] = norm.y;
|
||||||
|
fvNormOut[2] = norm.z;
|
||||||
|
};
|
||||||
|
mts_interface.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) -> void {
|
||||||
|
const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData);
|
||||||
|
const size_t i = iFace * 3 + iVert;
|
||||||
|
assert(i < meshData->num_indices);
|
||||||
|
const size_t vertex_index = meshData->indices[i];
|
||||||
|
const glm::vec2 uv = meshData->uvs->operator[](vertex_index);
|
||||||
|
fvTexcOut[0] = uv.x;
|
||||||
|
fvTexcOut[1] = uv.y;
|
||||||
|
};
|
||||||
|
mts_interface.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace,
|
||||||
|
const int iVert) -> void {
|
||||||
|
MeshData* const meshData = static_cast<MeshData*>(pContext->m_pUserData);
|
||||||
|
const size_t i = iFace * 3 + iVert;
|
||||||
|
assert(i < meshData->num_indices);
|
||||||
|
const size_t vertex_index = meshData->indices[i];
|
||||||
|
|
||||||
|
Vertex& new_v = meshData->new_vertices->operator[](i);
|
||||||
|
|
||||||
|
new_v.pos = meshData->positions->operator[](vertex_index);
|
||||||
|
new_v.norm = meshData->normals->operator[](vertex_index);
|
||||||
|
new_v.uv = meshData->uvs->operator[](vertex_index);
|
||||||
|
new_v.tangent.x = fvTangent[0];
|
||||||
|
new_v.tangent.y = fvTangent[1];
|
||||||
|
new_v.tangent.z = fvTangent[2];
|
||||||
|
new_v.tangent.w = fSign;
|
||||||
|
};
|
||||||
|
SMikkTSpaceContext mts_context{};
|
||||||
|
mts_context.m_pInterface = &mts_interface;
|
||||||
|
mts_context.m_pUserData = &meshData;
|
||||||
|
|
||||||
|
bool tan_result = genTangSpaceDefault(&mts_context);
|
||||||
|
if (tan_result == false) throw std::runtime_error("Failed to generate tangents!");
|
||||||
|
|
||||||
|
// regenerate indices as simple ones
|
||||||
|
indices.clear();
|
||||||
|
indices.reserve(meshData.new_vertices->size());
|
||||||
|
// temp generate simple indices
|
||||||
|
for (uint32_t i = 0; i < meshData.new_vertices->size(); ++i) {
|
||||||
|
indices.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// combine vertices into one array
|
||||||
|
vertices.clear();
|
||||||
vertices.reserve(num_vertices);
|
vertices.reserve(num_vertices);
|
||||||
for (size_t i = 0; i < num_vertices; ++i) {
|
for (size_t i = 0; i < num_vertices; ++i) {
|
||||||
Vertex v{.pos = positions[i], .norm = normals[i], .tangent = tangents[i], .uv = uv0s[i]};
|
Vertex v{.pos = positions[i], .norm = normals[i], .tangent = tangents[i], .uv = uv0s[i]};
|
||||||
vertices.push_back(v);
|
vertices.push_back(v);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// generate mesh on GPU
|
// generate mesh on GPU
|
||||||
std::shared_ptr<Mesh> engine_mesh = std::make_shared<Mesh>(scene.app()->renderer()->GetDevice(), vertices, indices);
|
std::shared_ptr<Mesh> engine_mesh = std::make_shared<Mesh>(scene.app()->renderer()->GetDevice(), vertices, indices);
|
||||||
@ -355,9 +468,12 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// glTF uses the Y-up convention so objects must be rotated to Z-up
|
/* now create the entities and traverse the glTF scene hierarchy */
|
||||||
const Entity parent =
|
const std::filesystem::path filePath(path);
|
||||||
scene.CreateEntity("test_node", 0, glm::vec3{}, glm::quat{glm::one_over_root_two<float>(), glm::one_over_root_two<float>(), 0.0f, 0.0f});
|
const std::string name = filePath.stem().string();
|
||||||
|
|
||||||
|
// glTF uses the Y-up convention so the parent object must be rotated to Z-up
|
||||||
|
const Entity parent = scene.CreateEntity(name, 0, glm::vec3{}, glm::quat{glm::one_over_root_two<float>(), glm::one_over_root_two<float>(), 0.0f, 0.0f});
|
||||||
|
|
||||||
std::vector<Entity> entities(model.nodes.size(), 0);
|
std::vector<Entity> entities(model.nodes.size(), 0);
|
||||||
std::function<void(Entity, const tg::Node&)> generateEntities = [&](Entity parent_entity, const tg::Node& node) -> void {
|
std::function<void(Entity, const tg::Node&)> generateEntities = [&](Entity parent_entity, const tg::Node& node) -> void {
|
||||||
|
Binary file not shown.
@ -50,7 +50,7 @@ void PlayGame(GameSettings settings)
|
|||||||
graphics_settings.vsync = true;
|
graphics_settings.vsync = true;
|
||||||
graphics_settings.wait_for_present = false;
|
graphics_settings.wait_for_present = false;
|
||||||
graphics_settings.msaa_level = engine::gfx::MSAALevel::kOff;
|
graphics_settings.msaa_level = engine::gfx::MSAALevel::kOff;
|
||||||
graphics_settings.enable_anisotropy = false;
|
graphics_settings.enable_anisotropy = true;
|
||||||
|
|
||||||
engine::Application::Configuration configuration{};
|
engine::Application::Configuration configuration{};
|
||||||
configuration.enable_frame_limiter = settings.enable_frame_limiter;
|
configuration.enable_frame_limiter = settings.enable_frame_limiter;
|
||||||
@ -167,7 +167,8 @@ void PlayGame(GameSettings settings)
|
|||||||
scene2->AddComponent<CameraControllerComponent>(camera);
|
scene2->AddComponent<CameraControllerComponent>(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ /* axes */
|
{
|
||||||
|
/* axes */
|
||||||
// engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true);
|
// engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ void PlayGame(GameSettings settings)
|
|||||||
|
|
||||||
engine::Entity pivot = scene2->CreateEntity("pivot", 0, glm::vec3{0.0f, 0.0f, 0.0f});
|
engine::Entity pivot = scene2->CreateEntity("pivot", 0, glm::vec3{0.0f, 0.0f, 0.0f});
|
||||||
|
|
||||||
engine::Entity wall2 = scene2->CreateEntity("wall2", pivot, glm::vec3{-50.0f, -50.0f, 0.0f});
|
engine::Entity wall2 = scene2->CreateEntity("floor", pivot, glm::vec3{-50.0f, -50.0f, 0.0f});
|
||||||
auto wall_renderable = scene2->AddComponent<engine::MeshRenderableComponent>(wall2);
|
auto wall_renderable = scene2->AddComponent<engine::MeshRenderableComponent>(wall2);
|
||||||
wall_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 100.0f, 100.0f, 0.1f, 100.0f);
|
wall_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 100.0f, 100.0f, 0.1f, 100.0f);
|
||||||
wall_renderable->material = std::make_unique<engine::Material>(app.renderer(), app.GetResource<engine::Shader>("builtin.fancy"));
|
wall_renderable->material = std::make_unique<engine::Material>(app.renderer(), app.GetResource<engine::Shader>("builtin.fancy"));
|
||||||
@ -197,14 +198,19 @@ void PlayGame(GameSettings settings)
|
|||||||
wall_renderable->material->SetAlbedoTexture(app.GetResource<engine::Texture>("builtin.white"));
|
wall_renderable->material->SetAlbedoTexture(app.GetResource<engine::Texture>("builtin.white"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto teapot = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot_with_tangents.glb"));
|
//auto teapot = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot_with_tangents.glb"));
|
||||||
scene2->GetComponent<engine::TransformComponent>(teapot)->scale *= 10.0f;
|
//scene2->GetComponent<engine::TransformComponent>(teapot)->scale *= 10.0f;
|
||||||
//auto teapot2 = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot.glb"));
|
auto teapot2 = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot.glb"));
|
||||||
//scene2->GetComponent<engine::TransformComponent>(teapot2)->scale *= 10.0f;
|
scene2->GetComponent<engine::TransformComponent>(teapot2)->scale *= 10.0f;
|
||||||
//scene2->GetComponent<engine::TransformComponent>(teapot2)->position.y += 5.0f;
|
scene2->GetComponent<engine::TransformComponent>(teapot2)->position.y += 5.0f;
|
||||||
|
auto custom = scene2->AddComponent<engine::CustomComponent>(teapot2);
|
||||||
|
custom->onInit = [](void) { return; };
|
||||||
|
custom->onUpdate = [&](float dt) {
|
||||||
|
scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation *= glm::angleAxis(dt, glm::vec3{0.0f, 1.0f, 0.0f});
|
||||||
|
};
|
||||||
// scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation = glm::angleAxis(glm::pi<float>(), glm::vec3{ 0.0f, 0.0f, 1.0f });
|
// scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation = glm::angleAxis(glm::pi<float>(), glm::vec3{ 0.0f, 0.0f, 1.0f });
|
||||||
// scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation *= glm::angleAxis(glm::half_pi<float>(), glm::vec3{1.0f, 0.0f, 0.0f});
|
// scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation *= glm::angleAxis(glm::half_pi<float>(), glm::vec3{1.0f, 0.0f, 0.0f});
|
||||||
auto walls = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/walls_with_tangents.glb"));
|
// auto walls = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/walls_with_tangents.glb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
my_scene->GetSystem<CameraControllerSystem>()->next_scene_ = scene2;
|
my_scene->GetSystem<CameraControllerSystem>()->next_scene_ = scene2;
|
||||||
|
Loading…
Reference in New Issue
Block a user