13#include <pxr/base/gf/rotation.h>
14#include <pxr/base/gf/vec3f.h>
15#include <pxr/usd/usdGeom/metrics.h>
16#include <pxr/usd/usdGeom/tokens.h>
17#include <pxr/usd/usdGeom/xformCache.h>
18#include <pxr/usd/usdGeom/xformCommonAPI.h>
19#include <pxr/usd/usdLux/domeLight.h>
42static const pxr::TfToken
color(
"color", pxr::TfToken::Immortal);
43static const pxr::TfToken
intensity(
"intensity", pxr::TfToken::Immortal);
44static const pxr::TfToken
texture_file(
"texture:file", pxr::TfToken::Immortal);
60bool get_authored_value(
const pxr::UsdAttribute &attr,
61 const double motionSampleTime,
62 const pxr::UsdPrim &prim,
63 const pxr::TfToken fallback_attr_name,
66 if (attr && attr.HasAuthoredValue()) {
67 return attr.Get<T>(r_value, motionSampleTime);
70 if (!prim || fallback_attr_name.IsEmpty()) {
74 pxr::UsdAttribute fallback_attr = prim.GetAttribute(fallback_attr_name);
75 if (fallback_attr && fallback_attr.HasAuthoredValue()) {
76 return fallback_attr.Get<T>(r_value, motionSampleTime);
86struct WorldNtreeSearchResults {
88 pxr::UsdStageRefPtr
stage;
90 std::string file_path;
92 float world_intensity = 0.0f;
93 float world_color[3]{};
94 float mapping_rot[3]{};
95 float color_mult[3]{};
97 bool background_found =
false;
98 bool env_tex_found =
false;
99 bool mult_found =
false;
102 pxr::UsdStageRefPtr in_stage)
119 std::string unique_path = path;
121 while (
stage->GetPrimAtPath(pxr::SdfPath(unique_path)).IsValid()) {
122 unique_path = path + std::to_string(suffix++);
124 return pxr::SdfPath(unique_path);
137 std::string imported_file_source_path = tex_path;
139 if (import_textures) {
144 params.import_textures_dir;
149 params.tex_name_collision_mode;
151 tex_path =
import_asset(tex_path.c_str(), textures_dir, name_collision_mode,
nullptr);
159 if (import_textures && imported_file_source_path != tex_path) {
179 const char *out_sock,
195 src_node->
locx = dst_node->
locx - offset;
211 if (!(userdata && fromnode)) {
215 WorldNtreeSearchResults *res =
reinterpret_cast<WorldNtreeSearchResults *
>(userdata);
217 if (!res->background_found && fromnode->
type == SH_NODE_BACKGROUND) {
225 res->background_found =
true;
226 res->world_intensity = strength_data->value;
227 res->world_color[0] = color_data->
value[0];
228 res->world_color[1] = color_data->
value[1];
229 res->world_color[2] = color_data->
value[2];
236 if (!res->file_path.empty()) {
237 res->env_tex_found =
true;
246 res->mult_found =
true;
250 vec_sock = vec_sock->
next;
262 socket->default_value);
276 pxr::UsdStageRefPtr
stage)
278 if (!(
stage && scene && scene->world && scene->world->use_nodes && scene->world->nodetree)) {
283 const bNodeTree *ntree = scene->world->nodetree;
284 ntree->ensure_topology_cache();
297 if (!(res.background_found || res.env_tex_found)) {
305 std::string(
params.root_prim_path) +
"/env_light");
307 pxr::UsdLuxDomeLight dome_light = pxr::UsdLuxDomeLight::Define(
stage, env_light_path);
309 if (!res.env_tex_found) {
314 float fill_color[4] = {res.world_color[0], res.world_color[1], res.world_color[2], 1.0f};
317 const std::string base_path =
stage->GetRootLayer()->GetRealPath();
330 if (
BLI_copy(source_path.c_str(), dest_path) != 0) {
331 CLOG_WARN(&
LOG,
"USD Export: Couldn't write world color image to %s", dest_path);
334 res.env_tex_found =
true;
336 res.file_path = dest_path;
340 if (res.env_tex_found) {
341 pxr::SdfAssetPath path(res.file_path);
342 dome_light.CreateTextureFileAttr().Set(path);
344 if (res.mult_found) {
345 pxr::GfVec3f color_val(res.color_mult[0], res.color_mult[1], res.color_mult[2]);
346 dome_light.CreateColorAttr().Set(color_val);
350 pxr::GfVec3f color_val(res.world_color[0], res.world_color[1], res.world_color[2]);
351 dome_light.CreateColorAttr().Set(color_val);
354 if (res.background_found) {
355 dome_light.CreateIntensityAttr().Set(res.world_intensity);
364 pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), 90.0)) *
365 pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), 90.0)) *
366 pxr::GfMatrix4d().SetRotate(
367 pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), -res.mapping_rot[2])) *
368 pxr::GfMatrix4d().SetRotate(
369 pxr::GfRotation(pxr::GfVec3d(0.0, 1.0, 0.0), -res.mapping_rot[1])) *
370 pxr::GfMatrix4d().SetRotate(
371 pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -res.mapping_rot[0]));
373 pxr::GfVec3d angles = xf.DecomposeRotation(
374 pxr::GfVec3d::ZAxis(), pxr::GfVec3d::YAxis(), pxr::GfVec3d::XAxis());
376 pxr::GfVec3f rot_vec(angles[2], angles[1], angles[0]);
378 pxr::UsdGeomXformCommonAPI xform_api(dome_light);
379 xform_api.SetRotate(rot_vec, pxr::UsdGeomXformCommonAPI::RotationOrderXYZ);
388 const pxr::UsdLuxDomeLight &dome_light,
389 const double motionSampleTime)
391 if (!(scene && scene->world && dome_light)) {
395 if (!scene->world->use_nodes) {
396 scene->world->use_nodes =
true;
399 if (!scene->world->nodetree) {
401 if (!scene->world->nodetree) {
407 bNodeTree *ntree = scene->world->nodetree;
408 bNode *output =
nullptr;
409 bNode *bgshader =
nullptr;
419 else if (node->type == SH_NODE_BACKGROUND) {
437 output->locx = 300.0f;
438 output->locy = 300.0f;
442 bgshader =
append_node(output, SH_NODE_BACKGROUND,
"Background",
"Surface", ntree, 200);
457 if (shader_input && shader_input->
link) {
462 float intensity = 1.0f;
463 get_authored_value(dome_light.GetIntensityAttr(),
465 dome_light.GetPrim(),
469 intensity *=
params.light_intensity_scale;
475 pxr::SdfAssetPath tex_path;
476 bool has_tex = get_authored_value(dome_light.GetTextureFileAttr(),
478 dome_light.GetPrim(),
483 bool has_color = get_authored_value(
484 dome_light.GetColorAttr(), motionSampleTime, dome_light.GetPrim(),
usdtokens::color, &color);
508 CLOG_WARN(&
LOG,
"Couldn't create vector multiply node");
517 vec_sock = vec_sock->
next;
524 CLOG_WARN(&
LOG,
"Couldn't find vector multiply second vector socket");
540 CLOG_WARN(&
LOG,
"Couldn't create world environment texture node");
554 CLOG_WARN(&
LOG,
"Couldn't create texture coordinate node");
559 std::string resolved_path = tex_path.GetResolvedPath();
561 if (resolved_path.empty()) {
562 CLOG_WARN(&
LOG,
"Couldn't get resolved path for asset %s", tex_path.GetAssetPath().c_str());
568 CLOG_WARN(&
LOG,
"Couldn't load image file %s", resolved_path.c_str());
572 tex->
id = &image->id;
575 pxr::UsdGeomXformCache xf_cache(motionSampleTime);
576 pxr::GfMatrix4d xf = xf_cache.GetLocalToWorldTransform(dome_light.GetPrim());
578 pxr::UsdStageRefPtr
stage = dome_light.GetPrim().GetStage();
582 &
LOG,
"Couldn't get stage for dome light %s", dome_light.GetPrim().GetPath().GetText());
586 if (pxr::UsdGeomGetStageUpAxis(
stage) == pxr::UsdGeomTokens->y) {
588 xf *= pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), 90.0));
591 xf = pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), -90.0)) *
592 pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -90.0)) * xf;
594 pxr::GfVec3d angles = xf.DecomposeRotation(
595 pxr::GfVec3d::XAxis(), pxr::GfVec3d::YAxis(), pxr::GfVec3d::ZAxis());
596 pxr::GfVec3f rot_vec(-angles[0], -angles[1], -angles[2]);
599 rot_vec *=
M_PI / 180.0f;
603 socket->default_value);
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
Image * BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists=nullptr)
bool BKE_image_has_packedfile(const Image *image)
#define SH_NODE_OUTPUT_WORLD
#define SH_NODE_TEX_COORD
#define SH_NODE_VECTOR_MATH
#define SH_NODE_TEX_ENVIRONMENT
void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
File and directory operations.
int BLI_copy(const char *path_src, const char *path_dst) ATTR_NONNULL()
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define LISTBASE_FOREACH(type, var, list)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
size_t BLI_path_append(char *__restrict dst, size_t dst_maxncpy, const char *__restrict file) ATTR_NONNULL(1
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
size_t size_t BLI_path_append_dir(char *__restrict dst, size_t dst_maxncpy, const char *__restrict dir) ATTR_NONNULL(1
#define CLOG_WARN(clg_ref,...)
void DEG_id_tag_update(ID *id, unsigned int flags)
#define ID_BLEND_PATH(_bmain, _id)
@ NODE_VECTOR_MATH_MULTIPLY
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
constexpr const T & first() const
constexpr bool is_empty() const
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
void node_set_active(bNodeTree *ntree, bNode *node)
bNode * node_add_static_node(const bContext *C, bNodeTree *ntree, int type)
bNodeLink * node_add_link(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
void node_chain_iterator(const bNodeTree *ntree, const bNode *node_start, bool(*callback)(bNode *, bNode *, void *, const bool), void *userdata, bool reversed)
bNodeTree * node_tree_add_tree(Main *bmain, const char *name, const char *idname)
void node_remove_link(bNodeTree *ntree, bNodeLink *link)
bNodeSocket * node_find_socket(bNode *node, eNodeSocketInOut in_out, StringRef identifier)
void world_material_to_dome_light(const USDExportParams ¶ms, const Scene *scene, pxr::UsdStageRefPtr stage)
const char * temp_textures_dir()
static pxr::SdfPath get_unique_path(pxr::UsdStageRefPtr stage, const std::string &path)
bool should_import_asset(const std::string &path)
static Image * load_image(std::string tex_path, Main *bmain, const USDImportParams ¶ms)
std::string import_asset(const char *src, const char *import_dir, eUSDTexNameCollisionMode name_collision_mode, ReportList *reports)
static void export_texture(const USDExporterContext &usd_export_context, bNode *node)
std::string cache_image_color(const float color[4])
static bool node_search(bNode *fromnode, bNode *, void *userdata, const bool)
@ USD_TEX_NAME_COLLISION_OVERWRITE
static std::string get_tex_image_asset_filepath(const USDExporterContext &usd_export_context, bNode *node)
void dome_light_to_world_material(const USDImportParams ¶ms, const ImportSettings &, Scene *scene, Main *bmain, const pxr::UsdLuxDomeLight &dome_light, const double motionSampleTime)
void ensure_usd_source_path_prop(const std::string &path, ID *id)
static bNode * append_node(bNode *dst_node, int16_t new_node_type, const char *out_sock, const char *in_sock, bNodeTree *ntree, float offset)
static const pxr::TfToken intensity("intensity", pxr::TfToken::Immortal)
static const pxr::TfToken texture_file("texture:file", pxr::TfToken::Immortal)
static const pxr::TfToken color("color", pxr::TfToken::Immortal)
struct bNodeSocket * next