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>
20#include <pxr/usd/usdLux/domeLight_1.h>
21#include <pxr/usd/usdLux/tokens.h>
48static const pxr::TfToken
pole_axis_z(
"Z", pxr::TfToken::Immortal);
57struct WorldNtreeSearchResults {
59 pxr::UsdStageRefPtr stage;
61 std::string file_path;
63 float world_intensity = 0.0f;
64 float world_color[3]{};
65 float mapping_rot[3]{};
66 float color_mult[3]{};
68 bool background_found =
false;
69 bool env_tex_found =
false;
70 bool mult_found =
false;
72 WorldNtreeSearchResults(
const blender::io::usd::USDExportParams &in_params,
73 pxr::UsdStageRefPtr in_stage)
74 : params(in_params), stage(in_stage)
93 std::string imported_file_source_path = tex_path;
95 if (import_textures) {
100 params.import_textures_dir;
105 params.tex_name_collision_mode;
107 tex_path =
import_asset(tex_path.c_str(), textures_dir, name_collision_mode,
nullptr);
115 if (import_textures && imported_file_source_path != tex_path) {
134 int16_t new_node_type,
167 if (!(userdata && fromnode)) {
171 WorldNtreeSearchResults *res =
reinterpret_cast<WorldNtreeSearchResults *
>(userdata);
181 res->background_found =
true;
182 res->world_intensity = strength_data->value;
183 res->world_color[0] = color_data->
value[0];
184 res->world_color[1] = color_data->
value[1];
185 res->world_color[2] = color_data->
value[2];
192 if (!res->file_path.empty()) {
193 res->env_tex_found =
true;
203 res->mult_found =
true;
207 vec_sock = vec_sock->
next;
219 socket->default_value);
229 pxr::UsdStageRefPtr stage)
231 if (!(stage && scene && scene->
world)) {
235 WorldNtreeSearchResults res(
params, stage);
241 ntree->ensure_topology_cache();
243 for (
const bNode *node : bsdf_nodes) {
258 res.world_intensity = 1.0f;
260 res.background_found = !
is_zero_v3(res.world_color);
263 if (!(res.background_found || res.env_tex_found)) {
271 std::string(
params.root_prim_path) +
"/env_light");
273 pxr::UsdLuxDomeLight dome_light = pxr::UsdLuxDomeLight::Define(stage, env_light_path);
275 if (!res.env_tex_found) {
280 float fill_color[4] = {res.world_color[0], res.world_color[1], res.world_color[2], 1.0f};
283 const std::string base_path = stage->GetRootLayer()->GetRealPath();
296 if (
BLI_copy(source_path.c_str(), dest_path) != 0) {
297 CLOG_WARN(&
LOG,
"USD Export: Couldn't write world color image to %s", dest_path);
300 res.env_tex_found =
true;
302 res.file_path = dest_path;
306 if (res.env_tex_found) {
307 pxr::SdfAssetPath path(res.file_path);
308 dome_light.CreateTextureFileAttr().Set(path);
310 if (res.mult_found) {
311 pxr::GfVec3f color_val(res.color_mult[0], res.color_mult[1], res.color_mult[2]);
312 dome_light.CreateColorAttr().Set(color_val);
316 pxr::GfVec3f color_val(res.world_color[0], res.world_color[1], res.world_color[2]);
317 dome_light.CreateColorAttr().Set(color_val);
320 if (res.background_found) {
321 dome_light.CreateIntensityAttr().Set(res.world_intensity);
330 pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), 90.0)) *
331 pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), 90.0)) *
332 pxr::GfMatrix4d().SetRotate(
333 pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), -res.mapping_rot[2])) *
334 pxr::GfMatrix4d().SetRotate(
335 pxr::GfRotation(pxr::GfVec3d(0.0, 1.0, 0.0), -res.mapping_rot[1])) *
336 pxr::GfMatrix4d().SetRotate(
337 pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -res.mapping_rot[0]));
339 pxr::GfVec3d angles = xf.DecomposeRotation(
340 pxr::GfVec3d::ZAxis(), pxr::GfVec3d::YAxis(), pxr::GfVec3d::XAxis());
342 pxr::GfVec3f rot_vec(angles[2], angles[1], angles[0]);
344 pxr::UsdGeomXformCommonAPI xform_api(dome_light);
345 xform_api.SetRotate(rot_vec, pxr::UsdGeomXformCommonAPI::RotationOrderXYZ);
354 const pxr::UsdPrim &prim,
355 const double motionSampleTime)
357 if (!(scene && scene->
world && prim)) {
375 bNode *bgshader =
nullptr;
381 for (
bNode *node : ntree->all_nodes()) {
390 node->location[1] += 300;
403 output->location[0] = 300.0f;
404 output->location[1] = 300.0f;
423 if (shader_input && shader_input->
link) {
428 float intensity = dome_light_data.
intensity *
params.light_intensity_scale;
433 if (!dome_light_data.
has_tex) {
439 dome_light_data.
color.data());
456 CLOG_WARN(&
LOG,
"Couldn't create vector multiply node");
465 vec_sock = vec_sock->
next;
470 dome_light_data.
color.data());
473 CLOG_WARN(&
LOG,
"Couldn't find vector multiply second vector socket");
477 bNode *tex =
nullptr;
489 CLOG_WARN(&
LOG,
"Couldn't create world environment texture node");
502 CLOG_WARN(&
LOG,
"Couldn't create texture coordinate node");
507 std::string resolved_path = dome_light_data.
tex_path.GetResolvedPath();
509 if (resolved_path.empty()) {
511 "Couldn't get resolved path for asset %s",
512 dome_light_data.
tex_path.GetAssetPath().c_str());
518 CLOG_WARN(&
LOG,
"Couldn't load image file %s", resolved_path.c_str());
522 tex->
id = &image->
id;
525 pxr::UsdGeomXformCache xf_cache(motionSampleTime);
526 pxr::GfMatrix4d xf = xf_cache.GetLocalToWorldTransform(prim);
528 pxr::UsdStageRefPtr stage = prim.GetStage();
531 CLOG_WARN(&
LOG,
"Couldn't get stage for dome light %s", prim.GetPath().GetText());
538 const pxr::TfToken stage_up = pxr::UsdGeomGetStageUpAxis(stage);
539 const bool needs_stage_z_adjust = stage_up == pxr::UsdGeomTokens->z &&
541 pxr::UsdLuxTokens->Z,
542 pxr::UsdLuxTokens->scene);
543 const bool needs_stage_y_adjust = stage_up == pxr::UsdGeomTokens->y &&
545 if (needs_stage_z_adjust || needs_stage_y_adjust) {
546 xf *= pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 1.0, 0.0), 90.0));
548 else if (stage_up == pxr::UsdGeomTokens->
y) {
550 xf *= pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), 90.0));
554 xf = pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), -90.0)) *
555 pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -90.0)) * xf;
557 pxr::GfVec3d angles = xf.DecomposeRotation(
558 pxr::GfVec3d::XAxis(), pxr::GfVec3d::YAxis(), pxr::GfVec3d::ZAxis());
559 pxr::GfVec3f rot_vec(-angles[0], -angles[1], -angles[2]);
562 rot_vec *=
M_PI / 180.0f;
566 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
#define SH_NODE_BACKGROUND
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams ¶ms={})
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()
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
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)
@ NODE_VECTOR_MATH_MULTIPLY
#define ID_BLEND_PATH(_bmain, _id)
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
void node_remove_link(bNodeTree *ntree, bNodeLink &link)
void node_chain_iterator(const bNodeTree *ntree, const bNode *node_start, bool(*callback)(bNode *, bNode *, void *, const bool), void *userdata, bool reversed)
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)
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
void node_set_active(bNodeTree &ntree, bNode &node)
void world_material_to_dome_light(const USDExportParams ¶ms, const Scene *scene, pxr::UsdStageRefPtr stage)
const char * temp_textures_dir()
bool should_import_asset(const std::string &path)
static Image * load_image(std::string tex_path, Main *bmain, const USDImportParams ¶ms)
pxr::SdfPath get_unique_path(pxr::UsdStageRefPtr stage, const std::string &path)
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)
void dome_light_to_world_material(const USDImportParams ¶ms, Scene *scene, Main *bmain, const USDImportDomeLightData &dome_light_data, const pxr::UsdPrim &prim, const double motionSampleTime)
@ USD_TEX_NAME_COLLISION_OVERWRITE
static std::string get_tex_image_asset_filepath(const USDExporterContext &usd_export_context, bNode *node)
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 StringRef out_sock, const StringRef in_sock, bNodeTree *ntree, float offset)
static const pxr::TfToken pole_axis_z("Z", pxr::TfToken::Immortal)
struct bNodeTree * nodetree
struct bNodeSocket * next
pxr::SdfAssetPath tex_path