3#include <Tempest/Application>
12using namespace Tempest;
14static uint64_t
mkUInt64(uint32_t a, uint32_t b) {
15 return (uint64_t(a)<<32) | uint64_t(b);
18static bool isVisuallySame(
const zenkit::Material& a,
const zenkit::Material& b) {
23 a.smooth_angle == b.smooth_angle &&
24 a.texture == b.texture &&
25 a.texture_scale == b.texture_scale &&
26 a.texture_anim_fps == b.texture_anim_fps &&
27 a.texture_anim_map_mode == b.texture_anim_map_mode &&
28 a.texture_anim_map_dir == b.texture_anim_map_dir &&
32 a.detail_object == b.detail_object &&
33 a.detail_object_scale == b.detail_object_scale &&
34 a.force_occluder == b.force_occluder &&
35 a.environment_mapping == b.environment_mapping &&
36 a.environment_mapping_strength == b.environment_mapping_strength &&
37 a.wave_mode == b.wave_mode &&
38 a.wave_speed == b.wave_speed &&
39 a.wave_max_amplitude == b.wave_max_amplitude &&
40 a.wave_grid_size == b.wave_grid_size &&
41 a.ignore_sun == b.ignore_sun &&
43 a.default_mapping == b.default_mapping;
46static float areaOf(
const Vec3 sahMin,
const Vec3 sahMax) {
47 auto sz = sahMax - sahMin;
48 return 2*(sz.x*sz.y + sz.x*sz.z + sz.y*sz.z);
52 return 2*(sz.x*sz.y + sz.x*sz.z + sz.y*sz.z);
56 return reinterpret_cast<uint32_t&
>(f);
61 using iterator = std::vector<value_type>::iterator;
63 std::vector<std::pair<uint64_t,uint32_t>>
data;
75 return l.first<r.first;
87 auto l = std::lower_bound(
data.begin(),
data.end(), v, [](
const value_type& x, uint64_t v){
91 while(r!=
data.end()) {
96 return std::make_pair(l,r);
100void PackedMesh::Meshlet::flush(std::vector<Vertex>& vertices,
101 std::vector<uint32_t>& indices,
102 std::vector<uint8_t>& indices8,
103 std::vector<Cluster>& instances,
104 const zenkit::Mesh& mesh) {
111 instances.push_back(bounds);
113 auto& vbo = mesh.vertices;
114 auto& uv = mesh.features;
116 size_t vboSz = vertices.size();
117 vertices.resize(vboSz + MaxVert);
118 for(
size_t i=0; i<vertSz; ++i) {
120 auto& v = uv [vert[i].second];
122 vx.pos[0] = vbo[vert[i].first].x;
123 vx.pos[1] = vbo[vert[i].first].y;
124 vx.pos[2] = vbo[vert[i].first].z;
125 vx.norm[0] = v.normal.x;
126 vx.norm[1] = v.normal.y;
127 vx.norm[2] = v.normal.z;
128 vx.uv[0] = v.texture.x;
129 vx.uv[1] = v.texture.y;
130 vx.color = 0xFFFFFFFF;
131 vertices[vboSz+i] = vx;
133 for(
size_t i=vertSz; i<MaxVert; ++i) {
135 vertices[vboSz+i] = vx;
138 size_t iboSz = indices.size();
139 indices.resize(iboSz + MaxInd);
140 for(
size_t i=0; i<indSz; ++i) {
141 indices[iboSz+i] = uint32_t(vboSz)+indexes[i];
143 for(
size_t i=indSz; i<MaxInd; ++i) {
145 indices[iboSz+i] = uint32_t(vboSz+indSz/3);
149 size_t iboSz8 = indices8.size();
150 indices8.resize(iboSz8 + MaxPrim*4);
151 for(
size_t i=0; i<indSz; i+=3) {
152 size_t at = iboSz8 + (i/3)*4;
153 indices8[at+0] = indexes[i+0];
154 indices8[at+1] = indexes[i+1];
155 indices8[at+2] = indexes[i+2];
159 size_t at = iboSz8 + MaxPrim*4 - 4;
160 indices8[at+0] = indexes[0];
161 indices8[at+1] = indexes[0];
162 indices8[at+2] = indSz/3;
163 indices8[at+3] = vertSz;
168void PackedMesh::Meshlet::flush(std::vector<Vertex>& vertices, std::vector<VertexA>& verticesA,
169 std::vector<uint32_t>& indices, std::vector<uint8_t>& indices8,
170 std::vector<uint32_t>* verticesId,
171 const std::vector<zenkit::Vec3>& vboList,
172 const std::vector<zenkit::MeshWedge>& wedgeList,
173 const std::vector<SkeletalData>* skeletal) {
178 auto& uv = wedgeList;
181 size_t iboSz = indices.size();
183 if(skeletal==
nullptr) {
184 vboSz = vertices.size();
185 vertices.resize(vboSz+MaxVert);
187 vboSz = verticesA.size();
188 verticesA.resize(vboSz+MaxVert);
191 indices.resize(iboSz + MaxInd);
193 if(verticesId!=
nullptr)
194 verticesId->resize(vboSz+MaxVert);
196 if(skeletal==
nullptr) {
197 for(
size_t i=0; i<vertSz; ++i) {
199 auto& v = uv [vert[i].second];
200 vx.pos[0] = vbo[vert[i].first].x;
201 vx.pos[1] = vbo[vert[i].first].y;
202 vx.pos[2] = vbo[vert[i].first].z;
203 vx.norm[0] = v.normal.x;
204 vx.norm[1] = v.normal.y;
205 vx.norm[2] = v.normal.z;
206 vx.uv[0] = v.texture.x;
207 vx.uv[1] = v.texture.y;
208 vx.color = 0xFFFFFFFF;
209 vertices[vboSz+i] = vx;
210 if(verticesId!=
nullptr)
211 (*verticesId)[vboSz+i] = vert[i].first;
213 for(
size_t i=vertSz; i<MaxVert; ++i) {
215 vertices[vboSz+i] = vx;
216 if(verticesId!=
nullptr)
217 (*verticesId)[vboSz+i] = uint32_t(-1);
220 auto& sk = *skeletal;
221 for(
size_t i=0; i<vertSz; ++i) {
223 auto& v = uv [vert[i].second];
224 vx.norm[0] = v.normal.x;
225 vx.norm[1] = v.normal.y;
226 vx.norm[2] = v.normal.z;
227 vx.uv[0] = v.texture.x;
228 vx.uv[1] = v.texture.y;
229 vx.color = 0xFFFFFFFF;
230 for(
int r=0; r<4; ++r) {
231 vx.pos [r][0] = sk[vert[i].first].localPositions[r].x;
232 vx.pos [r][1] = sk[vert[i].first].localPositions[r].y;
233 vx.pos [r][2] = sk[vert[i].first].localPositions[r].z;
234 vx.boneId [r] = sk[vert[i].first].boneIndices[r];
235 vx.weights[r] = sk[vert[i].first].weights[r];
237 verticesA[vboSz+i] = vx;
239 for(
size_t i=vertSz; i<MaxVert; ++i) {
241 verticesA[vboSz+i] = vx;
245 for(
size_t i=0; i<indSz; ++i) {
246 indices[iboSz+i] = uint32_t(vboSz)+indexes[i];
248 for(
size_t i=indSz; i<MaxInd; ++i) {
250 indices[iboSz+i] = uint32_t(vboSz+indSz/3);
254 size_t iboSz8 = indices8.size();
255 indices8.resize(iboSz8 + MaxPrim*4);
256 for(
size_t i=0; i<indSz; i+=3) {
257 size_t at = iboSz8 + (i/3)*4;
258 indices8[at+0] = indexes[i+0];
259 indices8[at+1] = indexes[i+1];
260 indices8[at+2] = indexes[i+2];
264 size_t at = iboSz8 + MaxPrim*4 - 4;
265 indices8[at+0] = indexes[0];
266 indices8[at+1] = indexes[0];
267 indices8[at+2] = indSz/3;
268 indices8[at+3] = vertSz;
273bool PackedMesh::Meshlet::validate()
const {
287bool PackedMesh::Meshlet::insert(
const Vert& a,
const Vert& b,
const Vert& c) {
291 uint8_t ea = MaxVert, eb = MaxVert, ec = MaxVert;
292 for(uint8_t i=0; i<vertSz; ++i) {
301 uint8_t vSz = vertSz;
319 for(
size_t i=0; i<indSz; i+=3) {
320 if(indexes[i+0]==ea && indexes[i+1]==eb && indexes[i+2]==ec) {
327 indexes[indSz+0] = ea;
328 indexes[indSz+1] = eb;
329 indexes[indSz+2] = ec;
330 indSz = uint8_t(indSz+3u);
340void PackedMesh::Meshlet::clear() {
345void PackedMesh::Meshlet::updateBounds(
const zenkit::Mesh& mesh) {
346 updateBounds(mesh.vertices);
349void PackedMesh::Meshlet::updateBounds(
const zenkit::MultiResolutionMesh& mesh) {
350 updateBounds(mesh.positions);
353void PackedMesh::Meshlet::updateBounds(
const std::vector<zenkit::Vec3>& vbo) {
355 for(
size_t i=0; i<vertSz; ++i)
356 for(
size_t r=i+1; r<vertSz; ++r) {
357 auto a = vbo[vert[i].first];
358 auto b = vbo[vert[r].first];
362 float d = a.x*a.x + a.y*a.y + a.z*a.z;
364 bounds.pos = Vec3(b.x,b.y,b.z)+Vec3(a.x,a.y,a.z)*0.5f;
369 for(
size_t i=0; i<vertSz; ++i) {
370 auto a = vbo[vert[i].first];
374 float d = (a.x*a.x + a.y*a.y + a.z*a.z);
378 bounds.r = std::sqrt(bounds.r);
381bool PackedMesh::Meshlet::canMerge(
const Meshlet& other)
const {
382 if(vertSz+other.vertSz>MaxVert)
384 if(indSz+other.indSz>MaxInd)
389bool PackedMesh::Meshlet::hasIntersection(
const Meshlet& other)
const {
390 return (bounds.pos-other.bounds.pos).quadLength() < std::pow(bounds.r+other.bounds.r,2.f);
393float PackedMesh::Meshlet::qDistance(
const Meshlet& other)
const {
394 return (bounds.pos-other.bounds.pos).quadLength();
397void PackedMesh::Meshlet::merge(
const Meshlet& other) {
398 for(uint8_t i=0; i<other.indSz; ++i) {
399 uint8_t index = uint8_t(vertSz+other.indexes[i]);
400 indexes[indSz] = index;
401 vert[index] = other.vert[other.indexes[i]];
404 vertSz = uint8_t(vertSz+other.vertSz);
418 packMeshletsLnd(mesh);
424 packPhysics(mesh,type);
430 subMeshes.resize(mesh.sub_meshes.size());
436 auto bbox = mesh.bbox;
441 packMeshletsObj(mesh,type,
nullptr);
445 auto& mesh = skinned.mesh;
446 subMeshes.resize(mesh.sub_meshes.size());
453 std::vector<SkeletalData>
vertices(mesh.positions.size());
455 auto& stream = skinned.weights;
456 for(
size_t i=0; i<stream.size() && i<
vertices.size(); ++i) {
458 auto& wx = stream[i];
460 for(
size_t j=0; j<wx.size(); j++) {
461 auto& weight = wx[j];
462 vert.boneIndices[j] = weight.node_index;
463 vert.localPositions[j] = {weight.position.x, weight.position.y, weight.position.z};
464 vert.weights[j] = weight.weight;
467 const float sum = (vert.weights[0] + vert.weights[1] + vert.weights[2] + vert.weights[3]);
468 if(sum>std::numeric_limits<float>::min()) {
469 vert.weights[0] /= sum;
470 vert.weights[1] /= sum;
471 vert.weights[2] /= sum;
472 vert.weights[3] /= sum;
479void PackedMesh::packPhysics(
const zenkit::Mesh& mesh, PkgType type) {
480 auto& vbo = mesh.vertices;
481 auto& ibo = mesh.polygons.vertex_indices;
484 auto& mid = mesh.polygons.material_indices;
485 auto& mat = mesh.materials;
487 std::vector<Prim> prim;
488 prim.reserve(mid.size());
489 for(
size_t i=0; i<mid.size(); ++i) {
490 auto& m = mat[mid[i]];
491 if(m.disable_collision)
494 p.primId = uint32_t(i*3);
495 if(m.name.find(
':')==std::string::npos) {
497 p.mat = uint8_t(m.group);
500 p.mat = uint32_t(zenkit::MaterialGroup::NONE) + mid[i];
505 std::sort(prim.begin(), prim.end(), [](
const Prim& a,
const Prim& b){
506 return std::tie(a.mat) < std::tie(b.mat);
509 std::unordered_map<uint32_t,size_t> icache;
510 icache.rehash(
size_t(std::sqrt(ibo.size())));
513 for(
size_t i=0; i<prim.size();) {
514 const auto mId = prim[i].mat;
517 sub.iboOffset =
indices.size();
519 if(mId <
size_t(zenkit::MaterialGroup::NONE)) {
520 sub.material.name =
"";
521 sub.material.group = zenkit::MaterialGroup(mId);
523 auto& m = mat[mId-size_t(zenkit::MaterialGroup::NONE)];
524 sub.material.name = m.name;
525 sub.material.group = m.group;
528 for(; i<prim.size() && prim[i].mat==mId; ++i) {
529 auto pr = prim[i].primId;
530 for(
size_t r=0; r<3; ++r) {
531 uint32_t index = ibo[pr+r];
532 auto rx = icache.find(index);
533 if(rx!=icache.end()) {
534 indices.push_back(uint32_t(rx->second));
537 vx.
pos[0] = vbo[index].x;
538 vx.pos[1] = vbo[index].y;
539 vx.pos[2] = vbo[index].z;
543 indices.push_back(uint32_t(val));
544 icache[index] = uint32_t(val);
549 sub.iboLength =
indices.size()-sub.iboOffset;
555void PackedMesh::packBVH(
const zenkit::Mesh& mesh) {
560void PackedMesh::quadAddPrim(Fragment& f,
const zenkit::Mesh& mesh, uint32_t prim0, uint32_t prim1, uint32_t iMin, uint32_t iMax) {
561 auto& ibo = mesh.polygons.vertex_indices;
566 auto i0 = ibo[prim0*3+0];
567 auto i1 = ibo[prim0*3+1];
568 auto i2 = ibo[prim0*3+2];
569 while(i1==iMin || i1==iMax) {
579 if(prim1==0xFFFFFFFF) {
587 while(i1==iMin || i1==iMax) {
596std::vector<PackedMesh::Fragment> PackedMesh::packQuads(
const zenkit::Mesh& mesh) {
597 auto pullVert = [&](
const zenkit::Mesh& mesh, uint32_t i) {
598 auto v = mesh.vertices[i];
599 return Tempest::Vec3(v.x, v.y, v.z);
602 auto& ibo = mesh.polygons.vertex_indices;
604 auto& mid = mesh.polygons.material_indices;
607 std::vector<HalfEdge> edgeFrag;
608 for(
size_t i=0; i<mid.size(); ++i) {
609 const auto primId = uint32_t(i*3);
611 ib[0] = ibo[primId+0];
612 ib[1] = ibo[primId+1];
613 ib[2] = ibo[primId+2];
615 if(ib[0]==ib[1] || ib[0]==ib[2] || ib[1]==ib[2])
618 for(
size_t r=0; r<3; ++r) {
620 auto i1 = ib[(r+1)%3];
621 auto bbox = pullVert(mesh, i0) - pullVert(mesh, i1);
628 f.iMin = std::min(i0, i1);
629 f.iMax = std::max(i0, i1);
630 f.prim = uint32_t(i);
632 edgeFrag.push_back(f);
636 std::sort(edgeFrag.begin(), edgeFrag.end(), [](
const HalfEdge& l,
const HalfEdge& r){
637 return std::tie(l.sah, l.iMin, l.iMax, l.prim) > std::tie(r.sah, r.iMin, r.iMax, r.prim);
640 std::vector<bool> pairings(mid.size());
641 std::vector<Fragment> frag;
642 for(
size_t i=0; i<edgeFrag.size(); ++i) {
643 const auto& a = edgeFrag[i+0];
644 const auto& b = (i+1<edgeFrag.size()) ? edgeFrag[i+1] : a;
645 if(pairings[a.prim] || pairings[b.prim])
649 if(i+1<edgeFrag.size() && a.iMin==b.iMin && a.iMax==b.iMax) {
650 pairings[a.prim] =
true;
651 pairings[b.prim] =
true;
652 quadAddPrim(f, mesh, a.prim, b.prim, a.iMin, a.iMax);
658 for(
size_t i=0; i<pairings.size(); ++i) {
662 quadAddPrim(f, mesh, uint32_t(i), 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
667 Vec3 bbmin = pullVert(mesh, f.ibo[0]);
669 for(
size_t i=1; i<4; ++i) {
670 Vec3 vec = pullVert(mesh, f.ibo[i]);
671 bbmin.x = std::min(bbmin.x, vec.x);
672 bbmin.y = std::min(bbmin.y, vec.y);
673 bbmin.z = std::min(bbmin.z, vec.z);
675 bbmax.x = std::max(bbmax.x, vec.x);
676 bbmax.y = std::max(bbmax.y, vec.y);
677 bbmax.z = std::max(bbmax.z, vec.z);
680 f.centroid = (bbmin+bbmax)/2.f;
688std::pair<uint32_t, float> PackedMesh::findNodeSplit(
const Fragment* frag,
size_t size,
const bool useSah) {
690 return std::make_pair(size/2, 0);
692 size_t split = size/2;
693 float bestCost = std::numeric_limits<float>::max();
695 std::vector<float> sahB(size);
696 Vec3 sahMin = frag[size-1].bbmin;
697 Vec3 sahMax = frag[size-1].bbmax;
698 for(
size_t i=size; i>1; ) {
701 sahMin.x = std::min(sahMin.x, f.bbmin.x);
702 sahMin.y = std::min(sahMin.y, f.bbmin.y);
703 sahMin.z = std::min(sahMin.z, f.bbmin.z);
705 sahMax.x = std::max(sahMax.x, f.bbmax.x);
706 sahMax.y = std::max(sahMax.y, f.bbmax.y);
707 sahMax.z = std::max(sahMax.z, f.bbmax.z);
709 sahB[i-1] =
areaOf(sahMin, sahMax);
712 sahMin = frag[0].bbmin;
713 sahMax = frag[0].bbmax;
714 for(
size_t i=0; i+1<size; ++i) {
716 sahMin.x = std::min(sahMin.x, f.bbmin.x);
717 sahMin.y = std::min(sahMin.y, f.bbmin.y);
718 sahMin.z = std::min(sahMin.z, f.bbmin.z);
720 sahMax.x = std::max(sahMax.x, f.bbmax.x);
721 sahMax.y = std::max(sahMax.y, f.bbmax.y);
722 sahMax.z = std::max(sahMax.z, f.bbmax.z);
724 const float sahA =
areaOf(sahMin, sahMax);
725 const float cost = sahA*float(i) + sahB[i]*float(size-i);
732 return std::make_pair(split, bestCost);
735std::pair<uint32_t, bool> PackedMesh::findNodeSplitSah(Fragment* frag,
size_t size) {
736 const bool useSah =
true;
738 return std::make_pair(size/2, 0);
740 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.x < r.centroid.x; });
741 const auto retX = findNodeSplit(frag, size, useSah);
743 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.y < r.centroid.y; });
744 const auto retY = findNodeSplit(frag, size, useSah);
746 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.z < r.centroid.z; });
747 const auto retZ = findNodeSplit(frag, size, useSah);
749 if(retZ.second <= retX.second && retZ.second <= retY.second)
750 return std::make_pair(retZ.first,
true);
751 if(retY.second <= retX.second && retY.second <= retZ.second) {
752 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.y < r.centroid.y; });
753 return std::make_pair(retY.first,
true);
755 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.x < r.centroid.x; });
756 return std::make_pair(retX.first,
true);
759void PackedMesh::packBlocks(Block* out, uint32_t& outSz, uint8_t destSz, Fragment* frag,
size_t size) {
760 out[outSz].frag = frag;
761 out[outSz].size = size;
764 while(outSz<destSz) {
765 uint32_t current = 0;
766 for(uint32_t i=1; i<outSz; ++i) {
767 if(out[i].size > out[current].size)
771 auto& cur = out[current];
775 const auto splitV = findNodeSplitSah(cur.frag, cur.size);
776 const size_t split = splitV.first;
778 auto& nxt = out[outSz]; ++outSz;
779 nxt.frag = cur.frag+split;
780 nxt.size = cur.size-split;
784 for(
size_t i=0; i<outSz; ++i) {
786 computeBbox(cur.bbmin, cur.bbmax, cur.frag, cur.size);
789 std::sort(out, out+outSz, [](
const Block& l,
const Block& r){
790 return areaOf(l.bbmin, l.bbmax)*float(l.size) <
areaOf(r.bbmin, r.bbmax)*float(r.size);
794void PackedMesh::computeBbox(Tempest::Vec3& bbmin, Tempest::Vec3& bbmax,
const Fragment* frag,
size_t size) {
795 bbmin = frag[0].bbmin;
796 bbmax = frag[0].bbmax;
797 for(
size_t i=1; i<size; ++i) {
799 bbmin.x = std::min(bbmin.x, f.bbmin.x);
800 bbmin.y = std::min(bbmin.y, f.bbmin.y);
801 bbmin.z = std::min(bbmin.z, f.bbmin.z);
803 bbmax.x = std::max(bbmax.x, f.bbmax.x);
804 bbmax.y = std::max(bbmax.y, f.bbmax.y);
805 bbmax.z = std::max(bbmax.z, f.bbmax.z);
809void PackedMesh::packBVH2(
const zenkit::Mesh& mesh) {
810 auto frag = packQuads(mesh);
812 std::vector<BVHNode> nodes;
813 packBVH2(mesh, nodes, frag.data(), frag.size(),
size_t(-1));
819uint32_t PackedMesh::packBVH2(
const zenkit::Mesh& mesh, std::vector<BVHNode>& nodes,
820 Fragment* frag,
size_t size,
size_t parentSz) {
821 auto pullVert = [&](
const zenkit::Mesh& mesh, uint32_t i) {
822 auto v = mesh.vertices[i];
823 return Tempest::Vec3(v.x, v.y, v.z);
832 const auto& f = frag[0];
835 node.padd1 = f.prim0;
836 node.lmin = pullVert(mesh, f.ibo[0]);
837 node.lmax = pullVert(mesh, f.ibo[1]);
838 node.rmin = pullVert(mesh, f.ibo[2]);
839 node.lmax -= node.lmin;
840 node.rmin -= node.lmin;
842 const size_t nId = nodes.size();
843 if(
true && frag[0].prim1!=0xFFFFFFFF) {
844 node.rmax = pullVert(mesh, f.ibo[3]);
845 node.rmax -= node.lmin;
846 nodes.emplace_back(node);
850 nodes.emplace_back(node);
856 uint32_t blockSz = 0;
857 packBlocks(block, blockSz, 2, frag, size);
860 const size_t nId = nodes.size();
861 nodes.emplace_back();
864 node.left = packBVH2(mesh, nodes, block[0].frag, block[0].size, size);
865 node.right = packBVH2(mesh, nodes, block[1].frag, block[1].size, size);
866 node.lmin = block[0].bbmin;
867 node.lmax = block[0].bbmax;
868 node.rmin = block[1].bbmin;
869 node.rmax = block[1].bbmax;
880void PackedMesh::packCWBVH8(
const zenkit::Mesh& mesh) {
882 auto frag = packQuads(mesh);
884 std::vector<UVec4> nodes(
sizeof(CWBVH8)/
sizeof(
UVec4));
885 auto root = packCWBVH8(mesh, nodes, frag.data(), frag.size());
886 std::memcpy(nodes.data(), &root,
sizeof(root));
892PackedMesh::CWBVH8 PackedMesh::packCWBVH8(
const zenkit::Mesh& mesh, std::vector<UVec4>& nodes, Fragment* frag,
size_t size) {
893 auto pullVert = [&](
const zenkit::Mesh& mesh, uint32_t i) {
894 auto v = mesh.vertices[i];
895 return Tempest::Vec3(v.x, v.y, v.z);
898 auto toUvec4 = [](
const Vec3 a){
914 uint32_t blockSz = 0;
915 packBlocks(block, blockSz, 8, frag, size);
919 constexpr uint32_t numVec = (
sizeof(CWBVH8)/
sizeof(
UVec4));
920 auto node = nodeFromBlocks(block);
922 const uint32_t numNodes = node.pNodes;
923 const uint32_t numPrims = node.pPrimitives;
925 node.pNodes = node.pNodes==0 ? 0 : uint32_t(nodes.size());
926 node.pPrimitives = node.pPrimitives==0 ? 0 : uint32_t(nodes.size() + numNodes*numVec);
927 nodes.resize(nodes.size() + numNodes*numVec + numPrims*3);
929 uint32_t iNode = 0, iPrim = 0;
930 for(
size_t i=0; i<8; ++i) {
935 if((node.imask & (1u << i))!=0) {
936 auto child = packCWBVH8(mesh, nodes, b.frag, b.size);
937 auto* cwnode =
reinterpret_cast<CWBVH8*
>(nodes.data() + node.pNodes);
938 cwnode[iNode] = child;
944 const auto& f = b.frag[0];
945 const uint32_t prim = b.frag[0].prim0;
946 const Vec3 ta = pullVert(mesh, f.ibo[0]);
947 const Vec3 tb = pullVert(mesh, f.ibo[1]);
948 const Vec3 tc = pullVert(mesh, f.ibo[2]);
950 auto* cwnode = (nodes.data() + node.pPrimitives + iPrim*3);
951 cwnode[0] = toUvec4(ta);
952 cwnode[1] = toUvec4(tb);
953 cwnode[2] = toUvec4(tc);
967PackedMesh::CWBVH8 PackedMesh::packCWBVH8(
const zenkit::Mesh& mesh, std::vector<UVec4>& nodes,
968 const std::vector<uint32_t>& ibo, Fragment* frag,
size_t size) {
969 auto pullVert = [&](uint32_t i) {
970 auto v = mesh.vertices[i];
971 return Tempest::Vec3(v.x, v.y, v.z);
974 auto toUvec4 = [](
const Vec3 a){
990 uint32_t blockSz = 0;
991 packCW8Blocks(block, blockSz, mesh, nodes, frag, size, 0);
995 constexpr uint32_t numVec = (
sizeof(CWBVH8)/
sizeof(
UVec4));
996 CWBVH8 node = nodeFromBlocks(block);
998 const uint32_t numNodes = node.pNodes;
999 const uint32_t numPrims = node.pPrimitives;
1001 node.pNodes = node.pNodes==0 ? 0 : uint32_t(nodes.size());
1002 node.pPrimitives = node.pPrimitives==0 ? 0 : uint32_t(nodes.size()) + numNodes*numVec;
1003 nodes.resize(nodes.size() + numNodes*numVec + numPrims*3);
1005 uint32_t iNode = 0, iPrim = 0;
1006 for(
size_t i=0; i<8; ++i) {
1011 if((node.imask & (1u << i))!=0) {
1012 auto child = packCWBVH8(mesh, nodes, ibo, b.frag, b.size);
1013 auto* cwnode =
reinterpret_cast<CWBVH8*
>(nodes.data() + node.pNodes);
1014 cwnode[iNode] = child;
1020 const uint32_t prim = b.frag[0].prim0;
1021 const Vec3 ta = pullVert(ibo[prim+0]);
1022 const Vec3 tb = pullVert(ibo[prim+1]);
1023 const Vec3 tc = pullVert(ibo[prim+2]);
1025 auto* cwnode = (nodes.data() + node.pPrimitives + iPrim*3);
1026 cwnode[0] = toUvec4(ta);
1027 cwnode[1] = toUvec4(tb);
1028 cwnode[2] = toUvec4(tc);
1041void PackedMesh::packCW8Blocks(Block* out, uint32_t& outSz,
const zenkit::Mesh& mesh, std::vector<UVec4>& nodes,
1042 Fragment* frag,
size_t size, uint8_t depth) {
1043 Tempest::Vec3 bbmin = {}, bbmax = {};
1044 bbmin = frag[0].bbmin;
1045 bbmax = frag[0].bbmax;
1046 for(
size_t i=1; i<size; ++i) {
1048 bbmin.x = std::min(bbmin.x, f.bbmin.x);
1049 bbmin.y = std::min(bbmin.y, f.bbmin.y);
1050 bbmin.z = std::min(bbmin.z, f.bbmin.z);
1052 bbmax.x = std::max(bbmax.x, f.bbmax.x);
1053 bbmax.y = std::max(bbmax.y, f.bbmax.y);
1054 bbmax.z = std::max(bbmax.z, f.bbmax.z);
1058 out[outSz].bbmin = bbmin;
1059 out[outSz].bbmax = bbmax;
1060 out[outSz].frag = frag;
1061 out[outSz].size = size;
1066 Vec3 sz = bbmax-bbmin;
1067 if(sz.x>sz.y && sz.x>sz.z) {
1068 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.x < r.centroid.x; });
1070 else if(sz.y>sz.x && sz.y>sz.z) {
1071 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.y < r.centroid.y; });
1074 std::sort(frag, frag+size, [](
const Fragment& l,
const Fragment& r){
return l.centroid.z < r.centroid.z; });
1077 const bool useSah =
false;
1078 const auto split = findNodeSplit(frag, size, useSah).first;
1080 packCW8Blocks(out, outSz, mesh, nodes, frag, split, depth+1);
1081 packCW8Blocks(out, outSz, mesh, nodes, frag+split, size-split, depth+1);
1084 orderBlocks(out, outSz, bbmin, bbmax);
1088void PackedMesh::orderBlocks(Block* block,
const uint32_t numBlocks,
const Tempest::Vec3 bbmin,
const Tempest::Vec3 bbmax) {
1090 const Vec3 nodeCen = (bbmin + bbmax) * 0.5f;
1092 int assignment[8] = {};
1094 bool isSlotEmpty[8];
1096 for(uint32_t s=0; s<8; s++) {
1097 isSlotEmpty[s] =
true;
1098 for(
size_t i=0; i<8; ++i)
1099 cost[s][i] = std::numeric_limits<float>::max();
1102 for(
size_t i=0; i<8; i++)
1105 for(uint32_t s = 0; s < 8; s++) {
1107 (((s >> 2) & 1) == 1) ? -1.0f : 1.0f,
1108 (((s >> 1) & 1) == 1) ? -1.0f : 1.0f,
1109 (((s >> 0) & 1) == 1) ? -1.0f : 1.0f);
1111 for(
size_t i=0; i<numBlocks; ++i) {
1112 Vec3 cen = (block[i].bbmin + block[i].bbmax) * 0.5f;
1113 cost[s][i] = Vec3::dotProduct(cen - nodeCen, ds);
1118 float minCost = std::numeric_limits<float>::max();
1119 IVec2 minEntry = IVec2(-1);
1121 for(
int s = 0; s < 8; s++) {
1122 for(
int i = 0; i < 8; i++) {
1123 if(assignment[i] == -1 && isSlotEmpty[s] && cost[s][i] < minCost) {
1124 minCost = cost[s][i];
1125 minEntry = IVec2(s, i);
1130 if(minEntry.x != -1 || minEntry.y != -1) {
1131 assert(minEntry.x != -1 && minEntry.y != -1);
1132 isSlotEmpty[minEntry.x] =
false;
1133 assignment [minEntry.y] = minEntry.x;
1135 assert(minEntry.x == -1 && minEntry.y == -1);
1140 for(
size_t i = 0; i < 8; i++) {
1141 if(assignment[i] == -1) {
1142 for(
int s = 0; s < 8; s++) {
1143 if(isSlotEmpty[s]) {
1144 isSlotEmpty[s] =
false;
1153 for(
size_t i=0; i<8; ++i)
1154 tmp[i] = block[assignment[i]];
1155 std::memcpy(block, tmp,
sizeof(Block)*8);
1158PackedMesh::CWBVH8 PackedMesh::nodeFromBlocks(Block* block) {
1161 Vec3 bbmin = block[0].bbmin;
1162 Vec3 bbmax = block[0].bbmax;
1163 for(
size_t i=1; i<8; ++i) {
1165 bbmin.x = std::min(bbmin.x, f.bbmin.x);
1166 bbmin.y = std::min(bbmin.y, f.bbmin.y);
1167 bbmin.z = std::min(bbmin.z, f.bbmin.z);
1169 bbmax.x = std::max(bbmax.x, f.bbmax.x);
1170 bbmax.y = std::max(bbmax.y, f.bbmax.y);
1171 bbmax.z = std::max(bbmax.z, f.bbmax.z);
1174 node.p[0] = bbmin.x;
1175 node.p[1] = bbmin.y;
1176 node.p[2] = bbmin.z;
1179 constexpr int Nq = 8;
1180 constexpr float denom = 1.0f / float((1 << Nq) - 1);
1182 const float ex = exp2f(ceilf(log2f((bbmax.x - bbmin.x) * denom)));
1183 const float ey = exp2f(ceilf(log2f((bbmax.y - bbmin.y) * denom)));
1184 const float ez = exp2f(ceilf(log2f((bbmax.z - bbmin.z) * denom)));
1186 const float inv_ex = 1.f/ex;
1187 const float inv_ey = 1.f/ey;
1188 const float inv_ez = 1.f/ez;
1190 node.e[0] = uint8_t(
reinterpret_cast<const uint32_t&
>(ex) >> 23);
1191 node.e[1] = uint8_t(
reinterpret_cast<const uint32_t&
>(ey) >> 23);
1192 node.e[2] = uint8_t(
reinterpret_cast<const uint32_t&
>(ez) >> 23);
1195 node.pPrimitives = 0;
1198 const size_t maxPrimPerNode = 1;
1199 for(
size_t i=0; i<8; ++i) {
1204 if(b.size<=maxPrimPerNode) {
1205 static const uint32_t uNum[] = {0b000, 0b001, 0b011, 0b111};
1206 const uint32_t triIndex = node.pPrimitives * 3;
1208 assert(triIndex<=24);
1210 node.imask |= (0u << i);
1211 node.meta[i] = uint8_t((uNum[b.size] << 5) | (triIndex & 0b11111));
1215 node.imask |= (1u << i);
1216 node.meta[i] = (1u << 5) | ((24+i) & 0b11111);
1219 node.qmin_x[i] = uint8_t(floorf((b.bbmin.x - node.p[0]) * inv_ex));
1220 node.qmin_y[i] = uint8_t(floorf((b.bbmin.y - node.p[1]) * inv_ey));
1221 node.qmin_z[i] = uint8_t(floorf((b.bbmin.z - node.p[2]) * inv_ez));
1223 node.qmax_x[i] = uint8_t(ceilf ((b.bbmax.x - node.p[0]) * inv_ex));
1224 node.qmax_y[i] = uint8_t(ceilf ((b.bbmax.y - node.p[1]) * inv_ey));
1225 node.qmax_z[i] = uint8_t(ceilf ((b.bbmax.z - node.p[2]) * inv_ez));
1231void PackedMesh::packMeshletsLnd(
const zenkit::Mesh& mesh) {
1232 auto& ibo = mesh.polygons.vertex_indices;
1233 auto& feat = mesh.polygons.feature_indices;
1234 auto& mid = mesh.polygons.material_indices;
1236 std::vector<uint32_t> mat(mesh.materials.size());
1237 for(
size_t i=0; i<mesh.materials.size(); ++i)
1238 mat[i] = uint32_t(i);
1240 for(
size_t i=0; i<mesh.materials.size(); ++i) {
1241 for(
size_t r=i+1; r<mesh.materials.size(); ++r) {
1244 auto& a = mesh.materials[i];
1245 auto& b = mesh.materials[r];
1251 std::vector<Prim> prim;
1252 prim.reserve(mid.size());
1253 for(
size_t i=0; i<mid.size(); ++i) {
1255 p.primId = uint32_t(i*3);
1256 p.mat = mat[mid[i]];
1259 std::sort(prim.begin(), prim.end(), [](
const Prim& a,
const Prim& b){
1260 return std::tie(a.mat) < std::tie(b.mat);
1264 heap.reserve(mid.size());
1265 std::vector<bool> used(mid.size(),
false);
1267 vertices.reserve(mesh.vertices.size());
1271 for(
size_t i=0; i<prim.size();) {
1272 const auto mId = prim[i].mat;
1275 for(; i<prim.size() && prim[i].mat==mId; ++i) {
1276 const uint32_t
id = prim[i].primId;
1278 auto a =
mkUInt64(ibo[
id+0],feat[
id+0]);
1279 auto b =
mkUInt64(ibo[
id+1],feat[
id+1]);
1280 auto c =
mkUInt64(ibo[
id+2],feat[
id+2]);
1282 heap.push_back(std::make_pair(a,
id));
1283 heap.push_back(std::make_pair(b,
id));
1284 heap.push_back(std::make_pair(c,
id));
1290 std::vector<Meshlet> meshlets = buildMeshlets(&mesh,
nullptr,heap,used);
1291 for(
size_t i=0; i<meshlets.size(); ++i)
1292 meshlets[i].updateBounds(mesh);
1295 pack.material = mesh.materials[mId];
1296 pack.iboOffset =
indices.size();
1297 for(
auto& i:meshlets)
1299 pack.iboLength =
indices.size() - pack.iboOffset;
1300 if(pack.iboLength>0)
1307void PackedMesh::packMeshletsObj(
const zenkit::MultiResolutionMesh& mesh, PkgType type,
1308 const std::vector<SkeletalData>* skeletal) {
1312 for(
auto& sm:mesh.sub_meshes)
1313 maxTri = std::max(maxTri, sm.triangles.size());
1315 heap.reserve(maxTri);
1316 std::vector<bool> used(maxTri);
1318 for(
size_t mId=0; mId<mesh.sub_meshes.size(); ++mId) {
1319 auto& sm = mesh.sub_meshes[mId];
1321 pack.material = sm.mat;
1324 for(
size_t i=0; i<sm.triangles.size(); ++i) {
1325 const uint16_t* ibo = sm.triangles[i].wedges;
1326 for(
int x=0; x<3; ++x) {
1327 auto& wedge = sm.wedges[ibo[x]];
1328 auto vert =
mkUInt64(wedge.index,ibo[x]);
1329 heap.push_back(std::make_pair(vert,uint32_t(i*3)));
1333 std::vector<Meshlet> meshlets = buildMeshlets(
nullptr,&sm,heap,used);
1334 for(
size_t i=0; i<meshlets.size(); ++i)
1335 meshlets[i].updateBounds(mesh);
1337 pack.iboOffset =
indices.size();
1338 for(
auto& i:meshlets)
1340 pack.iboLength =
indices.size() - pack.iboOffset;
1346std::vector<PackedMesh::Meshlet> PackedMesh::buildMeshlets(
const zenkit::Mesh* mesh,
1347 const zenkit::SubMesh* proto_mesh,
1348 PrimitiveHeap& heap, std::vector<bool>& used) {
1350 std::fill(used.begin(), used.end(),
false);
1352 const bool tightPacking =
true;
1354 size_t firstUnused = 0;
1355 size_t firstVert = 0;
1358 std::vector<Meshlet> meshlets;
1360 size_t triId = size_t(-1);
1362 for(
size_t r=firstVert; r<active.vertSz; ++r) {
1363 auto i = active.vert[r];
1364 auto e = heap.equal_range(
mkUInt64(i.first,i.second));
1365 for(
auto it = e.first; it!=e.second; ++it) {
1366 auto id = it->second/3;
1369 if(addTriangle(active,mesh,proto_mesh,
id)) {
1379 if(triId==
size_t(-1) && active.indSz!=0 && !tightPacking) {
1381 meshlets.push_back(std::move(active));
1387 if(triId==
size_t(-1)) {
1388 for(
auto i=heap.begin()+ptrdiff_t(firstUnused); i!=heap.end();) {
1389 if(used[i->second/3]) {
1393 firstUnused = size_t(std::distance(heap.begin(),i+1));
1394 triId = i->second/3;
1399 if(triId!=
size_t(-1) && addTriangle(active,mesh,proto_mesh,triId)) {
1404 if(active.indSz!=0) {
1406 meshlets.push_back(std::move(active));
1411 if(triId==
size_t(-1))
1418bool PackedMesh::addTriangle(Meshlet& dest,
const zenkit::Mesh* mesh,
const zenkit::SubMesh* sm,
size_t id) {
1421 auto& ibo = mesh->polygons.vertex_indices;
1422 auto& feat = mesh->polygons.feature_indices;
1424 auto a = std::make_pair(ibo[id3+0],feat[id3+0]);
1425 auto b = std::make_pair(ibo[id3+1],feat[id3+1]);
1426 auto c = std::make_pair(ibo[id3+2],feat[id3+2]);
1427 return dest.insert(a,b,c);
1430 const uint16_t* feat = sm->triangles[id].wedges;
1431 auto a = std::make_pair(sm->wedges[feat[0]].index, feat[0]);
1432 auto b = std::make_pair(sm->wedges[feat[1]].index, feat[1]);
1433 auto c = std::make_pair(sm->wedges[feat[2]].index, feat[2]);
1434 return dest.insert(a,b,c);
1439 out <<
"v " << i.pos[0] <<
" " << i.pos[1] <<
" " << i.pos[2] << std::endl;
1440 out <<
"vn " << i.norm[0] <<
" " << i.norm[1] <<
" " << i.norm[2] << std::endl;
1441 out <<
"vt " << i.uv[0] <<
" " << i.uv[1] << std::endl;
1445 out <<
"o " << s.material.name << std::endl;
1446 for(
size_t i=0; i<s.iboLength; i+=3) {
1447 const uint32_t* tri = &
indices[s.iboOffset+i];
1448 out <<
"f " << 1+tri[0] <<
" " << 1+tri[1] <<
" " << 1+tri[2] << std::endl;
1454 return std::make_pair(mBbox[0],mBbox[1]);
1457void PackedMesh::computeBbox() {
1467 mBbox[1] = mBbox[0];
1469 for(
size_t i=1; i<
vertices.size(); ++i) {
1470 mBbox[0].x = std::min(mBbox[0].x,
vertices[i].pos[0]);
1471 mBbox[0].y = std::min(mBbox[0].y,
vertices[i].pos[1]);
1472 mBbox[0].z = std::min(mBbox[0].z,
vertices[i].pos[2]);
1474 mBbox[1].x = std::max(mBbox[1].x,
vertices[i].pos[0]);
1475 mBbox[1].y = std::max(mBbox[1].y,
vertices[i].pos[1]);
1476 mBbox[1].z = std::max(mBbox[1].z,
vertices[i].pos[2]);
1480void PackedMesh::dbgUtilization(
const std::vector<Meshlet>& meshlets) {
1481 size_t usedV = 0, allocatedV = 0;
1482 size_t usedP = 0, allocatedP = 0;
1483 for(
auto i:meshlets) {
1491 float procentV = (float(usedV*100)/float(allocatedV));
1492 float procentP = (float(usedP*100)/float(allocatedP));
1493 procentV = float(procentV*100)/100.f;
1496 std::snprintf(buf,
sizeof(buf),
"Meshlet usage: prim = %02.02f%%, vert = %02.02f%%, count = %d", procentP, procentV,
int(meshlets.size()));
1504void PackedMesh::dbgMeshlets(
const zenkit::Mesh& mesh,
const std::vector<Meshlet*>& meshlets) {
1505 std::ofstream out(
"dbg.obj");
1508 auto& vbo = mesh.vertices;
1509 for(
auto i:meshlets) {
1510 out <<
"o meshlet" << off <<
" " << i->bounds.r << std::endl;
1511 for(
size_t r=0; r<i->vertSz; ++r) {
1512 auto& v = vbo[i->vert[r].first];
1513 out <<
"v " << v.x <<
" " << v.y <<
" " << v.z << std::endl;
1515 for(
size_t r=0; r<i->indSz; r+=3) {
1516 auto tri = &i->indexes[r];
1517 out <<
"f " << off+tri[0] <<
" " << off+tri[1] <<
" " << off+tri[2] << std::endl;
static auto options() -> const Options &
std::vector< UVec4 > bvh8Nodes
std::vector< BVHNode > bvhNodes
std::pair< Tempest::Vec3, Tempest::Vec3 > bbox() const
std::vector< Cluster > meshletBounds
Tempest::BasicPoint< uint32_t, 4 > UVec4
PackedMesh(const zenkit::MultiResolutionMesh &mesh, PkgType type)
std::vector< SubMesh > subMeshes
void debug(std::ostream &out) const
std::vector< uint32_t > indices
std::vector< VertexA > verticesA
std::vector< uint8_t > indices8
std::vector< uint32_t > verticesId
std::vector< Vertex > vertices
zenkit::AxisAlignedBoundingBox get_total_aabb(const zenkit::SoftSkinMesh &)
static bool isVisuallySame(const zenkit::Material &a, const zenkit::Material &b)
static uint64_t mkUInt64(uint32_t a, uint32_t b)
static float areaOf(const Vec3 sahMin, const Vec3 sahMax)
static uint32_t floatBitsToUint(float f)
std::vector< std::pair< uint64_t, uint32_t > > data
std::pair< iterator, iterator > equal_range(uint64_t v)
std::pair< uint64_t, uint32_t > value_type
std::vector< value_type >::iterator iterator
void push_back(const value_type &v)
iterator erase(iterator &i)