Cycles: Add support for "stageMetersPerUnit" Hydra render setting

This can be useful to match transforms to what native Cycles
would see in Blender, as USD typically uses centimeters, but
Blender uses meters. This patch also fixes the hardcoded focal
length multiplicator, which is now using the same units as
everything else. Default of "stageMetersPerUnit" is 0.01 to match
the USD default of centimeters.

Differential Revision: https://developer.blender.org/D14630
This commit is contained in:
Patrick Mours 2022-04-12 18:08:25 +02:00
parent 3a88f151c4
commit c31b89e76e
7 changed files with 91 additions and 33 deletions

View File

@ -3,6 +3,7 @@
* Copyright 2022 Blender Foundation */
#include "hydra/camera.h"
#include "hydra/session.h"
#include "scene/camera.h"
#include <pxr/base/gf/frustum.h>
@ -12,6 +13,19 @@
HDCYCLES_NAMESPACE_OPEN_SCOPE
extern Transform convert_transform(const GfMatrix4d &matrix);
Transform convert_camera_transform(const GfMatrix4d &matrix, float metersPerUnit)
{
Transform t = convert_transform(matrix);
// Flip Z axis
t.x.z *= -1.0f;
t.y.z *= -1.0f;
t.z.z *= -1.0f;
// Scale translation
t.x.w *= metersPerUnit;
t.y.w *= metersPerUnit;
t.z.w *= metersPerUnit;
return t;
}
#if PXR_VERSION < 2102
// clang-format off
@ -61,13 +75,20 @@ void HdCyclesCamera::Sync(HdSceneDelegate *sceneDelegate,
if (*dirtyBits & DirtyBits::DirtyTransform) {
sceneDelegate->SampleTransform(id, &_transformSamples);
bool transform_found = false;
for (size_t i = 0; i < _transformSamples.count; ++i) {
if (_transformSamples.times[i] == 0.0f) {
_transform = _transformSamples.values[i];
_data.SetTransform(_transform);
transform_found = true;
break;
}
}
if (!transform_found && _transformSamples.count) {
_transform = _transformSamples.values[0];
_data.SetTransform(_transform);
}
}
#else
if (*dirtyBits & DirtyBits::DirtyViewMatrix) {
@ -236,18 +257,21 @@ void HdCyclesCamera::Finalize(HdRenderParam *renderParam)
HdCamera::Finalize(renderParam);
}
void HdCyclesCamera::ApplyCameraSettings(Camera *cam) const
void HdCyclesCamera::ApplyCameraSettings(HdRenderParam *renderParam, Camera *cam) const
{
ApplyCameraSettings(_data, _windowPolicy, cam);
ApplyCameraSettings(renderParam, _data, _windowPolicy, cam);
const float metersPerUnit = static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
array<Transform> motion(_transformSamples.count);
for (size_t i = 0; i < _transformSamples.count; ++i)
motion[i] = convert_transform(_transformSamples.values[i]) *
transform_scale(1.0f, 1.0f, -1.0f);
for (size_t i = 0; i < _transformSamples.count; ++i) {
motion[i] = convert_camera_transform(_transformSamples.values[i], metersPerUnit);
}
cam->set_motion(motion);
}
void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
void HdCyclesCamera::ApplyCameraSettings(HdRenderParam *renderParam,
const GfCamera &dataUnconformedWindow,
CameraUtilConformWindowPolicy windowPolicy,
Camera *cam)
{
@ -261,20 +285,22 @@ void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
GfCamera::Orthographic == CAMERA_ORTHOGRAPHIC);
cam->set_camera_type(static_cast<CameraType>(data.GetProjection()));
const float metersPerUnit = static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
auto viewplane = data.GetFrustum().GetWindow();
auto focalLength = 1.0f;
if (data.GetProjection() == GfCamera::Perspective) {
viewplane *= 2.0 / viewplane.GetSize()[1]; // Normalize viewplane
focalLength = data.GetFocalLength() * 1e-3f;
focalLength = data.GetFocalLength() * GfCamera::FOCAL_LENGTH_UNIT * metersPerUnit;
cam->set_fov(GfDegreesToRadians(data.GetFieldOfView(GfCamera::FOVVertical)));
}
cam->set_sensorwidth(data.GetHorizontalAperture() * GfCamera::APERTURE_UNIT);
cam->set_sensorheight(data.GetVerticalAperture() * GfCamera::APERTURE_UNIT);
cam->set_sensorwidth(data.GetHorizontalAperture() * GfCamera::APERTURE_UNIT * metersPerUnit);
cam->set_sensorheight(data.GetVerticalAperture() * GfCamera::APERTURE_UNIT * metersPerUnit);
cam->set_nearclip(data.GetClippingRange().GetMin());
cam->set_farclip(data.GetClippingRange().GetMax());
cam->set_nearclip(data.GetClippingRange().GetMin() * metersPerUnit);
cam->set_farclip(data.GetClippingRange().GetMax() * metersPerUnit);
cam->set_viewplane_left(viewplane.GetMin()[0]);
cam->set_viewplane_right(viewplane.GetMax()[0]);
@ -282,14 +308,15 @@ void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
cam->set_viewplane_top(viewplane.GetMax()[1]);
if (data.GetFStop() != 0.0f) {
cam->set_focaldistance(data.GetFocusDistance());
cam->set_focaldistance(data.GetFocusDistance() * metersPerUnit);
cam->set_aperturesize(focalLength / (2.0f * data.GetFStop()));
}
cam->set_matrix(convert_transform(data.GetTransform()) * transform_scale(1.0f, 1.0f, -1.0f));
cam->set_matrix(convert_camera_transform(data.GetTransform(), metersPerUnit));
}
void HdCyclesCamera::ApplyCameraSettings(const GfMatrix4d &worldToViewMatrix,
void HdCyclesCamera::ApplyCameraSettings(HdRenderParam *renderParam,
const GfMatrix4d &worldToViewMatrix,
const GfMatrix4d &projectionMatrix,
const std::vector<GfVec4d> &clipPlanes,
Camera *cam)
@ -298,7 +325,7 @@ void HdCyclesCamera::ApplyCameraSettings(const GfMatrix4d &worldToViewMatrix,
GfCamera data;
data.SetFromViewAndProjectionMatrix(worldToViewMatrix, projectionMatrix);
ApplyCameraSettings(data, CameraUtilFit, cam);
ApplyCameraSettings(renderParam, data, CameraUtilFit, cam);
#else
TF_CODING_ERROR("Not implemented");
#endif

View File

@ -17,12 +17,14 @@ class HdCyclesCamera final : public PXR_NS::HdCamera {
HdCyclesCamera(const PXR_NS::SdfPath &sprimId);
~HdCyclesCamera() override;
void ApplyCameraSettings(CCL_NS::Camera *targetCamera) const;
void ApplyCameraSettings(PXR_NS::HdRenderParam *renderParam, CCL_NS::Camera *targetCamera) const;
static void ApplyCameraSettings(const PXR_NS::GfCamera &cameraData,
static void ApplyCameraSettings(PXR_NS::HdRenderParam *renderParam,
const PXR_NS::GfCamera &cameraData,
PXR_NS::CameraUtilConformWindowPolicy windowPolicy,
CCL_NS::Camera *targetCamera);
static void ApplyCameraSettings(const PXR_NS::GfMatrix4d &worldToViewMatrix,
static void ApplyCameraSettings(PXR_NS::HdRenderParam *renderParam,
const PXR_NS::GfMatrix4d &worldToViewMatrix,
const PXR_NS::GfMatrix4d &projectionMatrix,
const std::vector<PXR_NS::GfVec4d> &clipPlanes,
CCL_NS::Camera *targetCamera);

View File

@ -153,7 +153,11 @@ void HdCyclesGeometry<Base, CyclesBase>::Sync(HdSceneDelegate *sceneDelegate,
// Update transforms of all instances
for (size_t i = 0; i < transforms.size(); ++i) {
const Transform tfm = convert_transform(_geomTransform * transforms[i]);
const float metersPerUnit =
static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
const Transform tfm = transform_scale(make_float3(metersPerUnit)) *
convert_transform(_geomTransform * transforms[i]);
_instances[i]->set_tfm(tfm);
}
}

View File

@ -54,11 +54,16 @@ void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate,
const SdfPath &id = GetId();
if (*dirtyBits & DirtyBits::DirtyTransform) {
const float metersPerUnit =
static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
const Transform tfm = transform_scale(make_float3(metersPerUnit)) *
#if PXR_VERSION >= 2011
const Transform tfm = convert_transform(sceneDelegate->GetTransform(id));
convert_transform(sceneDelegate->GetTransform(id));
#else
const Transform tfm = convert_transform(
sceneDelegate->GetLightParamValue(id, HdTokens->transform).Get<GfMatrix4d>());
convert_transform(
sceneDelegate->GetLightParamValue(id, HdTokens->transform)
.Get<GfMatrix4d>());
#endif
_light->set_tfm(tfm);

View File

@ -33,11 +33,12 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens,
);
TF_DEFINE_PRIVATE_TOKENS(HdCyclesRenderSettingsTokens,
(stageMetersPerUnit)
((device, "cycles:device"))
((threads, "cycles:threads"))
((time_limit, "cycles:time_limit"))
((timeLimit, "cycles:time_limit"))
((samples, "cycles:samples"))
((sample_offset, "cycles:sample_offset"))
((sampleOffset, "cycles:sample_offset"))
);
// clang-format on
@ -424,7 +425,7 @@ HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() co
descriptors.push_back({
"Time Limit",
HdCyclesRenderSettingsTokens->time_limit,
HdCyclesRenderSettingsTokens->timeLimit,
VtValue(0.0),
});
descriptors.push_back({
@ -434,7 +435,7 @@ HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() co
});
descriptors.push_back({
"Sample Offset",
HdCyclesRenderSettingsTokens->sample_offset,
HdCyclesRenderSettingsTokens->sampleOffset,
VtValue(0),
});
@ -452,7 +453,11 @@ void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS
Scene *const scene = _renderParam->session->scene;
Session *const session = _renderParam->session;
if (key == HdCyclesRenderSettingsTokens->time_limit) {
if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
_renderParam->SetStageMetersPerUnit(
VtValue::Cast<double>(value).GetWithDefault(_renderParam->GetStageMetersPerUnit()));
}
else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
session->set_time_limit(
VtValue::Cast<double>(value).GetWithDefault(session->params.time_limit));
}
@ -462,7 +467,7 @@ void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS
samples = std::min(std::max(1, samples), max_samples);
session->set_samples(samples);
}
else if (key == HdCyclesRenderSettingsTokens->sample_offset) {
else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
session->params.sample_offset = VtValue::Cast<int>(value).GetWithDefault(
session->params.sample_offset);
++_settingsVersion;
@ -484,19 +489,22 @@ VtValue HdCyclesDelegate::GetRenderSetting(const TfToken &key) const
Scene *const scene = _renderParam->session->scene;
Session *const session = _renderParam->session;
if (key == HdCyclesRenderSettingsTokens->device) {
if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
return VtValue(_renderParam->GetStageMetersPerUnit());
}
else if (key == HdCyclesRenderSettingsTokens->device) {
return VtValue(TfToken(Device::string_from_type(session->params.device.type)));
}
else if (key == HdCyclesRenderSettingsTokens->threads) {
return VtValue(session->params.threads);
}
else if (key == HdCyclesRenderSettingsTokens->time_limit) {
else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
return VtValue(session->params.time_limit);
}
else if (key == HdCyclesRenderSettingsTokens->samples) {
return VtValue(session->params.samples);
}
else if (key == HdCyclesRenderSettingsTokens->sample_offset) {
else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
return VtValue(session->params.sample_offset);
}
else {

View File

@ -117,10 +117,11 @@ void HdCyclesRenderPass::_Execute(const HdRenderPassStateSharedPtr &renderPassSt
#endif
if (const auto camera = static_cast<const HdCyclesCamera *>(renderPassState->GetCamera())) {
camera->ApplyCameraSettings(scene->camera);
camera->ApplyCameraSettings(_renderParam, scene->camera);
}
else {
HdCyclesCamera::ApplyCameraSettings(renderPassState->GetWorldToViewMatrix(),
HdCyclesCamera::ApplyCameraSettings(_renderParam,
renderPassState->GetWorldToViewMatrix(),
renderPassState->GetProjectionMatrix(),
renderPassState->GetClipPlanes(),
scene->camera);

View File

@ -29,6 +29,16 @@ class HdCyclesSession final : public PXR_NS::HdRenderParam {
void UpdateScene();
double GetStageMetersPerUnit() const
{
return _stageMetersPerUnit;
}
void SetStageMetersPerUnit(double stageMetersPerUnit)
{
_stageMetersPerUnit = stageMetersPerUnit;
}
PXR_NS::HdRenderPassAovBinding GetDisplayAovBinding() const
{
return _displayAovBinding;
@ -52,6 +62,7 @@ class HdCyclesSession final : public PXR_NS::HdRenderParam {
private:
const bool _ownCyclesSession;
double _stageMetersPerUnit = 0.01;
PXR_NS::HdRenderPassAovBindingVector _aovBindings;
PXR_NS::HdRenderPassAovBinding _displayAovBinding;
};