Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
pablode committed Apr 21, 2024
1 parent bacb031 commit b427f84
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 29 deletions.
21 changes: 21 additions & 0 deletions src/guc/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void print_usage()
fprintf(stderr, "--mtlx-as-usdshade Convert and inline MaterialX materials with UsdMtlx\n");
fprintf(stderr, "--hdstorm-compat Apply compatibility tweaks for the USD hdStorm renderer\n");
fprintf(stderr, "--default-material-variant <number> Index of the material variant that is selected by default\n");
fprintf(stderr, "--primvar-mode <auto|explicit|implicit> How shading networks read primvars. Default: auto\n");
}

int main(int argc, const char* argv[])
Expand All @@ -49,6 +50,7 @@ int main(int argc, const char* argv[])
options.mtlx_as_usdshade = false;
options.hdstorm_compat = false;
options.default_material_variant = 0;
options.primvar_mode = GUC_PRIMVAR_MODE_AUTO;

for (int i = 3; i < argc; i++)
{
Expand Down Expand Up @@ -79,6 +81,25 @@ int main(int argc, const char* argv[])
options.default_material_variant = atoi(val); // fall back to 0 on error
continue;
}
else if (!strcmp(arg, "primvar-mode") && ++i < argc)
{
const char* val = argv[i];
if (!strcmp(val, "auto"))
{
// default value
continue;
}
else if (!strcmp(val, "explicit"))
{
options.primvar_mode = GUC_PRIMVAR_MODE_EXPLICIT;
continue;
}
else if (!strcmp(val, "implicit"))
{
options.primvar_mode = GUC_PRIMVAR_MODE_IMPLICIT;
continue;
}
}
}

print_usage();
Expand Down
19 changes: 19 additions & 0 deletions src/libguc/include/guc.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ extern "C" {
#include <stdbool.h>
#endif

enum guc_primvar_mode
{
GUC_PRIMVAR_MODE_AUTO,
GUC_PRIMVAR_MODE_EXPLICIT,
GUC_PRIMVAR_MODE_IMPLICIT
};

struct guc_options
{
// Generate and reference a MaterialX document containing an accurate translation
Expand All @@ -43,6 +50,18 @@ struct guc_options
// If the asset supports the KHR_materials_variants extension, select the material
// variant at the given index by default.
int default_material_variant;

// Determines how shading networks are supplied with primvar data:
// AUTO: implicit primvars are used when no secondary texture sets, normal maps and
// vertex colors are present. Otherwise, explicit primvar reading is used.
// EXPLICIT: nodes generated in shading networks read primvars with explicit names.
// IMPLICIT: primvar reading network nodes are omitted and the data is supplied by the
// renderer. This option is supported by most runtimes but can cause incorrect
// rendering of non-trivial assets. The Hydra render engine now employs
// heuristics to determine the most suitable primvars. It searches for
// specific names ('st') and roles (texcoord2f). Following primvars are likely
// to be not detected: secondary texture UVs, vertex colors, tangent and bitangents.
enum guc_primvar_mode primvar_mode;
};

bool guc_convert(const char* gltf_path,
Expand Down
67 changes: 59 additions & 8 deletions src/libguc/src/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,43 @@ namespace detail
customData[_tokens->generated] = true;
attr.SetCustomDataByKey(_tokens->guc, VtValue(customData));
}

bool requiresExplicitPrimvarReading(const cgltf_data* data)
{
// Find primvars renderers usually not detect
for (size_t i = 0; i < data->meshes_count; i++)
{
const cgltf_mesh& mesh = data->meshes[i];
for (size_t j = 0; j < mesh.primitives_count; j++)
{
const cgltf_primitive& primitive = mesh.primitives[j];
for (size_t k = 0; k < primitive.attributes_count; k++)
{
const cgltf_attribute& attribute = primitive.attributes[k];
if (strstr(attribute.name, "COLOR") && strcmp(attribute.name, "COLOR_0") != 0)
{
return true;
}
if (strstr(attribute.name, "TEXCOORD") && strcmp(attribute.name, "TEXCOORD_0") != 0)
{
return true;
}
}
}
}
// Normal mapping should be fine in most cases, but both MaterialX and
// UsdPreviewSurface do not specify the exact tangent frame calculation.
for (size_t i = 0; i < data->materials_count; i++)
{
const cgltf_material& material = data->materials[i];
const cgltf_texture_view& texView = material.normal_texture;
if (texView.texture)
{
return true;
}
}
return false;
}
}

namespace guc
Expand All @@ -236,8 +273,6 @@ namespace guc
, m_stage(stage)
, m_params(params)
, m_mtlxDoc(mx::createDocument())
, m_mtlxConverter(m_mtlxDoc, m_imgMetadata, params.hdStormCompat)
, m_usdPreviewSurfaceConverter(m_stage, m_imgMetadata)
{
}

