Skip to content

Commit 86dff67

Browse files
committed
テクスチャのアトラス化について、最小地物がすごく重い問題を解決中:同じテクスチャが来たらそれを使い回す仕様に
1 parent 8dfc30e commit 86dff67

File tree

3 files changed

+176
-91
lines changed

3 files changed

+176
-91
lines changed

include/plateau/texture/texture_packer.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <memory>
88
#include <string>
9+
#include <utility>
910
#include <vector>
1011
#include <filesystem>
1112

@@ -16,13 +17,13 @@ namespace plateau::texture {
1617

1718
explicit AtlasInfo(const bool valid, const size_t left, const size_t top,
1819
const size_t width, const size_t height,
19-
double u_pos, double v_pos, double u_factor, double v_factor) :
20+
double u_pos, double v_pos, double u_factor, double v_factor, std::string src_texture_path) :
2021
valid_(valid), left_(left), top_(top), width_(width), height_(height),
21-
u_pos_(u_pos), v_pos_(v_pos), u_factor_(u_factor), v_factor_(v_factor) {
22+
u_pos_(u_pos), v_pos_(v_pos), u_factor_(u_factor), v_factor_(v_factor), src_texture_path(std::move(src_texture_path)) {
2223
}
2324

2425
static AtlasInfo empty() {
25-
return AtlasInfo(false, 0, 0, 0, 0, 0, 0, 0, 0);
26+
return AtlasInfo(false, 0, 0, 0, 0, 0, 0, 0, 0, "");
2627
}
2728

2829
size_t getLeft() const {
@@ -52,6 +53,10 @@ namespace plateau::texture {
5253

5354
bool getValid() const;
5455

56+
const std::string& getSrcTexturePath() const {
57+
return src_texture_path;
58+
};
59+
5560
private:
5661
bool valid_; // パッキングが成功したかどうか
5762
size_t left_; // パッキングされた画像の左上のX座標
@@ -62,6 +67,7 @@ namespace plateau::texture {
6267
double v_pos_; // uv座標の左上v座標
6368
double u_factor_; // u座標の倍率
6469
double v_factor_; // v座標の倍率
70+
std::string src_texture_path;
6571
};
6672

6773
class AtlasContainer {
@@ -90,10 +96,10 @@ namespace plateau::texture {
9096
size_t vertical_range; // パッキングの対象となる親の画像のコンテナが配置されている左上のY座標
9197
};
9298

99+
93100
class TextureAtlasCanvas {
94101
public:
95102

96-
97103
explicit TextureAtlasCanvas(size_t width, size_t height) :
98104
vertical_range_(0), capacity_(0), coverage_(0),
99105
canvas_(TextureImageBase::createNewTexture(width, height)),
@@ -117,8 +123,9 @@ namespace plateau::texture {
117123
return coverage_;
118124
}
119125

120-
void update(const size_t width, const size_t height, const bool is_new_container); // 画像のパッキング成功時の処理、第3引数(TRUE:新規コンテナを作成、FALSE:既存コンテナに追加)
121-
AtlasInfo insert(const size_t width, const size_t height); // 指定された画像領域(width x height)の領域が確保できるか検証、戻り値AtrasInfoの「valid」ブール値(true:成功、false:失敗)で判定可能
126+
void update(const size_t width, const size_t height, const bool is_new_container, const AtlasInfo& packed_texture_info); // 画像のパッキング成功時の処理、第3引数(TRUE:新規コンテナを作成、FALSE:既存コンテナに追加)
127+
AtlasInfo insert(const size_t width, const size_t height, const std::string& src_texture_path); // 指定された画像領域(width x height)の領域が確保できるか検証、戻り値AtrasInfoの「valid」ブール値(true:成功、false:失敗)で判定可能
128+
bool isTexturePacked(const std::string& src_file_path, AtlasInfo& out_atlas_info);
122129

123130
private:
124131
std::vector<AtlasContainer> container_list_;
@@ -129,6 +136,7 @@ namespace plateau::texture {
129136
double coverage_;
130137
std::unique_ptr<TextureImageBase> canvas_;
131138
std::string save_file_path_;
139+
std::vector<AtlasInfo> packed_textures_info;
132140
};
133141

134142
/// テクスチャのアトラス化をします。
@@ -144,8 +152,10 @@ namespace plateau::texture {
144152
void processMesh(plateau::polygonMesh::Mesh* mesh);
145153

146154
private:
155+
bool isTexturePacked(const std::string& src_file_path, TextureAtlasCanvas*& out_contained_canvas_ptr, AtlasInfo& out_atlas_info);
147156
std::vector<std::shared_ptr<TextureAtlasCanvas>> canvases_;
148157
size_t canvas_width_;
149158
size_t canvas_height_;
159+
150160
};
151161
} // namespace plateau::texture

src/texture/texture_packer.cpp

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ namespace plateau::texture {
6666
}
6767
}
6868

69+
bool TextureAtlasCanvas::isTexturePacked(const std::string& src_file_path, AtlasInfo& out_atlas_info) {
70+
for(const auto& tex_info : packed_textures_info) {
71+
if(tex_info.getSrcTexturePath() == src_file_path) {
72+
out_atlas_info = tex_info;
73+
return true;
74+
}
75+
}
76+
return false;
77+
}
78+
6979
void TexturePacker::process(Model& model) {
7080
for (size_t i = 0; i < model.getRootNodeCount(); ++i) {
7181
const auto& child_node = model.getRootNodeAt(i);
@@ -79,7 +89,7 @@ namespace plateau::texture {
7989
}
8090
}
8191

82-
void TexturePacker::processNodeRecursive(const Node& node) {
92+
void TexturePacker::processNodeRecursive(const Node& node) { // NOLINT(misc-no-recursion)
8393
Mesh* mesh = node.getMesh();
8494
processMesh(mesh);
8595
for (int i = 0; i < node.getChildCount(); ++i) {
@@ -88,6 +98,32 @@ namespace plateau::texture {
8898
}
8999
}
90100

101+
namespace {
102+
void updateUVOfSubMesh(Mesh* mesh, const SubMesh& sub_mesh, const AtlasInfo& info) {
103+
constexpr auto delta = 1.0;
104+
const auto u = info.getUPos();
105+
const auto v = info.getVPos();
106+
const auto u_fac = info.getUFactor() * delta;
107+
const auto v_fac = info.getVFactor() * delta;
108+
109+
110+
111+
// SubMesh中に含まれる頂点番号を求めます。
112+
const auto& indices = mesh->getIndices();
113+
std::set<size_t> vertices_in_sub_mesh;
114+
for(auto i = sub_mesh.getStartIndex(); i <= sub_mesh.getEndIndex(); i++) {
115+
vertices_in_sub_mesh.insert(indices.at(i));
116+
}
117+
// SubMesh中に含まれる頂点について、UVを変更します。
118+
auto& uv1 = mesh->getUV1();
119+
for(const auto vs : vertices_in_sub_mesh) {
120+
const double uv_x = u + (uv1.at(vs).x * u_fac);
121+
const double uv_y = 1 - v - v_fac + (uv1.at(vs).y * v_fac);
122+
uv1[vs] = TVec2f{(float)uv_x, (float)uv_y};
123+
}
124+
}
125+
}
126+
91127
void TexturePacker::processMesh(plateau::polygonMesh::Mesh* mesh) {
92128
if (mesh == nullptr) {
93129
return;
@@ -129,12 +165,26 @@ namespace plateau::texture {
129165
continue;
130166
}
131167

168+
// すでにパック済みならばそれを利用
169+
AtlasInfo packed_info = AtlasInfo::empty();
170+
TextureAtlasCanvas* packed_atlas_canvas_ptr = nullptr;
171+
if(isTexturePacked(tex_url, packed_atlas_canvas_ptr, packed_info)) {
172+
if(packed_atlas_canvas_ptr != nullptr) {
173+
SubMesh new_sub_mesh = sub_mesh;
174+
new_sub_mesh.setTexturePath(packed_atlas_canvas_ptr->getSaveFilePath());
175+
updateUVOfSubMesh(mesh, sub_mesh, packed_info);
176+
sub_mesh_list.push_back(new_sub_mesh);
177+
++index;
178+
continue;
179+
}
180+
}
181+
132182
// canvasのどれかにパックできるか確認
133183
int target_canvas_id = -1;
134184
AtlasInfo info = AtlasInfo::empty();
135185
for (int i=0; i<canvases_.size(); i++) {
136186
auto& canvas = canvases_.at(i);
137-
info = canvas->insert(width, height);
187+
info = canvas->insert(width, height, tex_url);
138188
if (info.getValid()) {
139189
target_canvas_id = i;
140190
break;
@@ -157,58 +207,38 @@ namespace plateau::texture {
157207
target_canvas_id = (int)max_coverage_index;
158208
canvases_.at(max_coverage_index)->flush();
159209
canvases_.at(max_coverage_index) = std::make_shared<TextureAtlasCanvas>(canvas_width_, canvas_height_);
160-
info = canvases_.at(max_coverage_index)->insert(width, height);
210+
info = canvases_.at(max_coverage_index)->insert(width, height, tex_url);
161211
}
162212

163213
assert(info.getValid());
164214

165-
constexpr auto delta = 1.0;
166-
const auto x = info.getLeft();
167-
const auto y = info.getTop();
168-
const auto u = info.getUPos();
169-
const auto v = info.getVPos();
170-
const auto u_fac = info.getUFactor() * delta;
171-
const auto v_fac = info.getVFactor() * delta;
172-
auto tex = sub_mesh.getTexturePath();
173215

174216
auto& target_canvas = canvases_.at(target_canvas_id);
175-
image->packTo(&target_canvas->getCanvas(), x, y);
217+
image->packTo(&target_canvas->getCanvas(), info.getLeft(), info.getTop());
176218
target_canvas->setSaveFilePathIfEmpty(image->getFilePath());
177-
178219
SubMesh new_sub_mesh = sub_mesh;
179220
new_sub_mesh.setTexturePath(target_canvas->getSaveFilePath());
180221
sub_mesh_list.push_back(new_sub_mesh);
181222

182-
// SubMesh中に含まれる頂点番号を求めます。
183-
const auto& indices = mesh->getIndices();
184-
std::set<size_t> vertices_in_sub_mesh;
185-
for(auto i = sub_mesh.getStartIndex(); i <= sub_mesh.getEndIndex(); i++) {
186-
vertices_in_sub_mesh.insert(indices.at(i));
187-
}
188-
// SubMesh中に含まれる頂点について、UVを変更します。
189-
auto& uv1 = mesh->getUV1();
190-
for(const auto vs : vertices_in_sub_mesh) {
191-
const double uv_x = u + (uv1.at(vs).x * u_fac);
192-
const double uv_y = 1 - v - v_fac + (uv1.at(vs).y * v_fac);
193-
uv1[vs] = TVec2f{(float)uv_x, (float)uv_y};
194-
}
223+
updateUVOfSubMesh(mesh, sub_mesh, info);
195224

196225
++index;
197226
}
198227
mesh->setSubMeshes(sub_mesh_list);
199228
}
200229

201-
void TextureAtlasCanvas::update(const size_t width, const size_t height, const bool is_new_container) {
230+
void TextureAtlasCanvas::update(const size_t width, const size_t height, const bool is_new_container, const AtlasInfo& packed_texture_info) {
202231

203232
capacity_ += (width * height);
204233
coverage_ = (double)capacity_ / static_cast<double>(canvas_width_ * canvas_height_) * 100.0;
234+
packed_textures_info.push_back(packed_texture_info);
205235

206236
if (is_new_container) {
207237
vertical_range_ += height;
208238
}
209239
}
210240

211-
AtlasInfo TextureAtlasCanvas::insert(const size_t width, const size_t height) {
241+
AtlasInfo TextureAtlasCanvas::insert(const size_t width, const size_t height, const std::string& src_texture_path) {
212242
AtlasInfo atlas_info = AtlasInfo::empty();
213243

214244
for (auto& container : container_list_) {
@@ -223,8 +253,9 @@ namespace plateau::texture {
223253
true, container.getHorizontalRange(), container.getVerticalRange(), width, height,
224254
(double)container.getHorizontalRange() / static_cast<double>(canvas_width_),
225255
(double)container.getVerticalRange() / static_cast<double>(canvas_height_),
226-
(double)width / static_cast<double>(canvas_width_), (double)height / static_cast<double>(canvas_height_));
227-
this->update(width, height, false);
256+
(double)width / static_cast<double>(canvas_width_), (double)height / static_cast<double>(canvas_height_),
257+
src_texture_path);
258+
this->update(width, height, false, atlas_info);
228259

229260
break;
230261
}
@@ -235,10 +266,27 @@ namespace plateau::texture {
235266
container_list_.push_back(container);
236267
atlas_info = AtlasInfo(true, container.getHorizontalRange(), container.getVerticalRange(), width, height,
237268
(double)container.getHorizontalRange() / static_cast<double>(canvas_width_), (double)container.getVerticalRange() / static_cast<double>(canvas_height_),
238-
(double)width / static_cast<double>(canvas_width_), (double)height / static_cast<double>(canvas_height_));
239-
this->update(width, height, true);
269+
(double)width / static_cast<double>(canvas_width_), (double)height / static_cast<double>(canvas_height_),
270+
src_texture_path);
271+
this->update(width, height, true, atlas_info);
240272
}
241273

242274
return atlas_info;
243275
}
276+
277+
278+
279+
bool TexturePacker::isTexturePacked(const std::string& src_file_path, TextureAtlasCanvas*& out_contained_canvas_ptr, AtlasInfo& out_atlas_info) {
280+
out_contained_canvas_ptr = nullptr;
281+
for(const auto& canvas : canvases_) {
282+
auto packed_info = AtlasInfo::empty();
283+
if(canvas->isTexturePacked(src_file_path, packed_info)) {
284+
out_contained_canvas_ptr = canvas.get();
285+
out_atlas_info = packed_info;
286+
return true;
287+
}
288+
}
289+
return false;
290+
}
291+
244292
} // namespace plateau::texture

0 commit comments

Comments
 (0)