mirror of
https://github.com/Relintai/godot-lportal.git
synced 2024-11-11 10:52:09 +01:00
External lightmap workflow working
This commit is contained in:
parent
b6cbce0621
commit
2a7933879c
447
ldae_exporter.cpp
Normal file
447
ldae_exporter.cpp
Normal file
@ -0,0 +1,447 @@
|
||||
#include "ldae_exporter.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "scene/3d/light.h"
|
||||
#include "ldebug.h"
|
||||
#include "lportal.h"
|
||||
|
||||
#define FSL(a) m_File.store_line(a)
|
||||
#define FSS(a) m_File.store_string(a)
|
||||
|
||||
#define FSL_T(a, b) {for (int n=0; n<a; n++) {FSS("\t");}\
|
||||
FSL(b);}
|
||||
|
||||
#define FSS_T(a, b) {for (int n=0; n<a; n++) {FSS("\t");}\
|
||||
FSS(b);}
|
||||
|
||||
|
||||
LDAEExporter::LDAEExporter()
|
||||
{
|
||||
m_pMergedMI = 0;
|
||||
m_bAddRootNode = true;
|
||||
m_Stage = ST_DATA;
|
||||
m_bRemovePortals = true;
|
||||
}
|
||||
|
||||
|
||||
bool LDAEExporter::SaveScene(Node * pNode, String szFilename, bool bRemovePortals)
|
||||
{
|
||||
m_bAddRootNode = true;
|
||||
m_bRemovePortals = bRemovePortals;
|
||||
|
||||
// open the output file
|
||||
Error err = m_File.open(szFilename, _File::WRITE);
|
||||
if (err != OK)
|
||||
return false;
|
||||
|
||||
Save_Preamble();
|
||||
|
||||
m_Stage = ST_DATA;
|
||||
|
||||
// initially find all the meshes, lights etc
|
||||
SaveScene_Recursive(pNode, 0);
|
||||
|
||||
// lights
|
||||
FSL("\t<library_lights>");
|
||||
for (int n=0; n<m_Lights.size(); n++)
|
||||
SaveData_Light(*m_Lights[n]);
|
||||
FSL("\t</library_lights>");
|
||||
|
||||
// mesh instances
|
||||
FSL("\t<library_geometries>");
|
||||
|
||||
// merged mesh?
|
||||
if (m_pMergedMI)
|
||||
SaveData_MeshInstance(*m_pMergedMI);
|
||||
|
||||
for (int n=0; n<m_MeshInstances.size(); n++)
|
||||
SaveData_MeshInstance(*m_MeshInstances[n]);
|
||||
FSL("\t</library_geometries>");
|
||||
|
||||
m_Stage = ST_SCENE_GRAPH;
|
||||
Save_Mid();
|
||||
|
||||
// now save the scene graph
|
||||
SaveScene_Recursive(pNode, 0);
|
||||
|
||||
Save_Final();
|
||||
|
||||
m_File.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LDAEExporter::Save_Preamble()
|
||||
{
|
||||
FSL("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
FSL("<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LDAEExporter::Save_Mid()
|
||||
{
|
||||
FSL("\t<library_visual_scenes>");
|
||||
FSL("\t\t<visual_scene id=\"Scene\" name=\"Scene\">");
|
||||
|
||||
if (m_bAddRootNode)
|
||||
{
|
||||
FSL_T(3, "<node id=\"l_root\" name=\"l_root\" type=\"NODE\">");
|
||||
|
||||
// rotate x by 90 degrees
|
||||
FSL_T(3, "<matrix sid=\"transform\">1 0 0 0 0 0 -1 0 0 1 0 0 0 0 0 1</matrix>");
|
||||
}
|
||||
|
||||
if (m_pMergedMI)
|
||||
{
|
||||
String sz = SaveScene_MeshInstance(*m_pMergedMI, 3);
|
||||
FSL(sz); // merged node close </node>
|
||||
|
||||
FSL_T(3, "<node id=\"l_level\" name=\"l_level\" type=\"NODE\">");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LDAEExporter::TransformToMatrix(const Transform &tr, float * m)
|
||||
{
|
||||
const Basis &b = tr.basis;
|
||||
|
||||
m[0] = b.elements[0][0];
|
||||
m[1] = b.elements[0][1];
|
||||
m[2] = b.elements[0][2];
|
||||
m[3] = tr.origin.x;
|
||||
|
||||
m[4] = b.elements[1][0];
|
||||
m[5] = b.elements[1][1];
|
||||
m[6] = b.elements[1][2];
|
||||
m[7] = tr.origin.y;
|
||||
|
||||
m[8] = b.elements[2][0];
|
||||
m[9] = b.elements[2][1];
|
||||
m[10] = b.elements[2][2];
|
||||
m[11] = tr.origin.z;
|
||||
|
||||
m[12] = 0.0f;
|
||||
m[13] = 0.0f;
|
||||
m[14] = 0.0f;
|
||||
m[15] = 1.0f;
|
||||
}
|
||||
|
||||
String LDAEExporter::SaveScene_Light(const Light &l, int depth)
|
||||
{
|
||||
int tab_depth = 3 + depth;
|
||||
|
||||
String name = l.get_name();
|
||||
String long_name = name + "-light";
|
||||
FSL_T(tab_depth, "<node id=\"" + name + "\" name=\"" + name + "\" type=\"NODE\">");
|
||||
|
||||
WriteMatrix(l.get_transform(), tab_depth+1);
|
||||
|
||||
FSL_T(tab_depth+1, "<instance_light url=\"#" + long_name + "\" />");
|
||||
|
||||
String sz = "";
|
||||
for (int n=0; n<tab_depth; n++)
|
||||
sz += "\t";
|
||||
sz += "</node>";
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
void LDAEExporter::WriteMatrix(const Transform &tr, int tab_depth)
|
||||
{
|
||||
float mat[16];
|
||||
TransformToMatrix(tr, mat);
|
||||
|
||||
FSS_T(tab_depth, "<matrix sid=\"transform\">");
|
||||
|
||||
for (int n=0; n<16; n++)
|
||||
{
|
||||
FSS(ftos(mat[n]) + " ");
|
||||
}
|
||||
|
||||
FSS("</matrix>\n");
|
||||
}
|
||||
|
||||
|
||||
String LDAEExporter::SaveScene_MeshInstance(const MeshInstance &mi, int depth)
|
||||
{
|
||||
int tab_depth = 3 + depth;
|
||||
|
||||
String name = mi.get_name();
|
||||
String long_name = name + "-mesh";
|
||||
FSL_T(tab_depth, "<node id=\"" + name + "\" name=\"" + name + "\" type=\"NODE\">");
|
||||
|
||||
|
||||
WriteMatrix(mi.get_transform(), tab_depth+1);
|
||||
|
||||
FSL_T(tab_depth+1, "<instance_geometry url=\"#" + long_name + "\" name=\"" + name + "\">");
|
||||
FSL_T(tab_depth+1, "</instance_geometry>");
|
||||
|
||||
String sz = "";
|
||||
for (int n=0; n<tab_depth; n++)
|
||||
sz += "\t";
|
||||
sz += "</node>";
|
||||
// FSL_T(tab_depth, "</node>");
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
String LDAEExporter::SaveScene_Spatial(const Spatial &sp, int depth)
|
||||
{
|
||||
int tab_depth = 3 + depth;
|
||||
String name = sp.get_name();
|
||||
|
||||
FSL_T(tab_depth, "<node id=\"" + name + "\" name=\"" + name + "\" type=\"NODE\">");
|
||||
|
||||
WriteMatrix(sp.get_transform(), tab_depth+1);
|
||||
|
||||
String sz = "";
|
||||
for (int n=0; n<tab_depth; n++)
|
||||
sz += "\t";
|
||||
sz += "</node>";
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
bool LDAEExporter::Save_Final()
|
||||
{
|
||||
if (m_pMergedMI)
|
||||
{
|
||||
FSL_T(3, "</node>"); // level
|
||||
}
|
||||
|
||||
if (m_bAddRootNode)
|
||||
{
|
||||
FSL_T(3, "</node>"); // root
|
||||
}
|
||||
|
||||
FSL("\t\t</visual_scene>");
|
||||
FSL("\t</library_visual_scenes>");
|
||||
FSL("\t<scene>");
|
||||
FSL("\t\t<instance_visual_scene url=\"#Scene\"/>");
|
||||
FSL("\t</scene>");
|
||||
|
||||
|
||||
FSL("</COLLADA>");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LDAEExporter::IsPortal(const MeshInstance &mi)
|
||||
{
|
||||
if (LPortal::NameStartsWith(&mi, "portal_"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LDAEExporter::SaveScene_Recursive(Node * pNode, int depth)
|
||||
{
|
||||
String szClose = "";
|
||||
|
||||
// mesh instance?
|
||||
MeshInstance * pMI = Object::cast_to<MeshInstance>(pNode);
|
||||
if (pMI)
|
||||
{
|
||||
if (m_bRemovePortals && (IsPortal(*pMI)))
|
||||
{
|
||||
// portal .. not exporting
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Stage == ST_DATA)
|
||||
m_MeshInstances.push_back(pMI);
|
||||
else
|
||||
szClose = SaveScene_MeshInstance(*pMI, depth);
|
||||
}
|
||||
}
|
||||
|
||||
// light?
|
||||
Light * pLight = Object::cast_to<Light>(pNode);
|
||||
if (pLight)
|
||||
{
|
||||
if (m_Stage == ST_DATA)
|
||||
m_Lights.push_back(pLight);
|
||||
else
|
||||
szClose = SaveScene_Light(*pLight, depth);
|
||||
}
|
||||
|
||||
// spatial? (and only a spatial)
|
||||
if (pNode->get_class() == "Spatial")
|
||||
{
|
||||
if (m_Stage == ST_SCENE_GRAPH)
|
||||
{
|
||||
szClose = SaveScene_Spatial(*Object::cast_to<Spatial>(pNode), depth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// go through the children
|
||||
for (int n=0; n<pNode->get_child_count(); n++)
|
||||
{
|
||||
SaveScene_Recursive(pNode->get_child(n), depth+1);
|
||||
}
|
||||
|
||||
// a closing xml expression
|
||||
if (szClose != "")
|
||||
{
|
||||
FSL(szClose);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool LDAEExporter::SaveData_Light(const Light &light)
|
||||
{
|
||||
String name = light.get_name();
|
||||
String long_name = name + "-light";
|
||||
|
||||
int t = 1;
|
||||
|
||||
String szLightType = "point";
|
||||
//if (light.is_class("OmniLight")
|
||||
|
||||
if (light.is_class("SpotLight"))
|
||||
szLightType = "spot";
|
||||
|
||||
if (light.is_class("DirectionalLight"))
|
||||
szLightType = "directional";
|
||||
|
||||
FSL_T(t, "<light id=\"" + long_name + "\" name=\"" + name + "\">");
|
||||
FSL_T(t+1, "<technique_common>");
|
||||
FSL_T(t+2, "<" + szLightType + ">");
|
||||
|
||||
|
||||
|
||||
FSL_T(t+2, "</" + szLightType + ">");
|
||||
FSL_T(t+1, "</technique_common>");
|
||||
FSL_T(t, "</light>");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//static bool g_SingleDAETest = false;
|
||||
|
||||
|
||||
bool LDAEExporter::SaveData_MeshInstance(const MeshInstance &mi)
|
||||
{
|
||||
// if (g_SingleDAETest)
|
||||
// return true;
|
||||
// g_SingleDAETest = true;
|
||||
|
||||
Ref<Mesh> rmesh = mi.get_mesh();
|
||||
Array arrays = rmesh->surface_get_arrays(0);
|
||||
PoolVector<Vector3> verts = arrays[VS::ARRAY_VERTEX];
|
||||
PoolVector<Vector3> norms = arrays[VS::ARRAY_NORMAL];
|
||||
PoolVector<Vector2> uv1s = arrays[VS::ARRAY_TEX_UV];
|
||||
PoolVector<int> inds = arrays[VS::ARRAY_INDEX];
|
||||
|
||||
int nVerts = verts.size();
|
||||
int nInds = inds.size();
|
||||
int nFaces = nInds / 3;
|
||||
|
||||
String name = mi.get_name();
|
||||
String long_name = name + "-mesh";
|
||||
|
||||
|
||||
FSL("\t<geometry id=\"" + long_name + "\" name=\"" + name + "\">");
|
||||
FSL("\t\t<mesh>");
|
||||
|
||||
// positions
|
||||
FSL("\t\t\t<source id=\"" + long_name + "-positions\">");
|
||||
|
||||
FSS("\t\t\t\t<float_array id=\"" + long_name + "-positions-array\" count=\"");
|
||||
FSS(itos(nVerts*3) + "\">");
|
||||
for (int n=0; n<nVerts; n++)
|
||||
{
|
||||
Vector3 pos = verts[n];
|
||||
|
||||
FSS(ftos(pos.x) + " " + ftos(pos.y) + " " + ftos(pos.z) + " ");
|
||||
}
|
||||
FSS("</float_array>\n");
|
||||
|
||||
FSL("\t\t\t\t<technique_common>");
|
||||
FSL("\t\t\t\t\t<accessor source=\"#" + long_name + "-positions-array\" count=\""
|
||||
+ itos(nVerts) + "\" stride=\"3\">");
|
||||
FSL("\t\t\t\t\t\t<param name=\"X\" type=\"float\" />");
|
||||
FSL("\t\t\t\t\t\t<param name=\"Y\" type=\"float\" />");
|
||||
FSL("\t\t\t\t\t\t<param name=\"Z\" type=\"float\" />");
|
||||
|
||||
FSL("\t\t\t\t\t</accessor>");
|
||||
FSL("\t\t\t\t</technique_common>");
|
||||
|
||||
FSL("\t\t\t</source>");
|
||||
|
||||
// normals
|
||||
if (norms.size())
|
||||
{
|
||||
FSL("\t\t\t<source id=\"" + long_name + "-normals\">");
|
||||
|
||||
FSS("\t\t\t\t<float_array id=\"" + long_name + "-normals-array\" count=\"");
|
||||
FSS(itos(nVerts*3) + "\">");
|
||||
for (int n=0; n<nVerts; n++)
|
||||
{
|
||||
Vector3 norm = norms[n];
|
||||
|
||||
FSS(ftos(norm.x) + " " + ftos(norm.y) + " " + ftos(norm.z) + " ");
|
||||
}
|
||||
FSS("</float_array>\n");
|
||||
|
||||
FSL("\t\t\t\t<technique_common>");
|
||||
FSL("\t\t\t\t\t<accessor source=\"#" + long_name + "-normals-array\" count=\""
|
||||
+ itos(nVerts) + "\" stride=\"3\">");
|
||||
FSL("\t\t\t\t\t\t<param name=\"X\" type=\"float\" />");
|
||||
FSL("\t\t\t\t\t\t<param name=\"Y\" type=\"float\" />");
|
||||
FSL("\t\t\t\t\t\t<param name=\"Z\" type=\"float\" />");
|
||||
|
||||
FSL("\t\t\t\t\t</accessor>");
|
||||
FSL("\t\t\t\t</technique_common>");
|
||||
|
||||
FSL("\t\t\t</source>");
|
||||
}
|
||||
|
||||
FSL("\t\t\t<vertices id=\"" + long_name + "-vertices\">");
|
||||
FSL("\t\t\t\t<input semantic=\"POSITION\" source=\"#" + long_name + "-positions\" />");
|
||||
FSL("\t\t\t</vertices>");
|
||||
|
||||
FSL("\t\t\t<triangles count=\"" + itos(nFaces) + "\">");
|
||||
FSL("\t\t\t\t<input semantic=\"VERTEX\" source=\"#" + long_name + "-vertices\" offset=\"0\"/>");
|
||||
if (norms.size())
|
||||
{
|
||||
FSL("\t\t\t\t<input semantic=\"NORMAL\" source=\"#" + long_name + "-normals\" offset=\"1\"/>");
|
||||
}
|
||||
|
||||
FSS("\t\t\t\t<p>");
|
||||
|
||||
// DAE has face winding reversed compared to godot
|
||||
for (int f=0; f<nFaces; f++)
|
||||
// for (int n=0; n<nInds; n++)
|
||||
{
|
||||
int base = f * 3;
|
||||
|
||||
// one index for position, one for normal
|
||||
FSS(itos(inds[base+2]) + " ");
|
||||
FSS(itos(inds[base+2]) + " ");
|
||||
FSS(itos(inds[base+1]) + " ");
|
||||
FSS(itos(inds[base+1]) + " ");
|
||||
FSS(itos(inds[base+0]) + " ");
|
||||
FSS(itos(inds[base+0]) + " ");
|
||||
}
|
||||
FSS("</p>\n");
|
||||
|
||||
FSL("\t\t\t</triangles>");
|
||||
|
||||
FSL("\t\t</mesh>");
|
||||
FSL("\t</geometry>");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#undef FSL
|
||||
#undef FSS
|
||||
|
59
ldae_exporter.h
Normal file
59
ldae_exporter.h
Normal file
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/bind/core_bind.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
|
||||
class Light;
|
||||
|
||||
class LDAEExporter
|
||||
{
|
||||
enum eStage
|
||||
{
|
||||
ST_DATA,
|
||||
ST_SCENE_GRAPH,
|
||||
};
|
||||
|
||||
public:
|
||||
LDAEExporter();
|
||||
bool SaveScene(Node * pNode, String szFilename, bool bRemovePortals = false);
|
||||
void SetMergedMeshInstance(MeshInstance * pMI) {m_pMergedMI = pMI;}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool SaveScene_Recursive(Node * pNode, int depth);
|
||||
|
||||
|
||||
|
||||
String SaveScene_MeshInstance(const MeshInstance &mi, int depth);
|
||||
String SaveScene_Light(const Light &l, int depth);
|
||||
String SaveScene_Spatial(const Spatial &sp, int depth);
|
||||
|
||||
bool SaveData_Light(const Light &light);
|
||||
bool SaveData_MeshInstance(const MeshInstance &mi);
|
||||
|
||||
|
||||
bool Save_Preamble();
|
||||
bool Save_Mid();
|
||||
bool Save_Final();
|
||||
|
||||
void WriteMatrix(const Transform &tr, int tab_depth);
|
||||
void TransformToMatrix(const Transform &tr, float * m);
|
||||
|
||||
bool IsPortal(const MeshInstance &mi);
|
||||
|
||||
Vector<const MeshInstance *> m_MeshInstances;
|
||||
Vector<const Light *> m_Lights;
|
||||
|
||||
_File m_File;
|
||||
eStage m_Stage;
|
||||
|
||||
// export the DAE with everything under a root node .. this is sometimes more convenient
|
||||
bool m_bAddRootNode;
|
||||
|
||||
// remove portals
|
||||
bool m_bRemovePortals;
|
||||
|
||||
// if we are exporting the level with a merged mesh too
|
||||
MeshInstance * m_pMergedMI;
|
||||
};
|
156
lhelper.cpp
156
lhelper.cpp
@ -7,6 +7,11 @@
|
||||
// for ::free
|
||||
#include <stdlib.h>
|
||||
|
||||
LHelper::LHelper()
|
||||
{
|
||||
SetUnMergeParams(0.1f, 0.95f);
|
||||
}
|
||||
|
||||
|
||||
String LHelper::LFace::ToString() const
|
||||
{
|
||||
@ -97,9 +102,16 @@ bool LHelper::FillMergedFromMesh(LMerged &merged, const MeshInstance &mesh)
|
||||
|
||||
if (merged.m_UV2s.size() == 0)
|
||||
{
|
||||
LWARN(5, "Merged mesh has no secondary UVs");
|
||||
LPRINT(5, "Merged mesh has no secondary UVs, using primary UVs");
|
||||
|
||||
merged.m_UV2s = arrays[VS::ARRAY_TEX_UV];
|
||||
|
||||
if (merged.m_UV2s.size() == 0)
|
||||
{
|
||||
LWARN(5, "Merged mesh has no UVs");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int miCount = 0;
|
||||
for (int mf=0; mf<merged.m_nFaces; mf++)
|
||||
@ -120,6 +132,13 @@ bool LHelper::FillMergedFromMesh(LMerged &merged, const MeshInstance &mesh)
|
||||
}
|
||||
|
||||
|
||||
void LHelper::SetUnMergeParams(float thresh_dist, float thresh_dot)
|
||||
{
|
||||
m_MergeParams.m_fThresholdDist = thresh_dist;
|
||||
m_MergeParams.m_fThresholdDist_Squared = thresh_dist * thresh_dist;
|
||||
m_MergeParams.m_fThresholdDot = thresh_dot;
|
||||
}
|
||||
|
||||
// take the UV2 coords from the merged mesh and attach these to the SOB meshes
|
||||
bool LHelper::UnMergeSOBs(LRoomManager &manager, MeshInstance * pMerged)
|
||||
{
|
||||
@ -134,8 +153,13 @@ bool LHelper::UnMergeSOBs(LRoomManager &manager, MeshInstance * pMerged)
|
||||
return false;
|
||||
|
||||
// go through each sob mesh
|
||||
// for (int n=1; n<2; n++)
|
||||
for (int n=0; n<manager.m_SOBs.size(); n++)
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
LPRINT(5, "Unmerge SOB " + itos(n));
|
||||
#endif
|
||||
|
||||
LSob &sob = manager.m_SOBs[n];
|
||||
GeometryInstance * pGI = sob.GetGI();
|
||||
if (!pGI)
|
||||
@ -182,71 +206,120 @@ unsigned int LHelper::FindMatchingVertex(const PoolVector<Vector2> &uvs, const V
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool LHelper::DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1) const
|
||||
bool LHelper::DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1, bool bDebug) const
|
||||
{
|
||||
return DoPosNormsApproxMatch(sob_f.m_Pos[c0], sob_f.m_Norm[c0], m_face.m_Pos[c1], m_face.m_Norm[c1]);
|
||||
return DoPosNormsApproxMatch(sob_f.m_Pos[c0], sob_f.m_Norm[c0], m_face.m_Pos[c1], m_face.m_Norm[c1], bDebug);
|
||||
}
|
||||
|
||||
bool LHelper::DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm) const
|
||||
bool LHelper::DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm, bool bDebug) const
|
||||
{
|
||||
bDebug = false;
|
||||
|
||||
float thresh_diff = m_MergeParams.m_fThresholdDist;
|
||||
float thresh_diff_squared = m_MergeParams.m_fThresholdDist_Squared;
|
||||
|
||||
float x_diff = fabs (b_pos.x - a_pos.x);
|
||||
if (x_diff > 0.2f)
|
||||
if (x_diff > thresh_diff)
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
if (bDebug)
|
||||
LPRINT(5, "\t\t\t\tRejecting x_diff " + ftos(x_diff));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
float z_diff = fabs (b_pos.z - a_pos.z);
|
||||
if (z_diff > thresh_diff)
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
if (bDebug)
|
||||
LPRINT(5, "\t\t\t\tRejecting z_diff " + ftos(z_diff));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
float y_diff = fabs (b_pos.y - a_pos.y);
|
||||
if (y_diff > thresh_diff)
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
if (bDebug)
|
||||
LPRINT(5, "\t\t\t\tRejecting y_diff " + ftos(y_diff));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3 pos_diff = b_pos - a_pos;
|
||||
if (pos_diff.length_squared() > 0.1f)
|
||||
if (pos_diff.length_squared() > thresh_diff_squared) // 0.1
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
if (bDebug)
|
||||
LPRINT(5, "\t\t\t\tRejecting length squared " + ftos(pos_diff.length_squared()));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure both are normalized
|
||||
Vector3 na = a_norm;//.normalized();
|
||||
Vector3 nb = b_norm;//.normalized();
|
||||
|
||||
float norm_dot = na.dot(nb);
|
||||
if (norm_dot < 0.95f)
|
||||
if (norm_dot < m_MergeParams.m_fThresholdDot)
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
if (bDebug)
|
||||
LPRINT(5, "\t\t\t\tRejecting normal " + ftos(norm_dot) + " na : " + String(na) + ", nb : " + String(nb));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int LHelper::DoFacesMatch_Offset(const LFace& sob_f, const LFace &m_face, int offset) const
|
||||
{
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
// debug
|
||||
String sz = "\t\tPOSS match sob : ";
|
||||
sz += sob_f.ToString();
|
||||
sz += "\n\t\t\tmerged : ";
|
||||
sz += m_face.ToString();
|
||||
LPRINT(2, sz);
|
||||
#endif
|
||||
|
||||
|
||||
// does 2nd and third match?
|
||||
int offset1 = (offset + 1) % 3;
|
||||
if (!DoFaceVertsApproxMatch(sob_f, m_face, 1, offset1, true))
|
||||
return -1;
|
||||
|
||||
int offset2 = (offset + 2) % 3;
|
||||
if (!DoFaceVertsApproxMatch(sob_f, m_face, 2, offset2, true))
|
||||
return -1;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
// -1 for no match, or 0 for 0 offset match, 1 for +1, 2 for +2 offset match...
|
||||
int LHelper::DoFacesMatch(const LFace& sob_f, const LFace &m_face) const
|
||||
{
|
||||
// match one
|
||||
int offset = 0;
|
||||
bool bMatch = false;
|
||||
for (offset = 0; offset < 3; offset++)
|
||||
for (int offset = 0; offset < 3; offset++)
|
||||
{
|
||||
if (DoFaceVertsApproxMatch(sob_f, m_face, 0, offset))
|
||||
if (DoFaceVertsApproxMatch(sob_f, m_face, 0, offset, false))
|
||||
{
|
||||
bMatch = true;
|
||||
break;
|
||||
int res = DoFacesMatch_Offset(sob_f, m_face, offset);
|
||||
|
||||
if (res != -1)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// none found that match, most common scenario
|
||||
if (!bMatch)
|
||||
return -1;
|
||||
|
||||
// debug
|
||||
// String sz = "\t\tposs match sob : ";
|
||||
// sz += sob_f.ToString();
|
||||
// sz += " merged : ";
|
||||
// sz += m_face.ToString();
|
||||
// LPRINT(2, sz);
|
||||
|
||||
|
||||
// does 2nd and third match?
|
||||
int offset1 = (offset + 1) % 3;
|
||||
if (!DoFaceVertsApproxMatch(sob_f, m_face, 1, offset1))
|
||||
return -1;
|
||||
|
||||
int offset2 = (offset + 2) % 3;
|
||||
if (!DoFaceVertsApproxMatch(sob_f, m_face, 2, offset2))
|
||||
return -1;
|
||||
|
||||
return offset;
|
||||
return -1; // no match
|
||||
}
|
||||
|
||||
|
||||
@ -318,6 +391,10 @@ bool LHelper::UnMerge_SOB(MeshInstance &mi, LMerged &merged)
|
||||
lf.m_index[c] = ind;
|
||||
}
|
||||
|
||||
#ifdef LDEBUG_UNMERGE
|
||||
LPRINT(5, "lface : " + lf.ToString());
|
||||
#endif
|
||||
|
||||
// find matching face
|
||||
// int miCount = 0;
|
||||
bool bMatchFound = false;
|
||||
@ -533,7 +610,7 @@ finish:
|
||||
}
|
||||
|
||||
|
||||
bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged)
|
||||
bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged, bool bLightmapUnwrap)
|
||||
{
|
||||
PoolVector<Vector3> verts;
|
||||
PoolVector<Vector3> normals;
|
||||
@ -554,12 +631,12 @@ bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged)
|
||||
continue;
|
||||
|
||||
// to get the transform, the node has to be in the tree, so temporarily show if hidden
|
||||
bool bShowing = sob.m_bShow;
|
||||
sob.Show(true);
|
||||
//bool bShowing = sob.m_bShow;
|
||||
//sob.Show(true);
|
||||
|
||||
Merge_MI(*pMI, verts, normals, inds);
|
||||
|
||||
sob.Show(bShowing);
|
||||
//sob.Show(bShowing);
|
||||
}
|
||||
|
||||
|
||||
@ -608,6 +685,7 @@ bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged)
|
||||
|
||||
am->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, Array(), Mesh::ARRAY_COMPRESS_DEFAULT);
|
||||
|
||||
if (bLightmapUnwrap)
|
||||
LightmapUnwrap(am, pMerged->get_global_transform());
|
||||
|
||||
// duplicate the UV2 to uv1 just in case they are needed
|
||||
|
23
lhelper.h
23
lhelper.h
@ -5,6 +5,8 @@
|
||||
class LHelper
|
||||
{
|
||||
public:
|
||||
LHelper();
|
||||
|
||||
struct LFace
|
||||
{
|
||||
Vector3 m_Pos[3];
|
||||
@ -43,11 +45,13 @@ public:
|
||||
MeshInstance * CreateLightmapProxy(LRoomManager &manager);
|
||||
|
||||
// for lightmapping
|
||||
bool MergeSOBs(LRoomManager &manager, MeshInstance * pMerged);
|
||||
bool MergeSOBs(LRoomManager &manager, MeshInstance * pMerged, bool bLightmapUnwrap = true);
|
||||
|
||||
// take the UV2 coords from the merged mesh and attach these to the SOB meshes
|
||||
bool UnMergeSOBs(LRoomManager &manager, MeshInstance * pMerged);
|
||||
|
||||
void SetUnMergeParams(float thresh_dist, float thresh_dot);
|
||||
|
||||
// bool UnMergeSOBs(LRoomManager &manager, const PoolVector<Vector2> &uv2s);
|
||||
|
||||
// main function for getting merged uv2 back to sobs
|
||||
@ -71,8 +75,10 @@ private:
|
||||
void Transform_Norms(const PoolVector<Vector3> &normsLocal, PoolVector<Vector3> &normsWorld, const Transform &tr) const;
|
||||
|
||||
int DoFacesMatch(const LFace& sob_f, const LFace &m_face) const;
|
||||
bool DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1) const;
|
||||
bool DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm) const;
|
||||
int DoFacesMatch_Offset(const LFace& sob_f, const LFace &m_face, int offset) const;
|
||||
|
||||
bool DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1, bool bDebug) const;
|
||||
bool DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm, bool bDebug) const;
|
||||
|
||||
int FindOrAddVert(LVector<LVert> &uni_verts, const LVert &vert) const;
|
||||
|
||||
@ -80,4 +86,15 @@ private:
|
||||
|
||||
bool FillMergedFromMesh(LMerged &merged, const MeshInstance &mesh);
|
||||
// bool xatlas_mesh_lightmap_unwrap(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
|
||||
|
||||
|
||||
// internal data
|
||||
// merging params
|
||||
struct LMergeParams
|
||||
{
|
||||
float m_fThresholdDist;
|
||||
float m_fThresholdDist_Squared;
|
||||
float m_fThresholdDot;
|
||||
} m_MergeParams;
|
||||
|
||||
};
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool LPortal::NameStartsWith(Node * pNode, String szSearch)
|
||||
bool LPortal::NameStartsWith(const Node * pNode, String szSearch)
|
||||
{
|
||||
int sl = szSearch.length();
|
||||
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
void ReverseWindingOrder();
|
||||
|
||||
// useful funcs
|
||||
static bool NameStartsWith(Node * pNode, String szSearch);
|
||||
static bool NameStartsWith(const Node * pNode, String szSearch);
|
||||
static String FindNameAfter(Node * pNode, String szStart);
|
||||
|
||||
private:
|
||||
|
@ -5,6 +5,8 @@
|
||||
#define LDEBUG_LIGHTS
|
||||
#define LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
|
||||
//#define LDEBUG_UNMERGE
|
||||
|
||||
// single compilation unit
|
||||
#include "register_types.cpp"
|
||||
#include "ldebug.cpp"
|
||||
@ -21,4 +23,5 @@
|
||||
#include "ltrace.cpp"
|
||||
#include "lmain_camera.cpp"
|
||||
#include "larea.cpp"
|
||||
#include "ldae_exporter.cpp"
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "lroom.h"
|
||||
#include "lhelper.h"
|
||||
#include "lscene_saver.h"
|
||||
#include "ldae_exporter.h"
|
||||
|
||||
#define LROOMLIST m_pRoomList
|
||||
#define CHECK_ROOM_LIST if (!CheckRoomList())\
|
||||
@ -68,6 +69,15 @@ LRoomManager::LRoomManager()
|
||||
|
||||
m_pRoomList = 0;
|
||||
|
||||
|
||||
|
||||
// loses detail at approx .. 0.00001
|
||||
// dot 0.9999
|
||||
// however, this will depend on the map so we will use some more approximate figures, and allow
|
||||
// the user to change in rare cases where this fails
|
||||
m_fLightmapUnMerge_ThresholdDist = 0.001f;
|
||||
m_fLightmapUnMerge_ThresholdDot = 0.99f;
|
||||
|
||||
if (!Engine::get_singleton()->is_editor_hint())
|
||||
{
|
||||
CreateDebug();
|
||||
@ -1233,25 +1243,65 @@ bool LRoomManager::rooms_transfer_uv2s(Node * pMeshInstance_From, Node * pMeshIn
|
||||
}
|
||||
|
||||
|
||||
bool LRoomManager::rooms_unmerge_sobs(Node * pMergeMeshInstance)
|
||||
bool LRoomManager::rooms_unmerge_sobs(Node * pMergeMeshInstance, float thresh_dist, float thresh_dot)
|
||||
{
|
||||
MeshInstance * pMI = Object::cast_to<MeshInstance>(pMergeMeshInstance);
|
||||
|
||||
LHelper helper;
|
||||
helper.SetUnMergeParams(thresh_dist, thresh_dot);
|
||||
Lawn::LDebug::m_bRunning = false;
|
||||
bool res = helper.UnMergeSOBs(*this, pMI);
|
||||
Lawn::LDebug::m_bRunning = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LRoomManager::export_scene_DAE(Node * pNode, String szFilename)
|
||||
{
|
||||
LDAEExporter dae;
|
||||
return dae.SaveScene(pNode, szFilename);
|
||||
}
|
||||
|
||||
bool LRoomManager::rooms_save_scene(Node * pNode, String szFilename)
|
||||
{
|
||||
LSceneSaver saver;
|
||||
return saver.SaveScene(pNode, szFilename);
|
||||
}
|
||||
|
||||
void LRoomManager::lightmap_set_unmerge_params(float thresh_dist, float thresh_dot)
|
||||
{
|
||||
// sanitize? NYI
|
||||
m_fLightmapUnMerge_ThresholdDist = thresh_dist;
|
||||
m_fLightmapUnMerge_ThresholdDot = thresh_dot;
|
||||
}
|
||||
|
||||
MeshInstance * LRoomManager::rooms_convert_lightmap_internal(String szProxyFilename, String szLevelFilename)
|
||||
bool LRoomManager::lightmap_external_unmerge(Node * pMergeMeshInstance, String szLevelFilename)
|
||||
{
|
||||
ResolveRoomListPath();
|
||||
if (!CheckRoomList())
|
||||
{
|
||||
WARN_PRINT_ONCE("rooms_convert_lightmap_external : rooms not set");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRoomConverter conv;
|
||||
conv.Convert(*this, true, true, false);
|
||||
|
||||
bool res = rooms_unmerge_sobs(pMergeMeshInstance, m_fLightmapUnMerge_ThresholdDist, m_fLightmapUnMerge_ThresholdDot);
|
||||
|
||||
if (res)
|
||||
{
|
||||
// save the UV2 mapped level
|
||||
if (szLevelFilename != "")
|
||||
rooms_save_scene(LROOMLIST, szLevelFilename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MeshInstance * LRoomManager::lightmap_internal(String szProxyFilename, String szLevelFilename)
|
||||
{
|
||||
ResolveRoomListPath();
|
||||
if (!CheckRoomList())
|
||||
@ -1264,6 +1314,10 @@ MeshInstance * LRoomManager::rooms_convert_lightmap_internal(String szProxyFilen
|
||||
conv.Convert(*this, true, true, false);
|
||||
|
||||
LHelper helper;
|
||||
|
||||
// as we are doing an unmerge, we want to allow the user to override the parameters of the unmerge
|
||||
helper.SetUnMergeParams(m_fLightmapUnMerge_ThresholdDist, m_fLightmapUnMerge_ThresholdDot);
|
||||
|
||||
Lawn::LDebug::m_bRunning = false;
|
||||
MeshInstance * pMI = helper.CreateLightmapProxy(*this);
|
||||
|
||||
@ -1283,15 +1337,70 @@ MeshInstance * LRoomManager::rooms_convert_lightmap_internal(String szProxyFilen
|
||||
return pMI;
|
||||
}
|
||||
|
||||
bool LRoomManager::lightmap_external_export(String szFilename) // DAE filename
|
||||
{
|
||||
ResolveRoomListPath();
|
||||
CHECK_ROOM_LIST
|
||||
|
||||
LRoomConverter conv;
|
||||
conv.Convert(*this, true, true, false, true);
|
||||
|
||||
// LRoomConverter conv;
|
||||
// conv.Convert(*this, true, true, false);
|
||||
|
||||
//#m_Manager.rooms_single_room_convert(true, false)
|
||||
// rooms_single_room_convert(
|
||||
|
||||
|
||||
|
||||
// if (!m_pRoomList)
|
||||
// return false;
|
||||
|
||||
rooms_set_active(false);
|
||||
|
||||
// first create a temporary mesh instance
|
||||
MeshInstance * pMerged = memnew(MeshInstance);
|
||||
pMerged->set_name("Merged");
|
||||
add_child(pMerged);
|
||||
|
||||
|
||||
LHelper helper;
|
||||
Lawn::LDebug::m_bRunning = false;
|
||||
bool res = helper.MergeSOBs(*this, pMerged, false);
|
||||
Lawn::LDebug::m_bRunning = true;
|
||||
|
||||
// create the merged geometry
|
||||
if (res)
|
||||
{
|
||||
// save as a DAE
|
||||
LDAEExporter dae;
|
||||
dae.SetMergedMeshInstance(pMerged);
|
||||
|
||||
res = dae.SaveScene(m_pRoomList, szFilename, true);
|
||||
}
|
||||
|
||||
pMerged->queue_delete();
|
||||
|
||||
rooms_set_active(true);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LRoomManager::rooms_merge_sobs(Node * pMergeMeshInstance)
|
||||
{
|
||||
MeshInstance * pMI = Object::cast_to<MeshInstance>(pMergeMeshInstance);
|
||||
|
||||
|
||||
// first make sure all SOBs are showing by deactivating LPortal
|
||||
rooms_set_active(false);
|
||||
|
||||
LHelper helper;
|
||||
Lawn::LDebug::m_bRunning = false;
|
||||
bool res = helper.MergeSOBs(*this, pMI);
|
||||
Lawn::LDebug::m_bRunning = true;
|
||||
|
||||
// finally reactivate LPortal
|
||||
rooms_set_active(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1885,6 +1994,13 @@ void LRoomManager::_bind_methods()
|
||||
//ClassDB::bind_method(D_METHOD("rooms_unmerge_sobs"), &LRoomManager::rooms_unmerge_sobs);
|
||||
//ClassDB::bind_method(D_METHOD("rooms_transfer_uv2s"), &LRoomManager::rooms_transfer_uv2s);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("lightmap_external_export", "DAE filename"), &LRoomManager::lightmap_external_export);
|
||||
ClassDB::bind_method(D_METHOD("lightmap_external_unmerge", "merged mesh instance", "output level filename"), &LRoomManager::lightmap_external_unmerge);
|
||||
ClassDB::bind_method(D_METHOD("lightmap_set_unmerge_params", "threshold distance (e.g. 0.001)", "threshold dot (e.g. 0.99)"), &LRoomManager::lightmap_set_unmerge_params);
|
||||
|
||||
|
||||
// lightmapping
|
||||
ClassDB::bind_method(D_METHOD("lightmap_internal", "output proxy filename", "output level filename"), &LRoomManager::lightmap_internal);
|
||||
|
||||
// debugging
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_logging", "level 0 to 6"), &LRoomManager::rooms_set_logging);
|
||||
@ -1899,8 +2015,6 @@ void LRoomManager::_bind_methods()
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_frame_string", "active"), &LRoomManager::rooms_set_debug_frame_string);
|
||||
ClassDB::bind_method(D_METHOD("rooms_get_debug_frame_string"), &LRoomManager::rooms_get_debug_frame_string);
|
||||
|
||||
// lightmapping
|
||||
ClassDB::bind_method(D_METHOD("rooms_convert_lightmap_internal", "proxy filename", "level filename"), &LRoomManager::rooms_convert_lightmap_internal);
|
||||
|
||||
// functions to add dynamic objects to the culling system
|
||||
// Note that these should not be placed directly in rooms, the system will 'soft link' to them
|
||||
@ -1934,6 +2048,9 @@ void LRoomManager::_bind_methods()
|
||||
ClassDB::bind_method(D_METHOD("set_rooms_path", "rooms"), &LRoomManager::set_rooms_path);
|
||||
ClassDB::bind_method(D_METHOD("get_rooms_path"), &LRoomManager::get_rooms_path);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("export_scene_DAE", "node", "filename"), &LRoomManager::export_scene_DAE);
|
||||
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "rooms"), "set_rooms_path", "get_rooms_path");
|
||||
}
|
||||
|
||||
|
@ -106,12 +106,16 @@ public:
|
||||
// LIGHTMAPS
|
||||
// helper function to merge SOB meshes for producing lightmaps VIA external blender workflow
|
||||
bool rooms_merge_sobs(Node * pMergeMeshInstance);
|
||||
bool rooms_unmerge_sobs(Node * pMergeMeshInstance);
|
||||
bool rooms_unmerge_sobs(Node * pMergeMeshInstance, float thresh_dist, float thresh_dot);
|
||||
bool rooms_transfer_uv2s(Node * pMeshInstance_From, Node * pMeshInstance_To);
|
||||
|
||||
bool lightmap_external_export(String szFilename); // DAE filename
|
||||
bool lightmap_external_unmerge(Node * pMergeMeshInstance, String szLevelFilename);
|
||||
void lightmap_set_unmerge_params(float thresh_dist, float thresh_dot);
|
||||
|
||||
// one function to do all the uv mapping and lightmap creation in one
|
||||
// (for godot lightmap workflow)
|
||||
MeshInstance * rooms_convert_lightmap_internal(String szProxyFilename, String szLevelFilename);
|
||||
MeshInstance * lightmap_internal(String szProxyFilename, String szLevelFilename);
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// HELPERS
|
||||
@ -123,6 +127,7 @@ public:
|
||||
Array rooms_get_visible_rooms() const;
|
||||
// helper func, not needed usually as dob_update returns the room
|
||||
int dob_get_room_id(Node * pDOB);
|
||||
bool export_scene_DAE(Node * pNode, String szFilename);
|
||||
|
||||
|
||||
//______________________________________________________________________________________
|
||||
@ -284,6 +289,10 @@ private:
|
||||
// for debugging, can emulate view frustum culling
|
||||
bool m_bFrustumOnly;
|
||||
|
||||
// lightmap unmerge params
|
||||
float m_fLightmapUnMerge_ThresholdDist;
|
||||
float m_fLightmapUnMerge_ThresholdDot;
|
||||
|
||||
private:
|
||||
// PRIVATE FUNCS
|
||||
// this is where we do all the culling
|
||||
|
Loading…
Reference in New Issue
Block a user