Skip to content

Commit 842c201

Browse files
committed
fix converting special texture (empty mask)
1 parent 181a0af commit 842c201

File tree

2 files changed

+119
-49
lines changed

2 files changed

+119
-49
lines changed

sources/libcore/mesh/importConvert.cpp

Lines changed: 108 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace cage
4141
{
4242
for (auto &it : textures.images.parts)
4343
{
44+
CAGE_ASSERT(it.image->channels() == 3);
4445
Holder<Image> img = newImage();
4546
const Vec2i res = it.image->resolution();
4647
img->initialize(res, 1, it.image->format());
@@ -59,13 +60,27 @@ namespace cage
5960
textures.name += Stringizer() + "_avg";
6061
}
6162

62-
void expandChannels1To3(MeshImportTexture &textures)
63+
void duplicateChannels1To3(MeshImportTexture &textures)
6364
{
6465
for (auto &it : textures.images.parts)
6566
{
67+
CAGE_ASSERT(it.image->channels() == 1);
6668
const Image *arr[3] = { +it.image, +it.image, +it.image };
6769
it.image = imageChannelsJoin(arr);
6870
}
71+
if (find(textures.name, '?') != m)
72+
textures.name += Stringizer() + "_dup";
73+
}
74+
75+
void expandChannels2To3(MeshImportTexture &textures)
76+
{
77+
for (auto &it : textures.images.parts)
78+
{
79+
CAGE_ASSERT(it.image->channels() == 2);
80+
const auto split = imageChannelsSplit(+it.image);
81+
const Image *arr[3] = { +split[0], +split[1], nullptr };
82+
it.image = imageChannelsJoin(arr);
83+
}
6984
if (find(textures.name, '?') != m)
7085
textures.name += Stringizer() + "_exp";
7186
}
@@ -74,16 +89,29 @@ namespace cage
7489
{
7590
if (it.images.parts[0].image->channels() == 0)
7691
CAGE_THROW_ERROR(Exception, "texture with zero channels");
92+
if (it.images.parts[0].image->channels() > 4)
93+
CAGE_THROW_ERROR(Exception, "texture with too many channels");
7794
switch (it.type)
7895
{
7996
case MeshImportTextureType::None:
8097
{
8198
CAGE_THROW_ERROR(Exception, "invalid texture type");
99+
break;
82100
}
83101
case MeshImportTextureType::Albedo:
84102
{
85-
if (it.images.parts[0].image->channels() > 4)
86-
CAGE_THROW_ERROR(Exception, "too many channels for albedo texture");
103+
switch (it.images.parts[0].image->channels())
104+
{
105+
case 1:
106+
break;
107+
case 2:
108+
CAGE_THROW_ERROR(Exception, "albedo cannot have 2 channels");
109+
break;
110+
case 3:
111+
break;
112+
case 4:
113+
break;
114+
}
87115
break;
88116
}
89117
case MeshImportTextureType::Normal:
@@ -98,35 +126,47 @@ namespace cage
98126
case 3:
99127
break;
100128
case 4:
101-
limitChannels(it, 3);
129+
limitChannels(it, 3); // strip alpha
102130
break;
103-
default:
104-
CAGE_THROW_ERROR(Exception, "too many channels for normal texture");
105131
}
106132
break;
107133
}
108134
case MeshImportTextureType::Special:
109135
{
110-
if (it.images.parts[0].image->channels() > 4)
111-
CAGE_THROW_ERROR(Exception, "too many channels for special texture");
136+
switch (it.images.parts[0].image->channels())
137+
{
138+
case 1:
139+
break;
140+
case 2:
141+
expandChannels2To3(it); // prevent confusing RG with intensity+alpha
142+
break;
143+
case 3:
144+
break;
145+
case 4:
146+
break;
147+
}
112148
break;
113149
}
114150
case MeshImportTextureType::Custom:
115-
break; // no limits
151+
{
152+
// no limits
153+
break;
154+
}
116155
case MeshImportTextureType::AmbientOcclusion:
117156
{
118157
switch (it.images.parts[0].image->channels())
119158
{
120159
case 1:
121160
break;
161+
case 2:
162+
CAGE_THROW_ERROR(Exception, "ambient occlusion texture cannot have 2 channels");
163+
break;
122164
case 3:
123-
pickChannel(it, 0);
165+
pickChannel(it, 0); // extract from unreal texture
124166
break;
125167
case 4:
126-
pickChannel(it, 0);
168+
pickChannel(it, 0); // extract from unreal texture
127169
break;
128-
default:
129-
CAGE_THROW_ERROR(Exception, "unexpected channels count for ambient occlusion texture");
130170
}
131171
break;
132172
}
@@ -141,14 +181,15 @@ namespace cage
141181
{
142182
case 1:
143183
break;
184+
case 2:
185+
CAGE_THROW_ERROR(Exception, "bump texture cannot have 2 channels");
186+
break;
144187
case 3:
145188
pickChannel(it, 1);
146189
break;
147190
case 4:
148191
pickChannel(it, 1);
149192
break;
150-
default:
151-
CAGE_THROW_ERROR(Exception, "unexpected channels count for bump texture");
152193
}
153194
break;
154195
}
@@ -164,7 +205,7 @@ namespace cage
164205
case 1:
165206
break;
166207
case 3:
167-
averageChannels3To1(it);
208+
averageChannels3To1(it); // color to intensity
168209
break;
169210
default:
170211
CAGE_THROW_ERROR(Exception, "unexpected channels count for emission texture");
@@ -173,8 +214,7 @@ namespace cage
173214
}
174215
case MeshImportTextureType::GltfPbr:
175216
{
176-
if (it.images.parts[0].image->channels() > 4)
177-
CAGE_THROW_ERROR(Exception, "too many channels for gltf pbr texture");
217+
// all ok
178218
break;
179219
}
180220
case MeshImportTextureType::Mask:
@@ -194,14 +234,15 @@ namespace cage
194234
{
195235
case 1:
196236
break;
237+
case 2:
238+
CAGE_THROW_ERROR(Exception, "metallic texture cannot have 2 channels");
239+
break;
197240
case 3:
198-
pickChannel(it, 2);
241+
pickChannel(it, 2); // extract from unreal texture
199242
break;
200243
case 4:
201-
pickChannel(it, 2);
244+
pickChannel(it, 2); // extract from unreal texture
202245
break;
203-
default:
204-
CAGE_THROW_ERROR(Exception, "unexpected channels count for metallic texture");
205246
}
206247
break;
207248
}
@@ -212,13 +253,14 @@ namespace cage
212253
case 1:
213254
break;
214255
case 2:
215-
pickChannel(it, 1);
256+
pickChannel(it, 1); // extract from intensity+alpha texture
257+
break;
258+
case 3:
259+
CAGE_THROW_ERROR(Exception, "opacity texture cannot have 3 channels");
216260
break;
217261
case 4:
218-
pickChannel(it, 3);
262+
pickChannel(it, 3); // extract from color+alpha texture
219263
break;
220-
default:
221-
CAGE_THROW_ERROR(Exception, "unexpected channels count for opacity texture");
222264
}
223265
break;
224266
}
@@ -228,14 +270,15 @@ namespace cage
228270
{
229271
case 1:
230272
break;
273+
case 2:
274+
CAGE_THROW_ERROR(Exception, "roughness texture cannot have 2 channels");
275+
break;
231276
case 3:
232-
pickChannel(it, 1);
277+
pickChannel(it, 1); // extract from unreal texture
233278
break;
234279
case 4:
235-
pickChannel(it, 1);
280+
pickChannel(it, 1); // extract from unreal texture
236281
break;
237-
default:
238-
CAGE_THROW_ERROR(Exception, "unexpected channels count for roughness texture");
239282
}
240283
break;
241284
}
@@ -260,15 +303,16 @@ namespace cage
260303
switch (it.images.parts[0].image->channels())
261304
{
262305
case 1:
263-
expandChannels1To3(it);
306+
duplicateChannels1To3(it); // intensity to color
307+
break;
308+
case 2:
309+
CAGE_THROW_ERROR(Exception, "specular texture cannot have 2 channels");
264310
break;
265311
case 3:
266312
break;
267313
case 4:
268-
limitChannels(it, 3);
314+
limitChannels(it, 3); // strip alpha
269315
break;
270-
default:
271-
CAGE_THROW_ERROR(Exception, "too many channels for specular texture");
272316
}
273317
break;
274318
}
@@ -288,6 +332,19 @@ namespace cage
288332
return res;
289333
}
290334

