Dramatic sweeping material changes.
This commit is contained in:
parent
d67722a5d7
commit
de1de9ef8f
|
@ -257,7 +257,7 @@ struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name = fbxMaterial->GetName();
|
std::string name = fbxMaterial->GetName();
|
||||||
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->sShadingModel));
|
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
|
||||||
|
|
||||||
// four properties are on the same structure and follow the same rules
|
// four properties are on the same structure and follow the same rules
|
||||||
auto handleBasicProperty = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{
|
auto handleBasicProperty = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{
|
||||||
|
@ -768,22 +768,20 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
||||||
|
|
||||||
for (int polygonIndex = 0; polygonIndex < pMesh->GetPolygonCount(); polygonIndex++) {
|
for (int polygonIndex = 0; polygonIndex < pMesh->GetPolygonCount(); polygonIndex++) {
|
||||||
FBX_ASSERT(pMesh->GetPolygonSize(polygonIndex) == 3);
|
FBX_ASSERT(pMesh->GetPolygonSize(polygonIndex) == 3);
|
||||||
|
|
||||||
int textures[RAW_TEXTURE_USAGE_MAX] { -1 };
|
|
||||||
std::fill_n(textures, RAW_TEXTURE_USAGE_MAX, -1);
|
|
||||||
|
|
||||||
FbxString shadingModel, materialName;
|
|
||||||
FbxVector4 ambient, specular, diffuse, emissive;
|
|
||||||
FbxDouble shininess, emissiveIntensity, metallic, roughness;
|
|
||||||
|
|
||||||
const std::shared_ptr<FbxMaterialInfo> fbxMaterial = materials.GetMaterial(polygonIndex);
|
const std::shared_ptr<FbxMaterialInfo> fbxMaterial = materials.GetMaterial(polygonIndex);
|
||||||
|
|
||||||
|
int textures[RAW_TEXTURE_USAGE_MAX];
|
||||||
|
std::fill_n(textures, RAW_TEXTURE_USAGE_MAX, -1);
|
||||||
|
FbxString materialName;
|
||||||
|
std::shared_ptr<RawMatProps> rawMatProps;
|
||||||
|
|
||||||
if (fbxMaterial == nullptr) {
|
if (fbxMaterial == nullptr) {
|
||||||
materialName = "DefaultMaterial";
|
materialName = "DefaultMaterial";
|
||||||
shadingModel = "Lambert";
|
rawMatProps.reset(new RawTraditionalMatProps(RAW_SHADING_MODEL_LAMBERT,
|
||||||
|
Vec3f(0, 0, 0), Vec4f(.5, .5, .5, 1), Vec3f(0, 0, 0), Vec3f(0, 0, 0), 0.5));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
materialName = fbxMaterial->name;
|
materialName = fbxMaterial->name;
|
||||||
shadingModel = fbxMaterial->shadingModel;
|
|
||||||
|
|
||||||
const auto maybeAddTexture = [&](const FbxFileTexture *tex, RawTextureUsage usage) {
|
const auto maybeAddTexture = [&](const FbxFileTexture *tex, RawTextureUsage usage) {
|
||||||
if (tex != nullptr) {
|
if (tex != nullptr) {
|
||||||
|
@ -793,37 +791,44 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shadingModel == FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH) {
|
std::shared_ptr<RawMatProps> matInfo;
|
||||||
FbxRoughMetMaterialInfo *matProps = static_cast<FbxRoughMetMaterialInfo *>(fbxMaterial.get());
|
if (fbxMaterial->shadingModel == FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH) {
|
||||||
|
FbxRoughMetMaterialInfo *fbxMatInfo = static_cast<FbxRoughMetMaterialInfo *>(fbxMaterial.get());
|
||||||
|
|
||||||
maybeAddTexture(matProps->texColor, RAW_TEXTURE_USAGE_ALBEDO);
|
maybeAddTexture(fbxMatInfo->texColor, RAW_TEXTURE_USAGE_ALBEDO);
|
||||||
diffuse = matProps->colBase;
|
maybeAddTexture(fbxMatInfo->texNormal, RAW_TEXTURE_USAGE_NORMAL);
|
||||||
maybeAddTexture(matProps->texNormal, RAW_TEXTURE_USAGE_NORMAL);
|
maybeAddTexture(fbxMatInfo->texEmissive, RAW_TEXTURE_USAGE_EMISSIVE);
|
||||||
maybeAddTexture(matProps->texEmissive, RAW_TEXTURE_USAGE_EMISSIVE);
|
maybeAddTexture(fbxMatInfo->texRoughness, RAW_TEXTURE_USAGE_ROUGHNESS);
|
||||||
emissive = matProps->colEmissive;
|
maybeAddTexture(fbxMatInfo->texMetallic, RAW_TEXTURE_USAGE_METALLIC);
|
||||||
emissiveIntensity = matProps->emissiveIntensity;
|
maybeAddTexture(fbxMatInfo->texAmbientOcclusion, RAW_TEXTURE_USAGE_OCCLUSION);
|
||||||
maybeAddTexture(matProps->texRoughness, RAW_TEXTURE_USAGE_ROUGHNESS);
|
rawMatProps.reset(new RawMetRoughMatProps(
|
||||||
maybeAddTexture(matProps->texMetallic, RAW_TEXTURE_USAGE_METALLIC);
|
RAW_SHADING_MODEL_PBR_MET_ROUGH, toVec4f(fbxMatInfo->colBase), toVec3f(fbxMatInfo->colEmissive),
|
||||||
metallic = matProps->metallic;
|
fbxMatInfo->emissiveIntensity, fbxMatInfo->metallic, fbxMatInfo->roughness));
|
||||||
maybeAddTexture(matProps->texAmbientOcclusion, RAW_TEXTURE_USAGE_OCCLUSION);
|
|
||||||
roughness = matProps->roughness;
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
FbxTraditionalMaterialInfo *matProps = static_cast<FbxTraditionalMaterialInfo *>(fbxMaterial.get());
|
FbxTraditionalMaterialInfo *fbxMatInfo = static_cast<FbxTraditionalMaterialInfo *>(fbxMaterial.get());
|
||||||
|
RawShadingModel shadingModel;
|
||||||
maybeAddTexture(matProps->texDiffuse, RAW_TEXTURE_USAGE_DIFFUSE);
|
if (fbxMaterial->shadingModel == "Lambert") {
|
||||||
diffuse = matProps->colDiffuse;
|
shadingModel = RAW_SHADING_MODEL_LAMBERT;
|
||||||
maybeAddTexture(matProps->texNormal, RAW_TEXTURE_USAGE_NORMAL);
|
} else if (fbxMaterial->shadingModel == "Blinn") {
|
||||||
maybeAddTexture(matProps->texEmissive, RAW_TEXTURE_USAGE_EMISSIVE);
|
shadingModel = RAW_SHADING_MODEL_BLINN;
|
||||||
emissive = matProps->colEmissive;
|
} else if (fbxMaterial->shadingModel == "Phong") {
|
||||||
maybeAddTexture(matProps->texShininess, RAW_TEXTURE_USAGE_SHININESS);
|
shadingModel = RAW_SHADING_MODEL_PHONG;
|
||||||
shininess = matProps->shininess;
|
} else if (fbxMaterial->shadingModel == "Constant") {
|
||||||
maybeAddTexture(matProps->texAmbient, RAW_TEXTURE_USAGE_AMBIENT);
|
shadingModel = RAW_SHADING_MODEL_PHONG;
|
||||||
ambient = matProps->colAmbient;
|
} else {
|
||||||
maybeAddTexture(matProps->texSpecular, RAW_TEXTURE_USAGE_SPECULAR);
|
shadingModel = RAW_SHADING_MODEL_UNKNOWN;
|
||||||
specular = matProps->colSpecular;
|
}
|
||||||
|
maybeAddTexture(fbxMatInfo->texDiffuse, RAW_TEXTURE_USAGE_DIFFUSE);
|
||||||
|
maybeAddTexture(fbxMatInfo->texNormal, RAW_TEXTURE_USAGE_NORMAL);
|
||||||
|
maybeAddTexture(fbxMatInfo->texEmissive, RAW_TEXTURE_USAGE_EMISSIVE);
|
||||||
|
maybeAddTexture(fbxMatInfo->texShininess, RAW_TEXTURE_USAGE_SHININESS);
|
||||||
|
maybeAddTexture(fbxMatInfo->texAmbient, RAW_TEXTURE_USAGE_AMBIENT);
|
||||||
|
maybeAddTexture(fbxMatInfo->texSpecular, RAW_TEXTURE_USAGE_SPECULAR);
|
||||||
|
rawMatProps.reset(new RawTraditionalMatProps(shadingModel,
|
||||||
|
toVec3f(fbxMatInfo->colAmbient), toVec4f(fbxMatInfo->colDiffuse), toVec3f(fbxMatInfo->colEmissive),
|
||||||
|
toVec3f(fbxMatInfo->colSpecular), fbxMatInfo->shininess));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RawVertex rawVertices[3];
|
RawVertex rawVertices[3];
|
||||||
|
@ -951,10 +956,7 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
||||||
}
|
}
|
||||||
|
|
||||||
const RawMaterialType materialType = GetMaterialType(raw, textures, vertexTransparency, skinning.IsSkinned());
|
const RawMaterialType materialType = GetMaterialType(raw, textures, vertexTransparency, skinning.IsSkinned());
|
||||||
const int rawMaterialIndex = raw.AddMaterial(
|
const int rawMaterialIndex = raw.AddMaterial(materialName, materialType, textures, rawMatProps);
|
||||||
materialName, shadingModel, materialType, textures,
|
|
||||||
toVec3f(ambient), toVec4f(diffuse), toVec3f(specular), toVec3f(emissive),
|
|
||||||
emissiveIntensity, shininess, metallic, roughness);
|
|
||||||
|
|
||||||
raw.AddTriangle(rawVertexIndices[0], rawVertexIndices[1], rawVertexIndices[2], rawMaterialIndex, rawSurfaceIndex);
|
raw.AddTriangle(rawVertexIndices[0], rawVertexIndices[1], rawVertexIndices[2], rawMaterialIndex, rawSurfaceIndex);
|
||||||
}
|
}
|
||||||
|
|
441
src/Raw2Gltf.cpp
441
src/Raw2Gltf.cpp
|
@ -273,7 +273,7 @@ ModelData *Raw2Gltf(
|
||||||
for (int i = 0; i < raw.GetMaterialCount(); i++) {
|
for (int i = 0; i < raw.GetMaterialCount(); i++) {
|
||||||
fmt::printf(
|
fmt::printf(
|
||||||
"Material %d: %s [shading: %s]\n", i, raw.GetMaterial(i).name.c_str(),
|
"Material %d: %s [shading: %s]\n", i, raw.GetMaterial(i).name.c_str(),
|
||||||
raw.GetMaterial(i).shadingModel.c_str());
|
Describe(raw.GetMaterial(i).info->shadingModel));
|
||||||
}
|
}
|
||||||
if (raw.GetVertexCount() > 2 * raw.GetTriangleCount()) {
|
if (raw.GetVertexCount() > 2 * raw.GetTriangleCount()) {
|
||||||
fmt::printf(
|
fmt::printf(
|
||||||
|
@ -298,7 +298,7 @@ ModelData *Raw2Gltf(
|
||||||
std::map<std::string, std::shared_ptr<NodeData>> nodesByName;
|
std::map<std::string, std::shared_ptr<NodeData>> nodesByName;
|
||||||
std::map<std::string, std::shared_ptr<MaterialData>> materialsByName;
|
std::map<std::string, std::shared_ptr<MaterialData>> materialsByName;
|
||||||
std::map<std::string, std::shared_ptr<MeshData>> meshByNodeName;
|
std::map<std::string, std::shared_ptr<MeshData>> meshByNodeName;
|
||||||
std::map<int, std::shared_ptr<TextureData>> textureByRawIndex;
|
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
|
||||||
|
|
||||||
// for now, we only have one buffer; data->binary points to the same vector as that BufferData does.
|
// for now, we only have one buffer; data->binary points to the same vector as that BufferData does.
|
||||||
BufferData &buffer = *gltf->buffers.hold(
|
BufferData &buffer = *gltf->buffers.hold(
|
||||||
|
@ -383,25 +383,36 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
// textures
|
// textures
|
||||||
//
|
//
|
||||||
typedef std::array<uint8_t, 4> pixel;
|
typedef std::array<float, 4> pixel; // pixel components are floats in [0, 1]
|
||||||
typedef std::function<pixel(const pixel &, const pixel &)> pixel_merger;
|
typedef std::function<pixel(const std::vector<const pixel *>)> pixel_merger;
|
||||||
|
|
||||||
|
auto texIndicesKey = [&](std::vector<int> ixVec, std::string tag) -> std::string {
|
||||||
|
std::string result = tag;
|
||||||
|
for (int ix : ixVec) {
|
||||||
|
result += "_";
|
||||||
|
result += ix;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new derived TextureData for the two given RawTexture indexes, or return a previously created one.
|
* Create a new derived TextureData for the two given RawTexture indexes, or return a previously created one.
|
||||||
* Each pixel in the derived texture will be determined from its equivalent in each source pixels, as decided
|
* Each pixel in the derived texture will be determined from its equivalent in each source pixels, as decided
|
||||||
* by the provided `combine` function.
|
* by the provided `combine` function.
|
||||||
*/
|
*/
|
||||||
auto getDerivedTexture = [&](int rawTexIx1, int rawTexIx2, const pixel_merger &combine) -> std::shared_ptr<TextureData> {
|
auto getDerivedTexture = [&](
|
||||||
// TODO: index on first texture? what if it's -1?
|
std::vector<int> rawTexIndices,
|
||||||
auto iter = textureByRawIndex.find(rawTexIx1);
|
const pixel_merger &combine,
|
||||||
if (iter != textureByRawIndex.end()) {
|
const std::string &tag
|
||||||
|
) -> std::shared_ptr<TextureData>
|
||||||
|
{
|
||||||
|
const std::string key = texIndicesKey(rawTexIndices, tag);
|
||||||
|
auto iter = textureByIndicesKey.find(key);
|
||||||
|
if (iter != textureByIndicesKey.end()) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RawTexture &rawTex1 = raw.GetTexture(rawTexIx1);
|
auto describeChannel = [&](int channels) -> std::string {
|
||||||
const RawTexture &rawTex2 = raw.GetTexture(rawTexIx2);
|
|
||||||
|
|
||||||
auto channelStr = [&](int channels) -> std::string {
|
|
||||||
switch(channels) {
|
switch(channels) {
|
||||||
case 1: return "G";
|
case 1: return "G";
|
||||||
case 2: return "GA";
|
case 2: return "GA";
|
||||||
|
@ -412,60 +423,99 @@ ModelData *Raw2Gltf(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int w1, h1, c1;
|
// keep track of some texture data as we load them
|
||||||
uint8_t *s1 = stbi_load(rawTex1.fileLocation.c_str(), &w1, &h1, &c1, 4);
|
struct TexInfo {
|
||||||
if (!s1) {
|
explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {}
|
||||||
fmt::printf("Warning: merge texture 1 (%s) could not be loaded.\n", rawTex1.fileName);
|
|
||||||
return nullptr;
|
const int rawTexIx;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int channels;
|
||||||
|
uint8_t *pixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
int width = -1, height = -1;
|
||||||
|
std::string mergedName = tag;
|
||||||
|
std::string mergedFilename = tag;
|
||||||
|
std::vector<TexInfo> texes { };
|
||||||
|
for (const int rawTexIx : rawTexIndices) {
|
||||||
|
TexInfo info(rawTexIx);
|
||||||
|
if (rawTexIx >= 0) {
|
||||||
|
const RawTexture &rawTex = raw.GetTexture(rawTexIx);
|
||||||
|
const std::string &fileLoc = rawTex.fileLocation;
|
||||||
|
const std::string &fileLocBase = Gltf::StringUtils::GetFileBaseString(Gltf::StringUtils::GetFileNameString(fileLoc));
|
||||||
|
if (!fileLoc.empty()) {
|
||||||
|
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 4);
|
||||||
|
if (!info.pixels) {
|
||||||
|
fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n",
|
||||||
|
rawTexIx,
|
||||||
|
Gltf::StringUtils::GetFileBaseString(Gltf::StringUtils::GetFileNameString(fileLoc)));
|
||||||
|
} else {
|
||||||
|
if (width < 0) {
|
||||||
|
width = info.width;
|
||||||
|
height = info.height;
|
||||||
|
} else if (width != info.width || height != info.height) {
|
||||||
|
fmt::printf("Warning: texture %s (%d, %d) can't be merged with previous texture(s) of dimension (%d, %d)\n",
|
||||||
|
Gltf::StringUtils::GetFileBaseString(Gltf::StringUtils::GetFileNameString(fileLoc)),
|
||||||
|
info.width, info.height, width, height);
|
||||||
|
// this is bad enough that we abort the whole merge
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
mergedName += "_" + rawTex.fileName;
|
||||||
|
mergedFilename += "_" + fileLocBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
texes.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
int w2, h2, c2;
|
if (width < 0) {
|
||||||
uint8_t *s2 = stbi_load(rawTex2.fileLocation.c_str(), &w2, &h2, &c2, 4);
|
// no textures to merge; bail
|
||||||
if (!s2) {
|
|
||||||
fmt::printf("Warning: merge texture 2 (%s) could not be loaded.\n", rawTex2.fileName);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w1 != w2 || h1 != h2) {
|
|
||||||
fmt::printf("Warning: textures %s and %s have different dimensions and can't be combined\n",
|
|
||||||
rawTex1.fileName, rawTex2.fileName);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// TODO: which channel combinations make sense in input files?
|
// TODO: which channel combinations make sense in input files?
|
||||||
|
|
||||||
std::vector<uint8_t > mergedPixels(4 * w1 * h1);
|
std::vector<uint8_t > mergedPixels(4 * width * height);
|
||||||
|
std::vector<pixel> pixels(texes.size());
|
||||||
|
std::vector<const pixel *> pixelPointers(texes.size());
|
||||||
for (int ii = 0; ii < mergedPixels.size(); ii += 4) {
|
for (int ii = 0; ii < mergedPixels.size(); ii += 4) {
|
||||||
pixel merged = combine(
|
pixels.clear();
|
||||||
pixel { s1[ii+0], s1[ii+1], s1[ii+2], s1[ii+3] },
|
for (int jj = 0; jj < texes.size(); jj ++) {
|
||||||
pixel { s2[ii+0], s2[ii+1], s2[ii+2], s2[ii+3] });
|
const TexInfo &tex = texes[jj];
|
||||||
|
if (tex.pixels != nullptr) {
|
||||||
|
pixels[jj] = { tex.pixels[ii+0]/255.0f, tex.pixels[ii+1]/255.0f, tex.pixels[ii+2]/255.0f, tex.pixels[ii+3]/255.0f };
|
||||||
|
} else {
|
||||||
|
// absent textures are to be treated as all ones
|
||||||
|
pixels[jj] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
}
|
||||||
|
pixelPointers[jj] = &pixels[jj];
|
||||||
|
}
|
||||||
|
const pixel &merged = combine(pixelPointers);
|
||||||
for (int jj = 0; jj < 4; jj ++) {
|
for (int jj = 0; jj < 4; jj ++) {
|
||||||
mergedPixels[ii + jj] = merged[jj];
|
mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool png = false;
|
bool png = true;
|
||||||
std::vector<char> imgBuffer;
|
std::vector<char> imgBuffer;
|
||||||
int res;
|
int res;
|
||||||
if (png) {
|
if (png) {
|
||||||
res = stbi_write_png_to_func(WriteToVectorContext<char>, &imgBuffer, w1, h1, 4, mergedPixels.data(), w1 * 4);
|
res = stbi_write_png_to_func(WriteToVectorContext<char>, &imgBuffer, width, height, 4, mergedPixels.data(), width * 4);
|
||||||
} else {
|
} else {
|
||||||
res = stbi_write_jpg_to_func(WriteToVectorContext<char>, &imgBuffer, w1, h1, 4, mergedPixels.data(), 80);
|
res = stbi_write_jpg_to_func(WriteToVectorContext<char>, &imgBuffer, width, height, 4, mergedPixels.data(), 80);
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
assert(res != 0);
|
|
||||||
|
|
||||||
const std::string name = "merge_" + rawTex1.name + "_" + rawTex2.name;
|
|
||||||
const std::string fileName = "merge_" +
|
|
||||||
Gltf::StringUtils::GetFileBaseString(Gltf::StringUtils::GetFileNameString(rawTex1.fileLocation)) + "_" +
|
|
||||||
Gltf::StringUtils::GetFileBaseString(Gltf::StringUtils::GetFileNameString(rawTex2.fileLocation));
|
|
||||||
|
|
||||||
ImageData *image;
|
ImageData *image;
|
||||||
if (options.outputBinary) {
|
if (options.outputBinary) {
|
||||||
const auto bufferView = gltf->AddRawBufferView(buffer, imgBuffer.data(), imgBuffer.size());
|
const auto bufferView = gltf->AddRawBufferView(buffer, imgBuffer.data(), imgBuffer.size());
|
||||||
image = new ImageData(name, *bufferView, png ? "image/png" : "image/jpeg");
|
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const std::string imageFilename = fileName + (png ? ".png" : ".jpg");
|
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
|
||||||
const std::string imagePath = outputFolder + imageFilename;
|
const std::string imagePath = outputFolder + imageFilename;
|
||||||
FILE *fp = fopen(imagePath.c_str(), "wb");
|
FILE *fp = fopen(imagePath.c_str(), "wb");
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
|
@ -483,19 +533,20 @@ ModelData *Raw2Gltf(
|
||||||
fmt::printf("Wrote %lu bytes to texture '%s'.\n", imgBuffer.size(), imagePath);
|
fmt::printf("Wrote %lu bytes to texture '%s'.\n", imgBuffer.size(), imagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
image = new ImageData(name, imageFilename);
|
image = new ImageData(mergedName, imageFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TextureData> texDat = gltf->textures.hold(
|
std::shared_ptr<TextureData> texDat = gltf->textures.hold(
|
||||||
new TextureData(name, defaultSampler, *gltf->images.hold(image)));
|
new TextureData(mergedName, defaultSampler, *gltf->images.hold(image)));
|
||||||
textureByRawIndex.insert(std::make_pair(rawTexIx1, texDat));
|
textureByIndicesKey.insert(std::make_pair(key, texDat));
|
||||||
return texDat;
|
return texDat;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Create a new TextureData for the given RawTexture index, or return a previously created one. */
|
/** Create a new TextureData for the given RawTexture index, or return a previously created one. */
|
||||||
auto getSimpleTexture = [&](int rawTexIndex) {
|
auto getSimpleTexture = [&](int rawTexIndex, const std::string &tag) {
|
||||||
auto iter = textureByRawIndex.find(rawTexIndex);
|
const std::string key = texIndicesKey({ rawTexIndex }, tag);
|
||||||
if (iter != textureByRawIndex.end()) {
|
auto iter = textureByIndicesKey.find(key);
|
||||||
|
if (iter != textureByIndicesKey.end()) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +582,7 @@ ModelData *Raw2Gltf(
|
||||||
|
|
||||||
std::shared_ptr<TextureData> texDat = gltf->textures.hold(
|
std::shared_ptr<TextureData> texDat = gltf->textures.hold(
|
||||||
new TextureData(textureName, defaultSampler, *gltf->images.hold(image)));
|
new TextureData(textureName, defaultSampler, *gltf->images.hold(image)));
|
||||||
textureByRawIndex.insert(std::make_pair(rawTexIndex, texDat));
|
textureByIndicesKey.insert(std::make_pair(key, texDat));
|
||||||
return texDat;
|
return texDat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -545,59 +596,289 @@ ModelData *Raw2Gltf(
|
||||||
material.type == RAW_MATERIAL_TYPE_TRANSPARENT ||
|
material.type == RAW_MATERIAL_TYPE_TRANSPARENT ||
|
||||||
material.type == RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT;
|
material.type == RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT;
|
||||||
|
|
||||||
|
Vec3f emissiveFactor;
|
||||||
|
float emissiveIntensity;
|
||||||
|
|
||||||
|
const Vec3f dielectric(0.04f, 0.04f, 0.04f);
|
||||||
|
const float epsilon = 1e-6f;
|
||||||
|
|
||||||
// acquire the texture of a specific RawTextureUsage as *TextData, or nullptr if none exists
|
// acquire the texture of a specific RawTextureUsage as *TextData, or nullptr if none exists
|
||||||
auto simpleTex = [&](RawTextureUsage usage) -> const TextureData * {
|
auto simpleTex = [&](RawTextureUsage usage) -> std::shared_ptr<TextureData> {
|
||||||
return (material.textures[usage] >= 0) ? getSimpleTexture(material.textures[usage]).get() : nullptr;
|
return (material.textures[usage] >= 0) ? getSimpleTexture(material.textures[usage], "simple") : nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// acquire derived texture of two RawTextureUsage as *TextData, or nullptr if neither exists
|
// acquire derived texture of two RawTextureUsage as *TextData, or nullptr if neither exists
|
||||||
auto derivedTex = [&](RawTextureUsage u1, RawTextureUsage u2, const pixel_merger &combine) -> const TextureData * {
|
auto merge2Tex = [&](
|
||||||
int t1 = material.textures[u1], t2 = material.textures[u2];
|
const std::string tag,
|
||||||
return (t1 >= 0 || t2 >= 0) ? getDerivedTexture(t1, t2, combine).get() : nullptr;
|
RawTextureUsage u1,
|
||||||
|
RawTextureUsage u2,
|
||||||
|
const pixel_merger &combine
|
||||||
|
) -> std::shared_ptr<TextureData> {
|
||||||
|
return getDerivedTexture({ material.textures[u1], material.textures[u2] }, combine, tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
// acquire derived texture of two RawTextureUsage as *TextData, or nullptr if neither exists
|
||||||
|
auto merge3Tex = [&](
|
||||||
|
const std::string tag,
|
||||||
|
RawTextureUsage u1,
|
||||||
|
RawTextureUsage u2,
|
||||||
|
RawTextureUsage u3,
|
||||||
|
const pixel_merger &combine
|
||||||
|
) -> std::shared_ptr<TextureData> {
|
||||||
|
return getDerivedTexture({ material.textures[u1], material.textures[u2], material.textures[u3] }, combine, tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getMaxComponent = [&](const Vec3f &color) {
|
||||||
|
return fmax(color.x, fmax(color.y, color.z));
|
||||||
|
};
|
||||||
|
auto getPerceivedBrightness = [&](const Vec3f &color) {
|
||||||
|
return sqrt(0.299 * color.x * color.x + 0.587 * color.y * color.y + 0.114 * color.z * color.z);
|
||||||
|
};
|
||||||
|
auto toVec3f = [&](const pixel &pix) -> const Vec3f {
|
||||||
|
return Vec3f(pix[0], pix[1], pix[2]);
|
||||||
|
};
|
||||||
|
auto toVec4f = [&](const pixel &pix) -> const Vec4f {
|
||||||
|
return Vec4f(pix[0], pix[1], pix[2], pix[3]);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<PBRMetallicRoughness> pbrMetRough;
|
std::shared_ptr<PBRMetallicRoughness> pbrMetRough;
|
||||||
if (options.usePBRMetRough) {
|
if (options.usePBRMetRough) {
|
||||||
// merge metallic into the blue channel and roughness into the green, of a new combinatory texture
|
// albedo is a basic texture, no merging needed
|
||||||
const TextureData *metRoughTex = derivedTex(
|
std::shared_ptr<TextureData> baseColorTex, metRoughTex;
|
||||||
RAW_TEXTURE_USAGE_METALLIC, RAW_TEXTURE_USAGE_ROUGHNESS,
|
|
||||||
[&](const pixel &met, const pixel &rough) -> pixel { return { 0, rough[0], met[0], 0 }; });
|
|
||||||
// albedo is basic
|
|
||||||
const TextureData *albedoTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
|
||||||
|
|
||||||
pbrMetRough.reset(new PBRMetallicRoughness(albedoTex, metRoughTex, material.diffuseFactor, material.metallic, material.roughness));
|
Vec4f diffuseFactor;
|
||||||
|
float metallic, roughness;
|
||||||
|
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
|
||||||
|
/**
|
||||||
|
* PBR FBX Material -> PBR Met/Rough glTF.
|
||||||
|
*
|
||||||
|
* METALLIC and ROUGHNESS textures are packed in G and B channels of a rough/met texture.
|
||||||
|
* Other values translate directly.
|
||||||
|
*/
|
||||||
|
RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get();
|
||||||
|
// merge metallic into the blue channel and roughness into the green, of a new combinatory texture
|
||||||
|
metRoughTex = merge2Tex("met_rough",
|
||||||
|
RAW_TEXTURE_USAGE_METALLIC, RAW_TEXTURE_USAGE_ROUGHNESS,
|
||||||
|
[&](const std::vector<const pixel *> pixels) -> pixel { return { 0, (*pixels[1])[0], (*pixels[0])[0], 0 }; });
|
||||||
|
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
||||||
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
metallic = props->metallic;
|
||||||
|
roughness = props->roughness;
|
||||||
|
emissiveFactor = props->emissiveFactor;
|
||||||
|
emissiveIntensity = props->emissiveIntensity;
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* Traditional FBX Material -> PBR Met/Rough glTF.
|
||||||
|
*
|
||||||
|
* Diffuse channel is used as base colour. No metallic/roughness texture is attempted. Constant
|
||||||
|
* metallic/roughness values are hard-coded.
|
||||||
|
*
|
||||||
|
* TODO: If we have specular & optional shininess map, we can generate a reasonable rough/met map.
|
||||||
|
*/
|
||||||
|
const RawTraditionalMatProps *props = ((RawTraditionalMatProps *) material.info.get());
|
||||||
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
// TODO: make configurable on the command line, or do a better job guessing from other, supplied params
|
||||||
|
if (material.info->shadingModel == RAW_SHADING_MODEL_LAMBERT) {
|
||||||
|
metallic = 0.6f;
|
||||||
|
roughness = 1.0f;
|
||||||
|
} else {
|
||||||
|
metallic = 0.2f;
|
||||||
|
roughness = 0.6f;
|
||||||
|
}
|
||||||
|
auto solveMetallic = [&](float pDiff, float pSpec, float oneMinusSpecularStrength)
|
||||||
|
{
|
||||||
|
if (pSpec < dielectric.x) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float a = dielectric.x;
|
||||||
|
float b = pDiff * oneMinusSpecularStrength / (1 - dielectric.x) + pSpec - 2 * dielectric.x;
|
||||||
|
float c = dielectric.x - pSpec;
|
||||||
|
float D = fmax(b * b - 4 * a * c, 0);
|
||||||
|
return fmax(0.0, fmin(1.0, (-b + sqrt(D)) / (2 * a)));
|
||||||
|
};
|
||||||
|
metRoughTex = merge3Tex("rough_met",
|
||||||
|
RAW_TEXTURE_USAGE_SPECULAR, RAW_TEXTURE_USAGE_SHININESS, RAW_TEXTURE_USAGE_DIFFUSE,
|
||||||
|
[&](const std::vector<const pixel *> pixels) -> pixel {
|
||||||
|
const Vec3f specular = pixels[0] ? toVec3f(*pixels[0]) : props->specularFactor;
|
||||||
|
float shininess = pixels[1] ? (*pixels[1])[0] : props->shininess;
|
||||||
|
const Vec4f diffuse = pixels[2] ? toVec4f(*pixels[2]) : props->diffuseFactor;
|
||||||
|
|
||||||
|
float pixelMet = solveMetallic(
|
||||||
|
getPerceivedBrightness(diffuse.xyz()),
|
||||||
|
getPerceivedBrightness(specular),
|
||||||
|
1 - getMaxComponent(specular));
|
||||||
|
float pixelRough = 1 - shininess;
|
||||||
|
|
||||||
|
return { 0, pixelRough, pixelMet, 0 };
|
||||||
|
});
|
||||||
|
if (material.textures[RAW_TEXTURE_USAGE_DIFFUSE] >= 0) {
|
||||||
|
baseColorTex = merge2Tex("base_col",
|
||||||
|
RAW_TEXTURE_USAGE_DIFFUSE, RAW_TEXTURE_USAGE_SPECULAR,
|
||||||
|
[&](const std::vector<const pixel *> pixels) -> pixel {
|
||||||
|
const Vec4f diffuse = pixels[0] ? toVec4f(*pixels[0]) : props->diffuseFactor;
|
||||||
|
const Vec3f specular = pixels[1] ? toVec3f(*pixels[1]) : props->specularFactor;
|
||||||
|
|
||||||
|
float oneMinus = 1 - getMaxComponent(specular);
|
||||||
|
|
||||||
|
float pixelMet = solveMetallic(
|
||||||
|
getPerceivedBrightness(diffuse.xyz()),
|
||||||
|
getPerceivedBrightness(specular),
|
||||||
|
oneMinus);
|
||||||
|
|
||||||
|
Vec3f fromDiffuse = diffuse.xyz() * (oneMinus / (1.0 - dielectric.x) / fmax(1.0 - pixelMet, epsilon));
|
||||||
|
Vec3f fromSpecular = specular - dielectric * (1.0 - pixelMet) * (1.0 / fmax(pixelMet, epsilon));
|
||||||
|
Vec3f baseColor = Vec3f::Lerp(fromDiffuse, fromSpecular, pixelMet * pixelMet);
|
||||||
|
|
||||||
|
return { baseColor[0], baseColor[1], baseColor[2], diffuse[3] };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
emissiveFactor = props->emissiveFactor;
|
||||||
|
emissiveIntensity = 1.0f;
|
||||||
|
}
|
||||||
|
pbrMetRough.reset(new PBRMetallicRoughness(baseColorTex.get(), metRoughTex.get(), diffuseFactor, metallic, roughness));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<PBRSpecularGlossiness> pbrSpecGloss;
|
std::shared_ptr<PBRSpecularGlossiness> pbrSpecGloss;
|
||||||
if (options.usePBRSpecGloss) {
|
if (options.usePBRSpecGloss) {
|
||||||
|
Vec4f diffuseFactor;
|
||||||
|
Vec3f specularFactor;
|
||||||
|
float glossiness;
|
||||||
|
std::shared_ptr<TextureData> specGlossTex;
|
||||||
|
std::shared_ptr<TextureData> diffuseTex;
|
||||||
|
|
||||||
|
const Vec3f dielectric(0.04f, 0.04f, 0.04f);
|
||||||
|
const float epsilon = 1e-6f;
|
||||||
|
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
|
||||||
|
/**
|
||||||
|
* PBR FBX Material -> PBR Spec/Gloss glTF.
|
||||||
|
*
|
||||||
|
* TODO: A complete mess. Low priority.
|
||||||
|
*/
|
||||||
|
RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get();
|
||||||
|
// we can estimate spec/gloss from met/rough by between Vec4f(0.04, 0.04, 0.04) and baseColor
|
||||||
|
// according to metalness, and then taking gloss to be the inverse of roughness
|
||||||
|
specGlossTex = merge3Tex("specgloss",
|
||||||
|
RAW_TEXTURE_USAGE_ALBEDO, RAW_TEXTURE_USAGE_METALLIC, RAW_TEXTURE_USAGE_ROUGHNESS,
|
||||||
|
[&](const std::vector<const pixel *> pixels) -> pixel {
|
||||||
|
Vec3f baseColor(1.0f);
|
||||||
|
if (pixels[0]) {
|
||||||
|
baseColor.x = (*pixels[0])[0];
|
||||||
|
baseColor.y = (*pixels[0])[1];
|
||||||
|
baseColor.z = (*pixels[0])[2];
|
||||||
|
}
|
||||||
|
float metallic = pixels[1] ? (*pixels[1])[0] : 1.0f;
|
||||||
|
float roughness = pixels[2] ? (*pixels[2])[0] : 1.0f;
|
||||||
|
Vec3f spec = Vec3f::Lerp(dielectric, baseColor, metallic);
|
||||||
|
return { spec[0], spec[1], spec[2], 1.0f - roughness };
|
||||||
|
});
|
||||||
|
diffuseTex = merge2Tex("albedo",
|
||||||
|
RAW_TEXTURE_USAGE_ALBEDO, RAW_TEXTURE_USAGE_METALLIC,
|
||||||
|
[&](const std::vector<const pixel *> pixels) -> pixel {
|
||||||
|
Vec3f baseColor(1.0f);
|
||||||
|
float alpha = 1.0f;
|
||||||
|
if (pixels[0]) {
|
||||||
|
baseColor[0] = (*pixels[0])[0];
|
||||||
|
baseColor[1] = (*pixels[0])[1];
|
||||||
|
baseColor[2] = (*pixels[0])[2];
|
||||||
|
alpha = (*pixels[0])[3];
|
||||||
|
}
|
||||||
|
float metallic = pixels[1] ? (*pixels[1])[0] : 1.0f;
|
||||||
|
Vec3f spec = Vec3f::Lerp(dielectric, baseColor, metallic);
|
||||||
|
float maxSpecComp = fmax(fmax(spec.x, spec.y), spec.z);
|
||||||
|
// attenuate baseColor to get specgloss-compliant diffuse; for details consult
|
||||||
|
// https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_pbrSpecularGlossiness
|
||||||
|
Vec3f diffuse = baseColor * (1 - dielectric[0]) * (1 - metallic) * fmax(1.0f - maxSpecComp, epsilon);
|
||||||
|
return { diffuse[0], diffuse[1], diffuse[2], alpha };
|
||||||
|
});
|
||||||
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
specularFactor = Vec3f::Lerp(dielectric, props->diffuseFactor.xyz(), props->metallic);
|
||||||
|
glossiness = 1.0f - props->roughness;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* Traditional FBX Material -> PBR Spec/Gloss glTF.
|
||||||
|
*
|
||||||
|
* TODO: A complete mess. Low priority.
|
||||||
|
*/
|
||||||
|
// TODO: this section a ludicrous over-simplifictation; we can surely do better.
|
||||||
|
const RawTraditionalMatProps *props = ((RawTraditionalMatProps *) material.info.get());
|
||||||
|
specGlossTex = merge2Tex("specgloss",
|
||||||
|
RAW_TEXTURE_USAGE_SPECULAR, RAW_TEXTURE_USAGE_SHININESS,
|
||||||
|
[&](const std::vector<const pixel *> pixels) -> pixel {
|
||||||
|
const auto &spec = *(pixels[0]);
|
||||||
|
const auto &shine = *(pixels[1]);
|
||||||
|
return { spec[0], spec[1], spec[2], shine[0] };
|
||||||
|
});
|
||||||
|
diffuseTex = simpleTex(RAW_TEXTURE_USAGE_DIFFUSE);
|
||||||
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
specularFactor = props->specularFactor;
|
||||||
|
glossiness = props->shininess;
|
||||||
|
}
|
||||||
|
|
||||||
pbrSpecGloss.reset(
|
pbrSpecGloss.reset(
|
||||||
new PBRSpecularGlossiness(
|
new PBRSpecularGlossiness(
|
||||||
simpleTex(RAW_TEXTURE_USAGE_DIFFUSE), material.diffuseFactor,
|
diffuseTex.get(), diffuseFactor, specGlossTex.get(), specularFactor, glossiness));
|
||||||
simpleTex(RAW_TEXTURE_USAGE_SPECULAR), material.specularFactor, material.shininess));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<KHRCommonMats> khrComMat;
|
std::shared_ptr<KHRCommonMats> khrComMat;
|
||||||
if (options.useKHRMatCom) {
|
if (options.useKHRMatCom) {
|
||||||
auto type = KHRCommonMats::MaterialType::Constant;
|
float shininess;
|
||||||
if (material.shadingModel == "Lambert") {
|
Vec3f ambientFactor, specularFactor;
|
||||||
type = KHRCommonMats::MaterialType::Lambert;
|
Vec4f diffuseFactor;
|
||||||
} else if (material.shadingModel == "Blinn") {
|
std::shared_ptr<TextureData> diffuseTex;
|
||||||
type = KHRCommonMats::MaterialType::Blinn;
|
auto type = KHRCommonMats::MaterialType::Constant;
|
||||||
} else if (material.shadingModel == "Phong") {
|
|
||||||
type = KHRCommonMats::MaterialType::Phong;
|
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
|
||||||
|
/**
|
||||||
|
* PBR FBX Material -> KHR Common Materials glTF.
|
||||||
|
*
|
||||||
|
* TODO: We can use the specularFactor calculation below to generate a reasonable specular map, too.
|
||||||
|
*/
|
||||||
|
const RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get();
|
||||||
|
shininess = 1.0f - props->roughness;
|
||||||
|
ambientFactor = Vec3f(0.0f, 0.0f, 0.0f);
|
||||||
|
diffuseTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
||||||
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
specularFactor = Vec3f::Lerp(Vec3f(0.04f, 0.04f, 0.04f), props->diffuseFactor.xyz(), props->metallic);
|
||||||
|
// render as Phong if there's any specularity, otherwise Lambert
|
||||||
|
type = (specularFactor.LengthSquared() > 1e-4) ?
|
||||||
|
KHRCommonMats::MaterialType::Phong : KHRCommonMats::MaterialType::Lambert;
|
||||||
|
// TODO: convert textures
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* Traditional FBX Material -> KHR Common Materials glTF.
|
||||||
|
*
|
||||||
|
* Should be in good shape. Essentially pass-through.
|
||||||
|
*/
|
||||||
|
const RawTraditionalMatProps *props = (RawTraditionalMatProps *) material.info.get();
|
||||||
|
shininess = props->shininess;
|
||||||
|
ambientFactor = props->ambientFactor;
|
||||||
|
diffuseTex = simpleTex(RAW_TEXTURE_USAGE_DIFFUSE);
|
||||||
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
specularFactor = props->specularFactor;
|
||||||
|
|
||||||
|
if (material.info->shadingModel == RAW_SHADING_MODEL_LAMBERT) {
|
||||||
|
type = KHRCommonMats::MaterialType::Lambert;
|
||||||
|
} else if (material.info->shadingModel == RAW_SHADING_MODEL_BLINN) {
|
||||||
|
type = KHRCommonMats::MaterialType::Blinn;
|
||||||
|
} else if (material.info->shadingModel == RAW_SHADING_MODEL_PHONG) {
|
||||||
|
type = KHRCommonMats::MaterialType::Phong;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
khrComMat.reset(
|
khrComMat.reset(
|
||||||
new KHRCommonMats(
|
new KHRCommonMats(type,
|
||||||
type,
|
simpleTex(RAW_TEXTURE_USAGE_SHININESS).get(), shininess,
|
||||||
simpleTex(RAW_TEXTURE_USAGE_SHININESS), material.shininess,
|
simpleTex(RAW_TEXTURE_USAGE_AMBIENT).get(), ambientFactor,
|
||||||
simpleTex(RAW_TEXTURE_USAGE_AMBIENT), material.ambientFactor,
|
diffuseTex.get(), diffuseFactor,
|
||||||
simpleTex(RAW_TEXTURE_USAGE_DIFFUSE), material.diffuseFactor,
|
simpleTex(RAW_TEXTURE_USAGE_SPECULAR).get(), specularFactor));
|
||||||
simpleTex(RAW_TEXTURE_USAGE_SPECULAR), material.specularFactor));
|
|
||||||
}
|
}
|
||||||
std::shared_ptr<MaterialData> mData = gltf->materials.hold(
|
std::shared_ptr<MaterialData> mData = gltf->materials.hold(
|
||||||
new MaterialData(
|
new MaterialData(
|
||||||
material.name, isTransparent, simpleTex(RAW_TEXTURE_USAGE_NORMAL),
|
material.name, isTransparent,
|
||||||
simpleTex(RAW_TEXTURE_USAGE_EMISSIVE), material.emissiveFactor * material.emissiveIntensity, // TODO: 1.0 default value for emissiveIntensity?
|
simpleTex(RAW_TEXTURE_USAGE_NORMAL).get(), simpleTex(RAW_TEXTURE_USAGE_EMISSIVE).get(),
|
||||||
|
emissiveFactor * emissiveIntensity,
|
||||||
khrComMat, pbrMetRough, pbrSpecGloss));
|
khrComMat, pbrMetRough, pbrSpecGloss));
|
||||||
materialsByName[materialHash(material)] = mData;
|
materialsByName[materialHash(material)] = mData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,38 +111,25 @@ int RawModel::AddTexture(const std::string &name, const std::string &fileName, c
|
||||||
|
|
||||||
int RawModel::AddMaterial(const RawMaterial &material)
|
int RawModel::AddMaterial(const RawMaterial &material)
|
||||||
{
|
{
|
||||||
return AddMaterial(
|
return AddMaterial(material.name.c_str(), material.type, material.textures, material.info);
|
||||||
material.name.c_str(), material.shadingModel.c_str(), material.type, material.textures, material.ambientFactor,
|
|
||||||
material.diffuseFactor, material.specularFactor, material.emissiveFactor, material.emissiveIntensity,
|
|
||||||
material.shininess, material.metallic, material.roughness);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddMaterial(
|
int RawModel::AddMaterial(
|
||||||
const char *name, const char *shadingModel, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX],
|
const char *name,
|
||||||
const Vec3f ambientFactor, const Vec4f diffuseFactor, const Vec3f specularFactor, const Vec3f emissiveFactor,
|
const RawMaterialType materialType,
|
||||||
float emissiveIntensity, float shinineness, float metallic, float roughness)
|
const int textures[RAW_TEXTURE_USAGE_MAX],
|
||||||
|
std::shared_ptr<RawMatProps> materialInfo)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < materials.size(); i++) {
|
for (size_t i = 0; i < materials.size(); i++) {
|
||||||
if (materials[i].name != name) {
|
if (materials[i].name != name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (materials[i].shadingModel != shadingModel) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (materials[i].type != materialType) {
|
if (materials[i].type != materialType) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (materials[i].ambientFactor != ambientFactor ||
|
if (*(materials[i].info) != *materialInfo) {
|
||||||
materials[i].diffuseFactor != diffuseFactor ||
|
|
||||||
materials[i].specularFactor != specularFactor ||
|
|
||||||
materials[i].emissiveFactor != emissiveFactor ||
|
|
||||||
materials[i].emissiveIntensity != emissiveIntensity ||
|
|
||||||
materials[i].shininess != shinineness ||
|
|
||||||
materials[i].metallic != metallic ||
|
|
||||||
materials[i].roughness != roughness) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match = true;
|
bool match = true;
|
||||||
for (int j = 0; match && j < RAW_TEXTURE_USAGE_MAX; j++) {
|
for (int j = 0; match && j < RAW_TEXTURE_USAGE_MAX; j++) {
|
||||||
match = match && (materials[i].textures[j] == textures[j]);
|
match = match && (materials[i].textures[j] == textures[j]);
|
||||||
|
@ -153,17 +140,9 @@ int RawModel::AddMaterial(
|
||||||
}
|
}
|
||||||
|
|
||||||
RawMaterial material;
|
RawMaterial material;
|
||||||
material.name = name;
|
material.name = name;
|
||||||
material.shadingModel = shadingModel;
|
material.type = materialType;
|
||||||
material.type = materialType;
|
material.info = materialInfo;
|
||||||
material.ambientFactor = ambientFactor;
|
|
||||||
material.diffuseFactor = diffuseFactor;
|
|
||||||
material.specularFactor = specularFactor;
|
|
||||||
material.emissiveFactor = emissiveFactor;
|
|
||||||
material.emissiveIntensity = emissiveIntensity;
|
|
||||||
material.shininess = shinineness;
|
|
||||||
material.metallic = metallic;
|
|
||||||
material.roughness = roughness;
|
|
||||||
|
|
||||||
for (int i = 0; i < RAW_TEXTURE_USAGE_MAX; i++) {
|
for (int i = 0; i < RAW_TEXTURE_USAGE_MAX; i++) {
|
||||||
material.textures[i] = textures[i];
|
material.textures[i] = textures[i];
|
||||||
|
|
167
src/RawModel.h
167
src/RawModel.h
|
@ -95,8 +95,32 @@ struct RawTriangle
|
||||||
int surfaceIndex;
|
int surfaceIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RawShadingModel
|
||||||
|
{
|
||||||
|
RAW_SHADING_MODEL_UNKNOWN = -1,
|
||||||
|
RAW_SHADING_MODEL_CONSTANT,
|
||||||
|
RAW_SHADING_MODEL_LAMBERT,
|
||||||
|
RAW_SHADING_MODEL_BLINN,
|
||||||
|
RAW_SHADING_MODEL_PHONG,
|
||||||
|
RAW_SHADING_MODEL_PBR_MET_ROUGH,
|
||||||
|
RAW_SHADING_MODEL_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline std::string Describe(RawShadingModel model) {
|
||||||
|
switch(model) {
|
||||||
|
case RAW_SHADING_MODEL_UNKNOWN: return "<unknown>";
|
||||||
|
case RAW_SHADING_MODEL_CONSTANT: return "Constant";
|
||||||
|
case RAW_SHADING_MODEL_LAMBERT: return "Lambert";
|
||||||
|
case RAW_SHADING_MODEL_BLINN: return "Blinn";
|
||||||
|
case RAW_SHADING_MODEL_PHONG: return "Phong";
|
||||||
|
case RAW_SHADING_MODEL_PBR_MET_ROUGH: return "Metallic/Roughness";
|
||||||
|
case RAW_SHADING_MODEL_MAX: default: return "<unknown>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum RawTextureUsage
|
enum RawTextureUsage
|
||||||
{
|
{
|
||||||
|
RAW_TEXTURE_USAGE_NONE = -1,
|
||||||
RAW_TEXTURE_USAGE_AMBIENT,
|
RAW_TEXTURE_USAGE_AMBIENT,
|
||||||
RAW_TEXTURE_USAGE_DIFFUSE,
|
RAW_TEXTURE_USAGE_DIFFUSE,
|
||||||
RAW_TEXTURE_USAGE_NORMAL,
|
RAW_TEXTURE_USAGE_NORMAL,
|
||||||
|
@ -111,35 +135,21 @@ enum RawTextureUsage
|
||||||
RAW_TEXTURE_USAGE_MAX
|
RAW_TEXTURE_USAGE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string DescribeTextureUsage(int usage)
|
static inline std::string Describe(RawTextureUsage usage)
|
||||||
{
|
{
|
||||||
if (usage < 0) {
|
switch (usage) {
|
||||||
return "<none>";
|
case RAW_TEXTURE_USAGE_NONE: return "<none>";
|
||||||
}
|
case RAW_TEXTURE_USAGE_AMBIENT: return "ambient";
|
||||||
switch (static_cast<RawTextureUsage>(usage)) {
|
case RAW_TEXTURE_USAGE_DIFFUSE: return "diffuse";
|
||||||
case RAW_TEXTURE_USAGE_AMBIENT:
|
case RAW_TEXTURE_USAGE_NORMAL: return "normal";
|
||||||
return "ambient";
|
case RAW_TEXTURE_USAGE_SPECULAR: return "specuar";
|
||||||
case RAW_TEXTURE_USAGE_DIFFUSE:
|
case RAW_TEXTURE_USAGE_SHININESS: return "shininess";
|
||||||
return "diffuse";
|
case RAW_TEXTURE_USAGE_EMISSIVE: return "emissive";
|
||||||
case RAW_TEXTURE_USAGE_NORMAL:
|
case RAW_TEXTURE_USAGE_REFLECTION: return "reflection";
|
||||||
return "normal";
|
case RAW_TEXTURE_USAGE_OCCLUSION: return "occlusion";
|
||||||
case RAW_TEXTURE_USAGE_SPECULAR:
|
case RAW_TEXTURE_USAGE_ROUGHNESS: return "roughness";
|
||||||
return "specuar";
|
case RAW_TEXTURE_USAGE_METALLIC: return "metallic";
|
||||||
case RAW_TEXTURE_USAGE_SHININESS:
|
case RAW_TEXTURE_USAGE_MAX:default: return "unknown";
|
||||||
return "shininess";
|
|
||||||
case RAW_TEXTURE_USAGE_EMISSIVE:
|
|
||||||
return "emissive";
|
|
||||||
case RAW_TEXTURE_USAGE_REFLECTION:
|
|
||||||
return "reflection";
|
|
||||||
case RAW_TEXTURE_USAGE_OCCLUSION:
|
|
||||||
return "occlusion";
|
|
||||||
case RAW_TEXTURE_USAGE_ROUGHNESS:
|
|
||||||
return "roughness";
|
|
||||||
case RAW_TEXTURE_USAGE_METALLIC:
|
|
||||||
return "metallic";
|
|
||||||
case RAW_TEXTURE_USAGE_MAX:
|
|
||||||
default:
|
|
||||||
return "unknown";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,21 +179,91 @@ enum RawMaterialType
|
||||||
RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT,
|
RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RawMatProps {
|
||||||
|
explicit RawMatProps(RawShadingModel shadingModel)
|
||||||
|
: shadingModel(shadingModel)
|
||||||
|
{}
|
||||||
|
const RawShadingModel shadingModel;
|
||||||
|
|
||||||
|
virtual bool operator!=(const RawMatProps &other) const { return !(*this == other); }
|
||||||
|
virtual bool operator==(const RawMatProps &other) const { return shadingModel == other.shadingModel; };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RawTraditionalMatProps : RawMatProps {
|
||||||
|
RawTraditionalMatProps(
|
||||||
|
RawShadingModel shadingModel,
|
||||||
|
const Vec3f &&ambientFactor,
|
||||||
|
const Vec4f &&diffuseFactor,
|
||||||
|
const Vec3f &&emissiveFactor,
|
||||||
|
const Vec3f &&specularFactor,
|
||||||
|
const float shininess
|
||||||
|
) : RawMatProps(shadingModel),
|
||||||
|
ambientFactor(ambientFactor),
|
||||||
|
diffuseFactor(diffuseFactor),
|
||||||
|
emissiveFactor(emissiveFactor),
|
||||||
|
specularFactor(specularFactor),
|
||||||
|
shininess(shininess)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const Vec3f ambientFactor;
|
||||||
|
const Vec4f diffuseFactor;
|
||||||
|
const Vec3f emissiveFactor;
|
||||||
|
const Vec3f specularFactor;
|
||||||
|
const float shininess;
|
||||||
|
|
||||||
|
bool operator==(const RawMatProps &other) const override {
|
||||||
|
if (RawMatProps::operator==(other)) {
|
||||||
|
const auto &typed = (RawTraditionalMatProps &) other;
|
||||||
|
return ambientFactor == typed.ambientFactor &&
|
||||||
|
diffuseFactor == typed.diffuseFactor &&
|
||||||
|
specularFactor == typed.specularFactor &&
|
||||||
|
emissiveFactor == typed.emissiveFactor &&
|
||||||
|
shininess == typed.shininess;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RawMetRoughMatProps : RawMatProps {
|
||||||
|
RawMetRoughMatProps(
|
||||||
|
RawShadingModel shadingModel,
|
||||||
|
const Vec4f &&diffuseFactor,
|
||||||
|
const Vec3f &&emissiveFactor,
|
||||||
|
float emissiveIntensity,
|
||||||
|
float metallic,
|
||||||
|
float roughness
|
||||||
|
) : RawMatProps(shadingModel),
|
||||||
|
diffuseFactor(diffuseFactor),
|
||||||
|
emissiveFactor(emissiveFactor),
|
||||||
|
emissiveIntensity(emissiveIntensity),
|
||||||
|
metallic(metallic),
|
||||||
|
roughness(roughness)
|
||||||
|
{}
|
||||||
|
const Vec4f diffuseFactor;
|
||||||
|
const Vec3f emissiveFactor;
|
||||||
|
const float emissiveIntensity;
|
||||||
|
const float metallic;
|
||||||
|
const float roughness;
|
||||||
|
|
||||||
|
bool operator==(const RawMatProps &other) const override {
|
||||||
|
if (RawMatProps::operator==(other)) {
|
||||||
|
const auto &typed = (RawMetRoughMatProps &) other;
|
||||||
|
return diffuseFactor == typed.diffuseFactor &&
|
||||||
|
emissiveFactor == typed.emissiveFactor &&
|
||||||
|
emissiveIntensity == typed.emissiveIntensity &&
|
||||||
|
metallic == typed.metallic &&
|
||||||
|
roughness == typed.roughness;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct RawMaterial
|
struct RawMaterial
|
||||||
{
|
{
|
||||||
|
std::string name;
|
||||||
std::string name;
|
RawMaterialType type;
|
||||||
std::string shadingModel; // typically "Surface", "Anisotropic", "Blinn", "Lambert", "Phong", "Phone E"
|
std::shared_ptr<RawMatProps> info;
|
||||||
RawMaterialType type;
|
int textures[RAW_TEXTURE_USAGE_MAX];
|
||||||
Vec3f ambientFactor;
|
|
||||||
Vec4f diffuseFactor;
|
|
||||||
Vec3f specularFactor;
|
|
||||||
Vec3f emissiveFactor;
|
|
||||||
float emissiveIntensity;
|
|
||||||
float shininess;
|
|
||||||
float metallic;
|
|
||||||
float roughness;
|
|
||||||
int textures[RAW_TEXTURE_USAGE_MAX];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawBlendChannel
|
struct RawBlendChannel
|
||||||
|
@ -275,9 +355,8 @@ public:
|
||||||
int AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage);
|
int AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage);
|
||||||
int AddMaterial(const RawMaterial &material);
|
int AddMaterial(const RawMaterial &material);
|
||||||
int AddMaterial(
|
int AddMaterial(
|
||||||
const char *name, const char *shadingModel, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX],
|
const char *name, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX],
|
||||||
const Vec3f ambientFactor, const Vec4f diffuseFactor, const Vec3f specularFactor, const Vec3f emissiveFactor,
|
std::shared_ptr<RawMatProps> materialInfo);
|
||||||
float emissiveIntensity, float shinineness, float metallic, float roughness);
|
|
||||||
int AddSurface(const RawSurface &suface);
|
int AddSurface(const RawSurface &suface);
|
||||||
int AddSurface(const char *name, const char *nodeName);
|
int AddSurface(const char *name, const char *nodeName);
|
||||||
int AddAnimation(const RawAnimation &animation);
|
int AddAnimation(const RawAnimation &animation);
|
||||||
|
|
Loading…
Reference in New Issue