Expand Down Expand Up @@ -292,7 +327,15 @@ namespace guc
fileExports.push_back({ metadata.filePath, metadata.refPath });
}

// Step 3: create materials
// Step 3: determine primvar mode if auto
if (m_params.primvarMode == PrimvarMode::Auto)
{
bool readExplicit = detail::requiresExplicitPrimvarReading(m_data);
m_params.primvarMode = readExplicit ? PrimvarMode::Explicit : PrimvarMode::Implicit;
TF_DEBUG(GUC).Msg("resolved auto primvar mode to %s\n", readExplicit ? "explicit" : "implicit");
}

// Step 4: create materials
bool hasMaterials = (m_data->materials_count > 0);
bool createDefaultMaterial = false;

Expand All @@ -315,7 +358,7 @@ namespace guc
createMaterials(fileExports, createDefaultMaterial);
}

// Step 4: create scene graph (nodes, meshes, lights, cameras, ...)
// Step 5: create scene graph (nodes, meshes, lights, cameras, ...)
auto createNode = [this](const cgltf_node* nodeData, SdfPath path)
{
std::string baseName(nodeData->name ? nodeData->name : "node");
Expand Down Expand Up @@ -396,6 +439,14 @@ namespace guc

void Converter::createMaterials(FileExports& fileExports, bool createDefaultMaterial)
{
bool explicitPrimvarReading = m_params.primvarMode == PrimvarMode::Explicit;

UsdPreviewSurfaceMaterialConverter previewSurfaceConverter(m_stage,
m_imgMetadata, explicitPrimvarReading);

// TODO: respect primvar reading in mtlx networks
MaterialXMaterialConverter mtlxConverter(m_mtlxDoc, m_imgMetadata, m_params.hdStormCompat);

// We import the MaterialX bxdf/pbrlib/stdlib documents mainly for validation, but
// because UsdMtlx tries to output them, we only do so when not exporting UsdShade.
if (m_params.emitMtlx && !m_params.mtlxAsUsdShade)
Expand Down Expand Up @@ -434,11 +485,11 @@ namespace guc
TF_DEBUG(GUC).Msg("creating default material\n");

SdfPath previewPath = makeUsdPreviewSurfaceMaterialPath(DEFAULT_MATERIAL_NAME);
m_usdPreviewSurfaceConverter.convert(&DEFAULT_MATERIAL, previewPath);
previewSurfaceConverter.convert(&DEFAULT_MATERIAL, previewPath);

if (m_params.emitMtlx)
{
m_mtlxConverter.convert(&DEFAULT_MATERIAL, DEFAULT_MATERIAL_NAME);
mtlxConverter.convert(&DEFAULT_MATERIAL, DEFAULT_MATERIAL_NAME);
}
materialNameSet.insert(DEFAULT_MATERIAL_NAME);
}
Expand All @@ -458,11 +509,11 @@ namespace guc
}

SdfPath previewPath = makeUsdPreviewSurfaceMaterialPath(m_materialNames[i]);
m_usdPreviewSurfaceConverter.convert(gmat, previewPath);
previewSurfaceConverter.convert(gmat, previewPath);

if (m_params.emitMtlx)
{
m_mtlxConverter.convert(gmat, materialName);
mtlxConverter.convert(gmat, materialName);
}
}

Expand Down
15 changes: 10 additions & 5 deletions src/libguc/src/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
#include <filesystem>
#include <string_view>

#include "materialx.h"
#include "usdpreviewsurface.h"
#include "image.h"

