Merge 2b94b87a96
into 739ee5db94
This commit is contained in:
commit
47b95eabe0
|
@ -5,3 +5,8 @@ npm/fbx2gltf/node_modules/
|
||||||
npm/tests/node_modules/
|
npm/tests/node_modules/
|
||||||
npm/tests/test/*.js
|
npm/tests/test/*.js
|
||||||
npm/tests/test/*.js.map
|
npm/tests/test/*.js.map
|
||||||
|
build
|
||||||
|
sdk
|
||||||
|
.vscode
|
||||||
|
Pipfile
|
||||||
|
Pipfile.lock
|
||||||
|
|
13
README.md
13
README.md
|
@ -308,6 +308,19 @@ that route should be digested propertly by FBX2glTF.
|
||||||
(A happy note: Allegorithmic's Substance Painter also exports Stingray PBS,
|
(A happy note: Allegorithmic's Substance Painter also exports Stingray PBS,
|
||||||
when hooked up to Maya.)
|
when hooked up to Maya.)
|
||||||
|
|
||||||
|
When processing PBR materials, this converter will always pack Occlusion,
|
||||||
|
Roughness, and Metallness into a single combined ORM texture, with each parameter
|
||||||
|
being in the R, G and, B channels respectively. If you specify a texture in any
|
||||||
|
of the Stingray material slots, a full ORM will be generated; if you leave all 3
|
||||||
|
blank, then no ORM texture will be assigned.
|
||||||
|
|
||||||
|
* Should you specify different textures for each, then they will
|
||||||
|
be merged into their respective channels. Any missing textures will be
|
||||||
|
defaulted to: Occlusion 1, Roughness 0, and Metallness 0. Note, all textures
|
||||||
|
must have the same dimensions.
|
||||||
|
* Should you specify the same texture in all 3 slots, then the texture will
|
||||||
|
be assumed to already be a packed ORM, and will be used as-is.
|
||||||
|
|
||||||
## Draco Compression
|
## Draco Compression
|
||||||
|
|
||||||
The tool will optionally apply [Draco](https://github.com/google/draco)
|
The tool will optionally apply [Draco](https://github.com/google/draco)
|
||||||
|
|
|
@ -261,41 +261,96 @@ ModelData* Raw2Gltf(
|
||||||
*/
|
*/
|
||||||
RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
|
RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
|
||||||
|
|
||||||
// determine if we need to generate a combined map
|
// determine if we need to generate a combined map, or if we only have 1 map to pass through
|
||||||
bool hasMetallicMap = material.textures[RAW_TEXTURE_USAGE_METALLIC] >= 0;
|
bool hasMetallicMap = material.textures[RAW_TEXTURE_USAGE_METALLIC] >= 0;
|
||||||
bool hasRoughnessMap = material.textures[RAW_TEXTURE_USAGE_ROUGHNESS] >= 0;
|
bool hasRoughnessMap = material.textures[RAW_TEXTURE_USAGE_ROUGHNESS] >= 0;
|
||||||
bool hasOcclusionMap = material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0;
|
bool hasOcclusionMap = material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0;
|
||||||
bool atLeastTwoMaps = hasMetallicMap ? (hasRoughnessMap || hasOcclusionMap)
|
|
||||||
: (hasRoughnessMap && hasMetallicMap);
|
auto texturesAreSame = [&](RawTextureUsage a, RawTextureUsage b) -> bool {
|
||||||
if (!atLeastTwoMaps) {
|
// note: at this point the usages will be different, so we can't just compare indexes
|
||||||
// this handles the case of 0 or 1 maps supplied
|
return StringUtils::CompareNoCase(
|
||||||
|
raw.GetTexture(material.textures[a]).fileLocation,
|
||||||
|
raw.GetTexture(material.textures[b]).fileLocation ) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isPassThroughTexture = hasOcclusionMap && hasRoughnessMap && hasMetallicMap;
|
||||||
|
if (isPassThroughTexture) {
|
||||||
|
isPassThroughTexture =
|
||||||
|
texturesAreSame(RAW_TEXTURE_USAGE_METALLIC, RAW_TEXTURE_USAGE_ROUGHNESS) &&
|
||||||
|
texturesAreSame(RAW_TEXTURE_USAGE_METALLIC, RAW_TEXTURE_USAGE_OCCLUSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto textureName = [&](RawTextureUsage usage){
|
||||||
|
int index = material.textures[usage];
|
||||||
|
if (index >= 0) {
|
||||||
|
return raw.GetTexture(index).name.c_str();
|
||||||
|
} else {
|
||||||
|
return "<empty>";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!(hasMetallicMap || hasRoughnessMap || hasOcclusionMap)) {
|
||||||
|
// no data, assume it's a material that just relies on the uniform properties
|
||||||
|
aoMetRoughTex = nullptr;
|
||||||
|
if (verboseOutput) {
|
||||||
|
fmt::printf("Material %s: no ORM textures detected\n", material.name.c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isPassThroughTexture) {
|
||||||
|
// this handles the case where the same map is assigned to all the channels
|
||||||
aoMetRoughTex = hasMetallicMap
|
aoMetRoughTex = hasMetallicMap
|
||||||
? simpleTex(RAW_TEXTURE_USAGE_METALLIC)
|
? simpleTex(RAW_TEXTURE_USAGE_METALLIC)
|
||||||
: (hasRoughnessMap
|
: (hasRoughnessMap
|
||||||
? simpleTex(RAW_TEXTURE_USAGE_ROUGHNESS)
|
? simpleTex(RAW_TEXTURE_USAGE_ROUGHNESS)
|
||||||
: (hasOcclusionMap ? simpleTex(RAW_TEXTURE_USAGE_OCCLUSION) : nullptr));
|
: (hasOcclusionMap
|
||||||
|
? simpleTex(RAW_TEXTURE_USAGE_OCCLUSION)
|
||||||
|
: nullptr));
|
||||||
|
if (verboseOutput) {
|
||||||
|
if (aoMetRoughTex) {
|
||||||
|
fmt::printf("Material %s: detected single ORM texture: %s\n", material.name.c_str(), aoMetRoughTex->name.c_str());
|
||||||
|
} else {
|
||||||
|
fmt::printf("Material %s: no ORM textures detected\n", material.name.c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// otherwise merge occlusion into the red channel, metallic into blue channel, and
|
/* otherwise we always have to create a new texture that merges
|
||||||
// roughness into the green, of a new combinatory texture
|
* occlusion into the red channel
|
||||||
|
* roughness into the green
|
||||||
|
* metallic into blue channel
|
||||||
|
* with defaults for any unspecified channels
|
||||||
|
*/
|
||||||
aoMetRoughTex = textureBuilder.combine(
|
aoMetRoughTex = textureBuilder.combine(
|
||||||
{
|
{
|
||||||
material.textures[RAW_TEXTURE_USAGE_OCCLUSION],
|
material.textures[RAW_TEXTURE_USAGE_OCCLUSION],
|
||||||
material.textures[RAW_TEXTURE_USAGE_METALLIC],
|
|
||||||
material.textures[RAW_TEXTURE_USAGE_ROUGHNESS],
|
material.textures[RAW_TEXTURE_USAGE_ROUGHNESS],
|
||||||
|
material.textures[RAW_TEXTURE_USAGE_METALLIC],
|
||||||
},
|
},
|
||||||
"ao_met_rough",
|
"ao_met_rough",
|
||||||
[&](const std::vector<const TextureBuilder::pixel*> pixels)
|
[&](const std::vector<const TextureBuilder::pixel*> pixels)
|
||||||
-> TextureBuilder::pixel {
|
-> TextureBuilder::pixel {
|
||||||
const float occlusion = (*pixels[0])[0];
|
/**
|
||||||
const float metallic = (*pixels[1])[0] * (hasMetallicMap ? 1 : props->metallic);
|
* note: we're picking the channels from the sources aligned with where they're going
|
||||||
const float roughness =
|
* just in case they were authored that way. This makes an existing ORM texture
|
||||||
(*pixels[2])[0] * (hasRoughnessMap ? 1 : props->roughness);
|
* "pass through", and has no effect on a grey single type texture.
|
||||||
|
*/
|
||||||
|
const float occlusion = hasOcclusionMap ? (*pixels[0])[0] : 1;
|
||||||
|
const float roughness = (*pixels[1])[1] * (hasRoughnessMap ? 1 : props->roughness);
|
||||||
|
const float metallic = (*pixels[2])[2] * (hasMetallicMap ? 1 : props->metallic);
|
||||||
return {{occlusion,
|
return {{occlusion,
|
||||||
props->invertRoughnessMap ? 1.0f - roughness : roughness,
|
props->invertRoughnessMap ? 1.0f - roughness : roughness,
|
||||||
metallic,
|
metallic,
|
||||||
1}};
|
1}};
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
|
if ( aoMetRoughTex && verboseOutput ) {
|
||||||
|
fmt::printf("Material %s: detected multiple ORM textures, combined: [%s, %s, %s] into [%s]\n",
|
||||||
|
material.name.c_str(),
|
||||||
|
textureName(RAW_TEXTURE_USAGE_OCCLUSION),
|
||||||
|
textureName(RAW_TEXTURE_USAGE_ROUGHNESS),
|
||||||
|
textureName(RAW_TEXTURE_USAGE_METALLIC),
|
||||||
|
aoMetRoughTex->name.c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
||||||
diffuseFactor = props->diffuseFactor;
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
|
Loading…
Reference in New Issue