335+
uint32 composingChannelsTop(PointerRange<Holder<Image>> channels)
336+
{
337+
uint32 top = 0;
338+
for (uint32 i = 0; i < channels.size(); i++)
339+
{
340+
if (channels[i])
341+
top = i + 1;
342+
}
343+
if (top == 2)
344+
top = 3; // prevent confusing RG with intensity+alpha
345+
return top;
346+
}
347+
291348
void composeAlbedoOpacity(PointerRangeHolder<MeshImportTexture> &textures)
292349
{
293350
const auto &find = [&](MeshImportTextureType type) -> const MeshImportTexture *
@@ -386,9 +443,12 @@ namespace cage
386443
channels[3] = std::move(em->images.parts[0].image);
387444
}
388445

446+
const uint32 top = composingChannelsTop(channels);
447+
CAGE_ASSERT(top > 0);
448+
389449
{
390450
ImageImportPart p;
391-
p.image = imageChannelsJoin(channels);
451+
p.image = imageChannelsJoin({ channels, channels + top });
392452
PointerRangeHolder<ImageImportPart> ps;
393453
ps.push_back(std::move(p));
394454
gltf->images.parts = std::move(ps);
@@ -414,6 +474,7 @@ namespace cage
414474
return;
415475
const Image *src = +spec->images.parts[0].image;
416476
const Vec2i res = src->resolution();
477+
CAGE_ASSERT(src->channels() == 3);
417478

418479
Holder<Image> ri = newImage();
419480
ri->initialize(res, 1, src->format());
@@ -459,7 +520,6 @@ namespace cage
459520
return;
460521

461522
Holder<Image> channels[4];
462-
uint32 top = 0;
463523
String base;
464524
String names;
465525

@@ -476,7 +536,6 @@ namespace cage
476536
if (!names.empty())
477537
names += "_";
478538
names += n;
479-
top = cage::max(top, index + 1);
480539
};
481540