namespace fs = std::filesystem;
using namespace PXR_NS;
Expand All @@ -37,6 +36,13 @@ namespace guc
class Converter
{
public:
enum class PrimvarMode
{
Auto,
Explicit,
Implicit
};

struct Params
{
fs::path srcDir;
Expand All @@ -48,6 +54,7 @@ namespace guc
bool mtlxAsUsdShade;
bool hdStormCompat;
int defaultMaterialVariant;
PrimvarMode primvarMode;
};

public:
Expand Down Expand Up @@ -79,13 +86,11 @@ namespace guc
private:
const cgltf_data* m_data;
UsdStageRefPtr m_stage;
const Params& m_params;
Params m_params;

private:
ImageMetadataMap m_imgMetadata;
MaterialX::DocumentPtr m_mtlxDoc;
MaterialXMaterialConverter m_mtlxConverter;
UsdPreviewSurfaceMaterialConverter m_usdPreviewSurfaceConverter;
std::unordered_map<void*, SdfPath> m_uniquePaths;
std::vector<std::string> m_materialNames;
};
Expand Down
1 change: 1 addition & 0 deletions src/libguc/src/guc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ bool convertToUsd(fs::path src_dir,
params.mtlxAsUsdShade = options->mtlx_as_usdshade;
params.hdStormCompat = options->hdstorm_compat;
params.defaultMaterialVariant = options->default_material_variant;
params.primvarMode = (Converter::PrimvarMode) options->primvar_mode;

Converter converter(gltf_data, stage, params);

Expand Down
6 changes: 5 additions & 1 deletion src/libguc/src/naming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ namespace guc
std::string makeStSetName(int index)
{
std::string uvSetBaseName = UsdUtilsGetPrimaryUVSetName(); // likely to be "st"
return uvSetBaseName + std::to_string(index);
if (index == 0)
{
return uvSetBaseName;
}
return uvSetBaseName + std::to_string(index); // TODO: st1 vs st2
}

std::string makeColorSetName(int index)
Expand Down
27 changes: 17 additions & 10 deletions src/libguc/src/usdpreviewsurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,11 @@ namespace detail
namespace guc
{
UsdPreviewSurfaceMaterialConverter::UsdPreviewSurfaceMaterialConverter(UsdStageRefPtr stage,
const ImageMetadataMap& imageMetadataMap)
const ImageMetadataMap& imageMetadataMap,
bool readPrimvars)
: m_stage(stage)
, m_imageMetadataMap(imageMetadataMap)
, m_readPrimvars(readPrimvars)
{
}

Expand Down Expand Up @@ -374,10 +376,10 @@ namespace guc
}
}

void UsdPreviewSurfaceMaterialConverter::addTextureTransformNode(const SdfPath& basePath,
const cgltf_texture_transform& transform,
int stIndex,
UsdShadeInput& textureStInput)
UsdShadeInput UsdPreviewSurfaceMaterialConverter::addTextureTransformNode(const SdfPath& basePath,
const cgltf_texture_transform& transform,
int stIndex,
UsdShadeInput& textureStInput)
{
auto nodePath = makeUniqueStageSubpath(m_stage, basePath, "node", "");

Expand All @@ -398,11 +400,11 @@ namespace guc
auto translationInput = node.CreateInput(_tokens->translation, SdfValueTypeNames->Float2);
translationInput.Set(offset);

auto untransformedInput = node.CreateInput(_tokens->in, SdfValueTypeNames->Float2);
setStPrimvarInput(untransformedInput, basePath, stIndex);

auto transformedOutput = node.CreateOutput(_tokens->result, SdfValueTypeNames->Float2);
textureStInput.ConnectToSource(transformedOutput);

auto untransformedInput = node.CreateInput(_tokens->in, SdfValueTypeNames->Float2);
return untransformedInput;
}

bool UsdPreviewSurfaceMaterialConverter::addTextureNode(const SdfPath& basePath,
Expand Down Expand Up @@ -464,12 +466,17 @@ namespace guc

if (textureView.has_transform && cgltf_transform_required(transform))
{
addTextureTransformNode(basePath, transform, stIndex, stInput);
stInput = addTextureTransformNode(basePath, transform, stIndex, stInput);
}
else

if (m_readPrimvars)
{
setStPrimvarInput(stInput, basePath, stIndex);
}
else if (stIndex > 0)
{
TF_WARN("secondary texture sets not supported by implicit primvars");
}

return true;
}
Expand Down
12 changes: 7 additions & 5 deletions src/libguc/src/usdpreviewsurface.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ namespace guc
{
public:
UsdPreviewSurfaceMaterialConverter(UsdStageRefPtr stage,
const ImageMetadataMap& imageMetadataMap);
const ImageMetadataMap& imageMetadataMap,
bool readPrimvars);

void convert(const cgltf_material* material, const SdfPath& path);

private:
UsdStageRefPtr m_stage;
const ImageMetadataMap& m_imageMetadataMap;
const bool m_readPrimvars;

private:
void setNormalTextureInput(const SdfPath& basePath,
Expand Down Expand Up @@ -71,10 +73,10 @@ namespace guc
const GfVec4f* bias,
const GfVec4f* fallback);

void addTextureTransformNode(const SdfPath& basePath,
const cgltf_texture_transform& transform,
int stIndex,
UsdShadeInput& textureStInput);
UsdShadeInput addTextureTransformNode(const SdfPath& basePath,
const cgltf_texture_transform& transform,
int stIndex,
UsdShadeInput& textureStInput);

bool addTextureNode(const SdfPath& basePath,
const cgltf_texture_view& textureView,
Expand Down

0 comments on commit b427f84

Please sign in to comment.