USD: Implement new DomeLight_1 Schema for Import
Handle the `DomeLight_1` schema for import and translate to a World material like what was already done for the original `DomeLight` schema. The primary difference is that the new schema provides a `poleAxis` attribute that authoring applications can use to remove ambiguity for the orientation of the HDRI texture. Some care was made to match `usdview` with a set of hand-crafted files. However, after matching, some real scenes ended up displaying differently. These were corrected but this could mean there's still issues that will need investigation and fixing in the future. Co-authored-by: Nig3l <nig3lpro@gmail.com> Co-authored-by: Jesse Yurkovich <jesse.y@gmail.com> Pull Request: https://projects.blender.org/blender/blender/pulls/137761
This commit is contained in:
committed by
Jesse Yurkovich
parent
0f37863fba
commit
efd871e9ef
@@ -89,6 +89,7 @@ set(SRC
|
||||
intern/usd_writer_volume.cc
|
||||
|
||||
intern/usd_reader_camera.cc
|
||||
intern/usd_reader_domelight.cc
|
||||
intern/usd_reader_curve.cc
|
||||
intern/usd_reader_geom.cc
|
||||
intern/usd_reader_instance.cc
|
||||
@@ -140,6 +141,7 @@ set(SRC
|
||||
|
||||
intern/usd_reader_camera.hh
|
||||
intern/usd_reader_curve.hh
|
||||
intern/usd_reader_domelight.hh
|
||||
intern/usd_reader_geom.hh
|
||||
intern/usd_reader_instance.hh
|
||||
intern/usd_reader_light.hh
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "IO_types.hh"
|
||||
#include "usd.hh"
|
||||
#include "usd_hook.hh"
|
||||
#include "usd_light_convert.hh"
|
||||
#include "usd_reader_domelight.hh"
|
||||
#include "usd_reader_geom.hh"
|
||||
#include "usd_reader_prim.hh"
|
||||
#include "usd_reader_stage.hh"
|
||||
@@ -236,10 +236,10 @@ static void import_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
||||
archive->collect_readers();
|
||||
|
||||
if (data->params.import_lights && data->params.create_world_material &&
|
||||
!archive->dome_lights().is_empty())
|
||||
!archive->dome_light_readers().is_empty())
|
||||
{
|
||||
dome_light_to_world_material(
|
||||
data->params, data->scene, data->bmain, archive->dome_lights().first());
|
||||
USDDomeLightReader *dome_light_reader = archive->dome_light_readers().first();
|
||||
dome_light_reader->create_object(data->scene, data->bmain);
|
||||
}
|
||||
|
||||
if (data->params.import_materials && data->params.import_all_materials) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <pxr/usd/usdGeom/xformCache.h>
|
||||
#include <pxr/usd/usdGeom/xformCommonAPI.h>
|
||||
#include <pxr/usd/usdLux/domeLight.h>
|
||||
#include <pxr/usd/usdLux/domeLight_1.h>
|
||||
#include <pxr/usd/usdLux/tokens.h>
|
||||
|
||||
#include "BKE_image.hh"
|
||||
#include "BKE_library.hh"
|
||||
@@ -42,47 +44,12 @@
|
||||
static CLG_LogRef LOG = {"io.usd"};
|
||||
|
||||
namespace usdtokens {
|
||||
// Attribute names.
|
||||
static const pxr::TfToken color("color", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken intensity("intensity", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken texture_file("texture:file", pxr::TfToken::Immortal);
|
||||
// Attribute values.
|
||||
static const pxr::TfToken pole_axis_z("Z", pxr::TfToken::Immortal);
|
||||
} // namespace usdtokens
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* If the given attribute has an authored value, return its value in the r_value
|
||||
* out parameter.
|
||||
*
|
||||
* We wish to support older UsdLux APIs in older versions of USD. For example,
|
||||
* in previous versions of the API, shader input attributes did not have the
|
||||
* "inputs:" prefix. One can provide the older input attribute name in the
|
||||
* 'fallback_attr_name' argument, and that attribute will be queried if 'attr'
|
||||
* doesn't exist or doesn't have an authored value.
|
||||
*/
|
||||
template<typename T>
|
||||
bool get_authored_value(const pxr::UsdAttribute &attr,
|
||||
const double motionSampleTime,
|
||||
const pxr::UsdPrim &prim,
|
||||
const pxr::TfToken fallback_attr_name,
|
||||
T *r_value)
|
||||
{
|
||||
if (attr && attr.HasAuthoredValue()) {
|
||||
return attr.Get<T>(r_value, motionSampleTime);
|
||||
}
|
||||
|
||||
if (!prim || fallback_attr_name.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pxr::UsdAttribute fallback_attr = prim.GetAttribute(fallback_attr_name);
|
||||
if (fallback_attr && fallback_attr.HasAuthoredValue()) {
|
||||
return fallback_attr.Get<T>(r_value, motionSampleTime);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper struct for retrieving shader information when traversing a world material
|
||||
* node chain, provided as user data for #bke::node_chain_iterator().
|
||||
@@ -377,10 +344,11 @@ void world_material_to_dome_light(const USDExportParams ¶ms,
|
||||
void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
Scene *scene,
|
||||
Main *bmain,
|
||||
const pxr::UsdLuxDomeLight &dome_light,
|
||||
const USDImportDomeLightData &dome_light_data,
|
||||
const pxr::UsdPrim &prim,
|
||||
const double motionSampleTime)
|
||||
{
|
||||
if (!(scene && scene->world && dome_light)) {
|
||||
if (!(scene && scene->world && prim)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -451,36 +419,18 @@ void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
}
|
||||
|
||||
/* Set the background shader intensity. */
|
||||
float intensity = 1.0f;
|
||||
get_authored_value(dome_light.GetIntensityAttr(),
|
||||
motionSampleTime,
|
||||
dome_light.GetPrim(),
|
||||
usdtokens::intensity,
|
||||
&intensity);
|
||||
|
||||
intensity *= params.light_intensity_scale;
|
||||
float intensity = dome_light_data.intensity * params.light_intensity_scale;
|
||||
|
||||
bNodeSocket *strength_sock = bke::node_find_socket(*bgshader, SOCK_IN, "Strength");
|
||||
((bNodeSocketValueFloat *)strength_sock->default_value)->value = intensity;
|
||||
|
||||
/* Get the dome light texture file and color. */
|
||||
pxr::SdfAssetPath tex_path;
|
||||
bool has_tex = get_authored_value(dome_light.GetTextureFileAttr(),
|
||||
motionSampleTime,
|
||||
dome_light.GetPrim(),
|
||||
usdtokens::texture_file,
|
||||
&tex_path);
|
||||
|
||||
pxr::GfVec3f color;
|
||||
bool has_color = get_authored_value(
|
||||
dome_light.GetColorAttr(), motionSampleTime, dome_light.GetPrim(), usdtokens::color, &color);
|
||||
|
||||
if (!has_tex) {
|
||||
if (!dome_light_data.has_tex) {
|
||||
/* No texture file is authored on the dome light. Set the color, if it was authored,
|
||||
* and return early. */
|
||||
if (has_color) {
|
||||
if (dome_light_data.has_color) {
|
||||
bNodeSocket *color_sock = bke::node_find_socket(*bgshader, SOCK_IN, "Color");
|
||||
copy_v3_v3(((bNodeSocketValueRGBA *)color_sock->default_value)->value, color.data());
|
||||
copy_v3_v3(((bNodeSocketValueRGBA *)color_sock->default_value)->value,
|
||||
dome_light_data.color.data());
|
||||
}
|
||||
|
||||
bke::node_set_active(*ntree, *output);
|
||||
@@ -493,7 +443,7 @@ void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
* texture output. */
|
||||
bNode *mult = nullptr;
|
||||
|
||||
if (has_color) {
|
||||
if (dome_light_data.has_color) {
|
||||
mult = append_node(bgshader, SH_NODE_VECTOR_MATH, "Vector", "Color", ntree, 200);
|
||||
|
||||
if (!mult) {
|
||||
@@ -510,7 +460,8 @@ void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
}
|
||||
|
||||
if (vec_sock) {
|
||||
copy_v3_v3(((bNodeSocketValueVector *)vec_sock->default_value)->value, color.data());
|
||||
copy_v3_v3(((bNodeSocketValueVector *)vec_sock->default_value)->value,
|
||||
dome_light_data.color.data());
|
||||
}
|
||||
else {
|
||||
CLOG_WARN(&LOG, "Couldn't find vector multiply second vector socket");
|
||||
@@ -547,10 +498,12 @@ void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
}
|
||||
|
||||
/* Load the texture image. */
|
||||
std::string resolved_path = tex_path.GetResolvedPath();
|
||||
std::string resolved_path = dome_light_data.tex_path.GetResolvedPath();
|
||||
|
||||
if (resolved_path.empty()) {
|
||||
CLOG_WARN(&LOG, "Couldn't get resolved path for asset %s", tex_path.GetAssetPath().c_str());
|
||||
CLOG_WARN(&LOG,
|
||||
"Couldn't get resolved path for asset %s",
|
||||
dome_light_data.tex_path.GetAssetPath().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -564,21 +517,34 @@ void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
|
||||
/* Set the transform. */
|
||||
pxr::UsdGeomXformCache xf_cache(motionSampleTime);
|
||||
pxr::GfMatrix4d xf = xf_cache.GetLocalToWorldTransform(dome_light.GetPrim());
|
||||
pxr::GfMatrix4d xf = xf_cache.GetLocalToWorldTransform(prim);
|
||||
|
||||
pxr::UsdStageRefPtr stage = dome_light.GetPrim().GetStage();
|
||||
pxr::UsdStageRefPtr stage = prim.GetStage();
|
||||
|
||||
if (!stage) {
|
||||
CLOG_WARN(
|
||||
&LOG, "Couldn't get stage for dome light %s", dome_light.GetPrim().GetPath().GetText());
|
||||
CLOG_WARN(&LOG, "Couldn't get stage for dome light %s", prim.GetPath().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pxr::UsdGeomGetStageUpAxis(stage) == pxr::UsdGeomTokens->y) {
|
||||
/* Note: This logic tries to produce identical results to `usdview` as of USD 25.05.
|
||||
* However, `usdview` seems to handle Y-Up stages differently; some scenes match while others
|
||||
* do not unless we keep the second conditional below (+90 on x-axis). */
|
||||
const pxr::TfToken stage_up = pxr::UsdGeomGetStageUpAxis(stage);
|
||||
const bool needs_stage_z_adjust = stage_up == pxr::UsdGeomTokens->z &&
|
||||
ELEM(dome_light_data.pole_axis,
|
||||
pxr::UsdLuxTokens->Z,
|
||||
pxr::UsdLuxTokens->scene);
|
||||
const bool needs_stage_y_adjust = stage_up == pxr::UsdGeomTokens->y &&
|
||||
ELEM(dome_light_data.pole_axis, pxr::UsdLuxTokens->Z);
|
||||
if (needs_stage_z_adjust || needs_stage_y_adjust) {
|
||||
xf *= pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 1.0, 0.0), 90.0));
|
||||
}
|
||||
else if (stage_up == pxr::UsdGeomTokens->y) {
|
||||
/* Convert from Y-up to Z-up with a 90 degree rotation about the X-axis. */
|
||||
xf *= pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), 90.0));
|
||||
}
|
||||
|
||||
/* Rotate into Blender's frame of reference. */
|
||||
xf = pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), -90.0)) *
|
||||
pxr::GfMatrix4d().SetRotate(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -90.0)) * xf;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <pxr/usd/usd/common.h>
|
||||
#include <pxr/usd/usdLux/domeLight.h>
|
||||
|
||||
struct Main;
|
||||
struct Scene;
|
||||
@@ -14,6 +13,18 @@ namespace blender::io::usd {
|
||||
struct USDExportParams;
|
||||
struct USDImportParams;
|
||||
|
||||
/* This struct contains all DomeLight attribute needed to
|
||||
* create a world environment */
|
||||
struct USDImportDomeLightData {
|
||||
float intensity;
|
||||
pxr::GfVec3f color;
|
||||
pxr::SdfAssetPath tex_path;
|
||||
pxr::TfToken pole_axis;
|
||||
|
||||
bool has_color;
|
||||
bool has_tex;
|
||||
};
|
||||
|
||||
/**
|
||||
* If the Blender scene has an environment texture,
|
||||
* export it as a USD dome light.
|
||||
@@ -25,7 +36,8 @@ void world_material_to_dome_light(const USDExportParams ¶ms,
|
||||
void dome_light_to_world_material(const USDImportParams ¶ms,
|
||||
Scene *scene,
|
||||
Main *bmain,
|
||||
const pxr::UsdLuxDomeLight &dome_light,
|
||||
const USDImportDomeLightData &dome_light_data,
|
||||
const pxr::UsdPrim &prim,
|
||||
const double motionSampleTime = 0.0);
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
||||
120
source/blender/io/usd/intern/usd_reader_domelight.cc
Normal file
120
source/blender/io/usd/intern/usd_reader_domelight.cc
Normal file
@@ -0,0 +1,120 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "usd_reader_domelight.hh"
|
||||
#include "usd_light_convert.hh"
|
||||
|
||||
#include <pxr/usd/usdLux/domeLight.h>
|
||||
#include <pxr/usd/usdLux/domeLight_1.h>
|
||||
#include <pxr/usd/usdLux/tokens.h>
|
||||
|
||||
namespace usdtokens {
|
||||
// Attribute names.
|
||||
static const pxr::TfToken color("color", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken intensity("intensity", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken texture_file("texture:file", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken pole_axis("poleAxis", pxr::TfToken::Immortal);
|
||||
} // namespace usdtokens
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
/**
|
||||
* If the given attribute has an authored value, return its value in the r_value
|
||||
* out parameter.
|
||||
*
|
||||
* We wish to support older UsdLux APIs in older versions of USD. For example,
|
||||
* in previous versions of the API, shader input attributes did not have the
|
||||
* "inputs:" prefix. One can provide the older input attribute name in the
|
||||
* 'fallback_attr_name' argument, and that attribute will be queried if 'attr'
|
||||
* doesn't exist or doesn't have an authored value.
|
||||
*/
|
||||
template<typename T>
|
||||
static bool get_authored_value(const pxr::UsdAttribute &attr,
|
||||
const double motionSampleTime,
|
||||
const pxr::UsdPrim &prim,
|
||||
const pxr::TfToken fallback_attr_name,
|
||||
T *r_value)
|
||||
{
|
||||
if (attr && attr.HasAuthoredValue()) {
|
||||
return attr.Get<T>(r_value, motionSampleTime);
|
||||
}
|
||||
|
||||
if (!prim || fallback_attr_name.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pxr::UsdAttribute fallback_attr = prim.GetAttribute(fallback_attr_name);
|
||||
if (fallback_attr && fallback_attr.HasAuthoredValue()) {
|
||||
return fallback_attr.Get<T>(r_value, motionSampleTime);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T> static float get_intensity(const T &dome_light, float motionSampleTime)
|
||||
{
|
||||
float intensity = 1.0f;
|
||||
get_authored_value(dome_light.GetIntensityAttr(),
|
||||
motionSampleTime,
|
||||
dome_light.GetPrim(),
|
||||
usdtokens::intensity,
|
||||
&intensity);
|
||||
return intensity;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool get_tex_path(const T &dome_light, float motionSampleTime, pxr::SdfAssetPath *tex_path)
|
||||
{
|
||||
bool has_tex = get_authored_value(dome_light.GetTextureFileAttr(),
|
||||
motionSampleTime,
|
||||
dome_light.GetPrim(),
|
||||
usdtokens::texture_file,
|
||||
tex_path);
|
||||
return has_tex;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool get_color(const T &dome_light, float motionSampleTime, pxr::GfVec3f *color)
|
||||
{
|
||||
bool has_color = get_authored_value(
|
||||
dome_light.GetColorAttr(), motionSampleTime, dome_light.GetPrim(), usdtokens::color, color);
|
||||
return has_color;
|
||||
}
|
||||
|
||||
static pxr::TfToken get_pole_axis(const pxr::UsdLuxDomeLight_1 &dome_light, float motionSampleTime)
|
||||
{
|
||||
pxr::TfToken pole_axis = pxr::UsdLuxTokens->scene;
|
||||
get_authored_value(
|
||||
dome_light.GetPoleAxisAttr(), motionSampleTime, dome_light.GetPrim(), {}, &pole_axis);
|
||||
return pole_axis;
|
||||
}
|
||||
|
||||
void USDDomeLightReader::create_object(Scene *scene, Main *bmain)
|
||||
{
|
||||
USDImportDomeLightData dome_light_data;
|
||||
|
||||
/* Time varying dome lights are not currently supported. */
|
||||
const double motionSampleTime = 0.0;
|
||||
|
||||
if (prim_.IsA<pxr::UsdLuxDomeLight>()) {
|
||||
pxr::UsdLuxDomeLight dome_light = pxr::UsdLuxDomeLight(prim_);
|
||||
dome_light_data.intensity = get_intensity(dome_light, motionSampleTime);
|
||||
dome_light_data.has_tex = get_tex_path(
|
||||
dome_light, motionSampleTime, &dome_light_data.tex_path);
|
||||
dome_light_data.has_color = get_color(dome_light, motionSampleTime, &dome_light_data.color);
|
||||
dome_light_data.pole_axis = pxr::UsdLuxTokens->Y;
|
||||
}
|
||||
else if (prim_.IsA<pxr::UsdLuxDomeLight_1>()) {
|
||||
pxr::UsdLuxDomeLight_1 dome_light = pxr::UsdLuxDomeLight_1(prim_);
|
||||
dome_light_data.intensity = get_intensity(dome_light, motionSampleTime);
|
||||
dome_light_data.has_tex = get_tex_path(
|
||||
dome_light, motionSampleTime, &dome_light_data.tex_path);
|
||||
dome_light_data.has_color = get_color(dome_light, motionSampleTime, &dome_light_data.color);
|
||||
dome_light_data.pole_axis = get_pole_axis(dome_light, motionSampleTime);
|
||||
}
|
||||
|
||||
dome_light_to_world_material(import_params_, scene, bmain, dome_light_data, prim_);
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
39
source/blender/io/usd/intern/usd_reader_domelight.hh
Normal file
39
source/blender/io/usd/intern/usd_reader_domelight.hh
Normal file
@@ -0,0 +1,39 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "usd.hh"
|
||||
#include "usd_reader_prim.hh"
|
||||
|
||||
#include <pxr/usd/usdLux/domeLight.h>
|
||||
#include <pxr/usd/usdLux/domeLight_1.h>
|
||||
|
||||
struct Main;
|
||||
struct Scene;
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
class USDDomeLightReader : public USDPrimReader {
|
||||
|
||||
public:
|
||||
USDDomeLightReader(const pxr::UsdPrim &prim,
|
||||
const USDImportParams &import_params,
|
||||
const ImportSettings &settings)
|
||||
: USDPrimReader(prim, import_params, settings)
|
||||
{
|
||||
}
|
||||
|
||||
bool valid() const override
|
||||
{
|
||||
return prim_.IsA<pxr::UsdLuxDomeLight>() || prim_.IsA<pxr::UsdLuxDomeLight_1>();
|
||||
}
|
||||
|
||||
/* Until Blender supports DomeLight objects natively, use a separate create_object overload that
|
||||
* allows the caller to pass in the required Scene data. */
|
||||
|
||||
void create_object(Main * /*bmain*/) override{};
|
||||
void create_object(Scene *scene, Main *bmain);
|
||||
};
|
||||
|
||||
} // namespace blender::io::usd
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <pxr/usd/usdGeom/tokens.h>
|
||||
#include <pxr/usd/usdGeom/xform.h>
|
||||
#include <pxr/usd/usdLux/boundableLightBase.h>
|
||||
#include <pxr/usd/usdLux/domeLight.h>
|
||||
#include <pxr/usd/usdLux/domeLight_1.h>
|
||||
#include <pxr/usd/usdLux/nonboundableLightBase.h>
|
||||
#include <pxr/usd/usdShade/material.h>
|
||||
|
||||
@@ -252,7 +254,9 @@ USDPrimReader *USDStageReader::create_reader_if_allowed(const pxr::UsdPrim &prim
|
||||
if (params_.import_meshes && prim.IsA<pxr::UsdGeomMesh>()) {
|
||||
return new USDMeshReader(prim, params_, settings_);
|
||||
}
|
||||
if (params_.import_lights && prim.IsA<pxr::UsdLuxDomeLight>()) {
|
||||
if (params_.import_lights &&
|
||||
(prim.IsA<pxr::UsdLuxDomeLight>() || prim.IsA<pxr::UsdLuxDomeLight_1>()))
|
||||
{
|
||||
/* Dome lights are handled elsewhere. */
|
||||
return nullptr;
|
||||
}
|
||||
@@ -297,7 +301,7 @@ USDPrimReader *USDStageReader::create_reader(const pxr::UsdPrim &prim)
|
||||
if (prim.IsA<pxr::UsdGeomMesh>()) {
|
||||
return new USDMeshReader(prim, params_, settings_);
|
||||
}
|
||||
if (prim.IsA<pxr::UsdLuxDomeLight>()) {
|
||||
if (prim.IsA<pxr::UsdLuxDomeLight>() || prim.IsA<pxr::UsdLuxDomeLight_1>()) {
|
||||
/* We don't handle dome lights. */
|
||||
return nullptr;
|
||||
}
|
||||
@@ -440,8 +444,10 @@ USDPrimReader *USDStageReader::collect_readers(const pxr::UsdPrim &prim,
|
||||
}
|
||||
}
|
||||
|
||||
if (prim.IsA<pxr::UsdLuxDomeLight>()) {
|
||||
dome_lights_.append(pxr::UsdLuxDomeLight(prim));
|
||||
if (prim.IsA<pxr::UsdLuxDomeLight>() || prim.IsA<pxr::UsdLuxDomeLight_1>()) {
|
||||
USDDomeLightReader *reader = new USDDomeLightReader(prim, params_, settings_);
|
||||
reader->incref();
|
||||
dome_light_readers_.append(reader);
|
||||
}
|
||||
|
||||
pxr::Usd_PrimFlagsConjunction filter_flags = pxr::UsdPrimIsActive && pxr::UsdPrimIsLoaded &&
|
||||
@@ -529,7 +535,6 @@ void USDStageReader::collect_readers()
|
||||
}
|
||||
|
||||
clear_readers();
|
||||
dome_lights_.clear();
|
||||
|
||||
/* Identify paths to point instancer prototypes, as these will be converted
|
||||
* in a separate pass over the stage. */
|
||||
@@ -733,6 +738,11 @@ void USDStageReader::clear_readers()
|
||||
}
|
||||
}
|
||||
instancer_proto_readers_.clear();
|
||||
|
||||
for (USDDomeLightReader *reader : dome_light_readers_) {
|
||||
decref(reader);
|
||||
}
|
||||
dome_light_readers_.clear();
|
||||
}
|
||||
|
||||
void USDStageReader::sort_readers()
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#include "usd.hh"
|
||||
#include "usd_hash_types.hh"
|
||||
#include "usd_reader_domelight.hh"
|
||||
#include "usd_reader_prim.hh"
|
||||
|
||||
#include <pxr/usd/usdGeom/imageable.h>
|
||||
#include <pxr/usd/usdLux/domeLight.h>
|
||||
|
||||
struct Collection;
|
||||
struct ImportSettings;
|
||||
@@ -42,7 +42,7 @@ class USDStageReader {
|
||||
|
||||
/* USD dome lights are converted to a world material,
|
||||
* rather than light objects, so are handled differently */
|
||||
blender::Vector<pxr::UsdLuxDomeLight> dome_lights_;
|
||||
blender::Vector<USDDomeLightReader *> dome_light_readers_;
|
||||
|
||||
/* USD material prim paths encountered during stage
|
||||
* traversal, for importing unused materials. */
|
||||
@@ -128,9 +128,9 @@ class USDStageReader {
|
||||
return readers_;
|
||||
};
|
||||
|
||||
const blender::Vector<pxr::UsdLuxDomeLight> &dome_lights() const
|
||||
const blender::Vector<USDDomeLightReader *> &dome_light_readers() const
|
||||
{
|
||||
return dome_lights_;
|
||||
return dome_light_readers_;
|
||||
};
|
||||
|
||||
void sort_readers();
|
||||
|
||||
123
tests/files/usd/usd_dome_light_1_stageY_poleDefault.usda
Normal file
123
tests/files/usd/usd_dome_light_1_stageY_poleDefault.usda
Normal file
@@ -0,0 +1,123 @@
|
||||
#usda 1.0
|
||||
(
|
||||
defaultPrim = "root"
|
||||
doc = "Blender v4.5.0 Alpha"
|
||||
metersPerUnit = 1
|
||||
upAxis = "Y"
|
||||
)
|
||||
|
||||
def Xform "root" (
|
||||
customData = {
|
||||
dictionary Blender = {
|
||||
bool generated = 1
|
||||
}
|
||||
}
|
||||
)
|
||||
{
|
||||
def DomeLight_1 "env_light"
|
||||
{
|
||||
float inputs:intensity = 1
|
||||
asset inputs:texture:file = @./textures/test_single.png@
|
||||
float3 xformOp:rotateXYZ = (90, 0, 90)
|
||||
uniform token[] xformOpOrder = ["xformOp:rotateXYZ"]
|
||||
}
|
||||
|
||||
def Xform "Cube"
|
||||
{
|
||||
def Mesh "Cube" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
|
||||
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
|
||||
int[] faceVertexIndices = [0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1]
|
||||
rel material:binding = </root/_materials/Material>
|
||||
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [(1, 1, 1), (1, 1, -1), (1, -1, 1), (1, -1, -1), (-1, 1, 1), (-1, 1, -1), (-1, -1, 1), (-1, -1, -1)]
|
||||
bool[] primvars:sharp_face = [1, 1, 1, 1, 1, 1] (
|
||||
interpolation = "uniform"
|
||||
)
|
||||
texCoord2f[] primvars:st = [(0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
}
|
||||
}
|
||||
|
||||
def Xform "Cube_001"
|
||||
{
|
||||
float3 xformOp:rotateXYZ = (0, -0, 0)
|
||||
float3 xformOp:scale = (0.2904613, 0.2904613, 0.2904613)
|
||||
double3 xformOp:translate = (0, 0, 1.6628384590148926)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Mesh "Cube_001" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 0.9999993)]
|
||||
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
|
||||
int[] faceVertexIndices = [0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1]
|
||||
rel material:binding = </root/_materials/Material>
|
||||
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [(0.24238217, 0.24238217, 0.9999993), (1, 1, -1), (0.24238217, -0.24238217, 0.9999993), (1, -1, -1), (-0.24238217, 0.24238217, 0.9999993), (-1, 1, -1), (-0.24238217, -0.24238217, 0.9999993), (-1, -1, -1)]
|
||||
bool[] primvars:sharp_face = [1, 1, 1, 1, 1, 1] (
|
||||
interpolation = "uniform"
|
||||
)
|
||||
texCoord2f[] primvars:st = [(0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
}
|
||||
}
|
||||
|
||||
def Xform "Camera"
|
||||
{
|
||||
custom string userProperties:blender:object_name = "Camera"
|
||||
float3 xformOp:rotateXYZ = (77.15932, -0.000010048663, 45.891956)
|
||||
float3 xformOp:scale = (0.99999994, 1, 0.99999994)
|
||||
double3 xformOp:translate = (7.904968738555908, -7.6511077880859375, 2.4478447437286377)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Camera "Camera"
|
||||
{
|
||||
float2 clippingRange = (0.1, 100)
|
||||
float focalLength = 0.5
|
||||
float horizontalAperture = 0.36
|
||||
token projection = "perspective"
|
||||
custom string userProperties:blender:data_name = "Camera"
|
||||
float verticalAperture = 0.2025
|
||||
}
|
||||
}
|
||||
|
||||
def Scope "_materials"
|
||||
{
|
||||
def Material "Material"
|
||||
{
|
||||
token outputs:surface.connect = </root/_materials/Material/Principled_BSDF.outputs:surface>
|
||||
|
||||
def Shader "Principled_BSDF"
|
||||
{
|
||||
uniform token info:id = "UsdPreviewSurface"
|
||||
float inputs:clearcoat = 0
|
||||
float inputs:clearcoatRoughness = 0.03
|
||||
color3f inputs:diffuseColor = (0.8, 0.8, 0.8)
|
||||
float inputs:ior = 1.45
|
||||
float inputs:metallic = 0
|
||||
float inputs:opacity = 1
|
||||
float inputs:roughness = 0.5
|
||||
float inputs:specular = 0.5
|
||||
token outputs:surface
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
124
tests/files/usd/usd_dome_light_1_stageZ_poleY.usda
Normal file
124
tests/files/usd/usd_dome_light_1_stageZ_poleY.usda
Normal file
@@ -0,0 +1,124 @@
|
||||
#usda 1.0
|
||||
(
|
||||
defaultPrim = "root"
|
||||
doc = "Blender v4.5.0 Alpha"
|
||||
metersPerUnit = 1
|
||||
upAxis = "Z"
|
||||
)
|
||||
|
||||
def Xform "root" (
|
||||
customData = {
|
||||
dictionary Blender = {
|
||||
bool generated = 1
|
||||
}
|
||||
}
|
||||
)
|
||||
{
|
||||
def DomeLight_1 "env_light"
|
||||
{
|
||||
float inputs:intensity = 1
|
||||
asset inputs:texture:file = @./textures/test_single.png@
|
||||
float3 xformOp:rotateXYZ = (90, 0, 90)
|
||||
uniform token[] xformOpOrder = ["xformOp:rotateXYZ"]
|
||||
uniform token poleAxis = "Y"
|
||||
}
|
||||
|
||||
def Xform "Cube"
|
||||
{
|
||||
def Mesh "Cube" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
|
||||
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
|
||||
int[] faceVertexIndices = [0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1]
|
||||
rel material:binding = </root/_materials/Material>
|
||||
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [(1, 1, 1), (1, 1, -1), (1, -1, 1), (1, -1, -1), (-1, 1, 1), (-1, 1, -1), (-1, -1, 1), (-1, -1, -1)]
|
||||
bool[] primvars:sharp_face = [1, 1, 1, 1, 1, 1] (
|
||||
interpolation = "uniform"
|
||||
)
|
||||
texCoord2f[] primvars:st = [(0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
}
|
||||
}
|
||||
|
||||
def Xform "Cube_001"
|
||||
{
|
||||
float3 xformOp:rotateXYZ = (0, -0, 0)
|
||||
float3 xformOp:scale = (0.2904613, 0.2904613, 0.2904613)
|
||||
double3 xformOp:translate = (0, 0, 1.6628384590148926)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Mesh "Cube_001" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 0.9999993)]
|
||||
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
|
||||
int[] faceVertexIndices = [0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1]
|
||||
rel material:binding = </root/_materials/Material>
|
||||
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [(0.24238217, 0.24238217, 0.9999993), (1, 1, -1), (0.24238217, -0.24238217, 0.9999993), (1, -1, -1), (-0.24238217, 0.24238217, 0.9999993), (-1, 1, -1), (-0.24238217, -0.24238217, 0.9999993), (-1, -1, -1)]
|
||||
bool[] primvars:sharp_face = [1, 1, 1, 1, 1, 1] (
|
||||
interpolation = "uniform"
|
||||
)
|
||||
texCoord2f[] primvars:st = [(0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
}
|
||||
}
|
||||
|
||||
def Xform "Camera"
|
||||
{
|
||||
custom string userProperties:blender:object_name = "Camera"
|
||||
float3 xformOp:rotateXYZ = (77.15932, -0.000010048663, 45.891956)
|
||||
float3 xformOp:scale = (0.99999994, 1, 0.99999994)
|
||||
double3 xformOp:translate = (7.904968738555908, -7.6511077880859375, 2.4478447437286377)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Camera "Camera"
|
||||
{
|
||||
float2 clippingRange = (0.1, 100)
|
||||
float focalLength = 0.5
|
||||
float horizontalAperture = 0.36
|
||||
token projection = "perspective"
|
||||
custom string userProperties:blender:data_name = "Camera"
|
||||
float verticalAperture = 0.2025
|
||||
}
|
||||
}
|
||||
|
||||
def Scope "_materials"
|
||||
{
|
||||
def Material "Material"
|
||||
{
|
||||
token outputs:surface.connect = </root/_materials/Material/Principled_BSDF.outputs:surface>
|
||||
|
||||
def Shader "Principled_BSDF"
|
||||
{
|
||||
uniform token info:id = "UsdPreviewSurface"
|
||||
float inputs:clearcoat = 0
|
||||
float inputs:clearcoatRoughness = 0.03
|
||||
color3f inputs:diffuseColor = (0.8, 0.8, 0.8)
|
||||
float inputs:ior = 1.45
|
||||
float inputs:metallic = 0
|
||||
float inputs:opacity = 1
|
||||
float inputs:roughness = 0.5
|
||||
float inputs:specular = 0.5
|
||||
token outputs:surface
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
124
tests/files/usd/usd_dome_light_1_stageZ_poleZ.usda
Normal file
124
tests/files/usd/usd_dome_light_1_stageZ_poleZ.usda
Normal file
@@ -0,0 +1,124 @@
|
||||
#usda 1.0
|
||||
(
|
||||
defaultPrim = "root"
|
||||
doc = "Blender v4.5.0 Alpha"
|
||||
metersPerUnit = 1
|
||||
upAxis = "Z"
|
||||
)
|
||||
|
||||
def Xform "root" (
|
||||
customData = {
|
||||
dictionary Blender = {
|
||||
bool generated = 1
|
||||
}
|
||||
}
|
||||
)
|
||||
{
|
||||
def DomeLight_1 "env_light"
|
||||
{
|
||||
float inputs:intensity = 1
|
||||
asset inputs:texture:file = @./textures/test_single.png@
|
||||
float3 xformOp:rotateXYZ = (90, 0, 90)
|
||||
uniform token[] xformOpOrder = ["xformOp:rotateXYZ"]
|
||||
uniform token poleAxis = "Z"
|
||||
}
|
||||
|
||||
def Xform "Cube"
|
||||
{
|
||||
def Mesh "Cube" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
|
||||
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
|
||||
int[] faceVertexIndices = [0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1]
|
||||
rel material:binding = </root/_materials/Material>
|
||||
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [(1, 1, 1), (1, 1, -1), (1, -1, 1), (1, -1, -1), (-1, 1, 1), (-1, 1, -1), (-1, -1, 1), (-1, -1, -1)]
|
||||
bool[] primvars:sharp_face = [1, 1, 1, 1, 1, 1] (
|
||||
interpolation = "uniform"
|
||||
)
|
||||
texCoord2f[] primvars:st = [(0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
}
|
||||
}
|
||||
|
||||
def Xform "Cube_001"
|
||||
{
|
||||
float3 xformOp:rotateXYZ = (0, -0, 0)
|
||||
float3 xformOp:scale = (0.2904613, 0.2904613, 0.2904613)
|
||||
double3 xformOp:translate = (0, 0, 1.6628384590148926)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Mesh "Cube_001" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 0.9999993)]
|
||||
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
|
||||
int[] faceVertexIndices = [0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1]
|
||||
rel material:binding = </root/_materials/Material>
|
||||
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (0, -0.9351529, 0.3542444), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (-0.9351529, 0, 0.35424438), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0.9351529, 0, 0.35424438), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444), (0, 0.9351529, 0.3542444)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [(0.24238217, 0.24238217, 0.9999993), (1, 1, -1), (0.24238217, -0.24238217, 0.9999993), (1, -1, -1), (-0.24238217, 0.24238217, 0.9999993), (-1, 1, -1), (-0.24238217, -0.24238217, 0.9999993), (-1, -1, -1)]
|
||||
bool[] primvars:sharp_face = [1, 1, 1, 1, 1, 1] (
|
||||
interpolation = "uniform"
|
||||
)
|
||||
texCoord2f[] primvars:st = [(0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5)] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
}
|
||||
}
|
||||
|
||||
def Xform "Camera"
|
||||
{
|
||||
custom string userProperties:blender:object_name = "Camera"
|
||||
float3 xformOp:rotateXYZ = (77.15932, -0.000010048663, 45.891956)
|
||||
float3 xformOp:scale = (0.99999994, 1, 0.99999994)
|
||||
double3 xformOp:translate = (7.904968738555908, -7.6511077880859375, 2.4478447437286377)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Camera "Camera"
|
||||
{
|
||||
float2 clippingRange = (0.1, 100)
|
||||
float focalLength = 0.5
|
||||
float horizontalAperture = 0.36
|
||||
token projection = "perspective"
|
||||
custom string userProperties:blender:data_name = "Camera"
|
||||
float verticalAperture = 0.2025
|
||||
}
|
||||
}
|
||||
|
||||
def Scope "_materials"
|
||||
{
|
||||
def Material "Material"
|
||||
{
|
||||
token outputs:surface.connect = </root/_materials/Material/Principled_BSDF.outputs:surface>
|
||||
|
||||
def Shader "Principled_BSDF"
|
||||
{
|
||||
uniform token info:id = "UsdPreviewSurface"
|
||||
float inputs:clearcoat = 0
|
||||
float inputs:clearcoatRoughness = 0.03
|
||||
color3f inputs:diffuseColor = (0.8, 0.8, 0.8)
|
||||
float inputs:ior = 1.45
|
||||
float inputs:metallic = 0
|
||||
float inputs:opacity = 1
|
||||
float inputs:roughness = 0.5
|
||||
float inputs:specular = 0.5
|
||||
token outputs:surface
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1204,6 +1204,29 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.assertEqual(blender_light.shape, 'DISK') # We read as disk to mirror what USD supports
|
||||
self.assertAlmostEqual(blender_light.size, 4, 3)
|
||||
|
||||
def test_import_dome_lights(self):
|
||||
"""Test importing dome lights and verify their rotations."""
|
||||
|
||||
# Test files and their expected EnvironmentTexture Mapping rotation values
|
||||
tests = [
|
||||
("usd_dome_light_1_stageZ_poleY.usda", [0.0, 0.0, 0.0]),
|
||||
("usd_dome_light_1_stageZ_poleZ.usda", [0.0, -1.5708, 0.0]),
|
||||
("usd_dome_light_1_stageY_poleDefault.usda", [-1.5708, 0.0, 0.0])
|
||||
]
|
||||
|
||||
for test_name, expected_rot in tests:
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend"))
|
||||
|
||||
infile = str(self.testdir / test_name)
|
||||
res = bpy.ops.wm.usd_import(filepath=infile)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to import USD file {infile}")
|
||||
|
||||
# Validate that the Mapping node on the World Material is set to the correct rotation
|
||||
world = bpy.data.worlds["World"]
|
||||
node = world.node_tree.nodes["Mapping"]
|
||||
self.assertEqual(
|
||||
self.round_vector(node.inputs[2].default_value), expected_rot, f"Incorrect rotation for {test_name}")
|
||||
|
||||
def check_attribute(self, blender_data, attribute_name, domain, data_type, elements_len):
|
||||
attr = blender_data.attributes[attribute_name]
|
||||
self.assertEqual(attr.domain, domain)
|
||||
|
||||
Reference in New Issue
Block a user