482541
for (auto &it : textures)
@@ -500,18 +559,21 @@ namespace cage
500559
}
501560
}
502561

562+
const uint32 top = composingChannelsTop(channels);
503563
if (top == 0)
504564
return;
505565

506-
ImageImportPart part;
507-
part.image = imageChannelsJoin({ channels, channels + top });
508-
PointerRangeHolder<ImageImportPart> parts;
509-
parts.push_back(std::move(part));
510-
MeshImportTexture res;
511-
res.images.parts = std::move(parts);
512-
res.name = Stringizer() + base + "?special_" + names;
513-
res.type = MeshImportTextureType::Special;
514-
textures.push_back(std::move(res));
566+
{
567+
ImageImportPart part;
568+
part.image = imageChannelsJoin({ channels, channels + top });
569+
PointerRangeHolder<ImageImportPart> parts;
570+
parts.push_back(std::move(part));
571+
MeshImportTexture res;
572+
res.images.parts = std::move(parts);
573+
res.name = Stringizer() + base + "?special_" + names;
574+
res.type = MeshImportTextureType::Special;
575+
textures.push_back(std::move(res));
576+
}
515577
}
516578

517579
void filterTextures(PointerRangeHolder<MeshImportTexture> &textures)

0 commit comments

Comments
 (0)