Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hdEmbree] add light texture support #5

Open
wants to merge 4 commits into
base: pr/hdEmbree-usd-lux-ref-implementation
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pxr/imaging/plugin/hdEmbree/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pxr_plugin(hdEmbree
renderParam.h

PRIVATE_CLASSES
debugCodes
implicitSurfaceSceneIndexPlugin

RESOURCE_FILES
Expand Down
20 changes: 20 additions & 0 deletions pxr/imaging/plugin/hdEmbree/debugCodes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Copyright 2024 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
#include "pxr/pxr.h"
#include "pxr/imaging/plugin/hdEmbree/debugCodes.h"

#include "pxr/base/tf/debug.h"
#include "pxr/base/tf/registryManager.h"

PXR_NAMESPACE_OPEN_SCOPE

TF_REGISTRY_FUNCTION(TfDebug)
{
TF_DEBUG_ENVIRONMENT_SYMBOL(HDEMBREE_LIGHT_CREATE, "Creation of HdEmbree lights");
}

PXR_NAMESPACE_CLOSE_SCOPE
21 changes: 21 additions & 0 deletions pxr/imaging/plugin/hdEmbree/debugCodes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Copyright 2024 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
#ifndef PXR_IMAGING_PLUGIN_HD_EMBREE_DEBUG_CODES_H
#define PXR_IMAGING_PLUGIN_HD_EMBREE_DEBUG_CODES_H

#include "pxr/pxr.h"
#include "pxr/base/tf/debug.h"

PXR_NAMESPACE_OPEN_SCOPE

TF_DEBUG_CODES(
HDEMBREE_LIGHT_CREATE
);

PXR_NAMESPACE_CLOSE_SCOPE

#endif // PXR_IMAGING_PLUGIN_HD_EMBREE_DEBUG_CODES_H
60 changes: 60 additions & 0 deletions pxr/imaging/plugin/hdEmbree/light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,61 @@
#include <sstream>
#include <vector>

namespace {

PXR_NAMESPACE_USING_DIRECTIVE

HdEmbree_LightTexture
_LoadLightTexture(std::string const& path)
{
if (path.empty()) {
return HdEmbree_LightTexture();
}

HioImageSharedPtr img = HioImage::OpenForReading(path);
if (!img) {
return HdEmbree_LightTexture();
}

int width = img->GetWidth();
int height = img->GetHeight();

std::vector<GfVec3f> pixels(width * height * 3.0f);

HioImage::StorageSpec storage;
storage.width = width;
storage.height = height;
storage.depth = 1;
storage.format = HioFormatFloat32Vec3;
storage.data = &pixels.front();

if (img->Read(storage)) {
return {std::move(pixels), width, height};
}
TF_WARN("Could not read image %s", path.c_str());
return { std::vector<GfVec3f>(), 0, 0 };
}


void
_SyncLightTexture(const SdfPath& id, HdEmbree_LightData& light, HdSceneDelegate *sceneDelegate)
{
std::string path;
if (VtValue textureValue = sceneDelegate->GetLightParamValue(
id, HdLightTokens->textureFile);
textureValue.IsHolding<SdfAssetPath>()) {
SdfAssetPath texturePath =
textureValue.UncheckedGet<SdfAssetPath>();
path = texturePath.GetResolvedPath();
if (path.empty()) {
path = texturePath.GetAssetPath();
}
}
light.texture = _LoadLightTexture(path);
}


} // anonymous namespace
PXR_NAMESPACE_OPEN_SCOPE

HdEmbree_Light::HdEmbree_Light(SdfPath const& id, TfToken const& lightType)
Expand All @@ -29,6 +84,8 @@ HdEmbree_Light::HdEmbree_Light(SdfPath const& id, TfToken const& lightType)
return;
}

TF_DEBUG(HDEMBREE_LIGHT_CREATE).Msg("Creating light %s: %s\n", id.GetText(), lightType.GetText());

// Set the variant to the right type - Sync will fill rest of data
if (lightType == HdSprimTypeTokens->cylinderLight) {
_lightData.lightVariant = HdEmbree_Cylinder();
Expand Down Expand Up @@ -73,6 +130,8 @@ HdEmbree_Light::Sync(HdSceneDelegate *sceneDelegate,
// Store luminance parameters
_lightData.intensity = sceneDelegate->GetLightParamValue(
id, HdLightTokens->intensity).GetWithDefault(1.0f);
_lightData.diffuse = sceneDelegate->GetLightParamValue(
id, HdLightTokens->diffuse).GetWithDefault(1.0f);
_lightData.exposure = sceneDelegate->GetLightParamValue(
id, HdLightTokens->exposure).GetWithDefault(0.0f);
_lightData.color = sceneDelegate->GetLightParamValue(
Expand Down Expand Up @@ -112,6 +171,7 @@ HdEmbree_Light::Sync(HdSceneDelegate *sceneDelegate,
sceneDelegate->GetLightParamValue(id, HdLightTokens->height)
.Get<float>(),
};
_SyncLightTexture(id, _lightData, sceneDelegate);
} else if constexpr (std::is_same_v<T, HdEmbree_Sphere>) {
typedLight = HdEmbree_Sphere{
sceneDelegate->GetLightParamValue(id, HdLightTokens->radius)
Expand Down
9 changes: 9 additions & 0 deletions pxr/imaging/plugin/hdEmbree/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ using HdEmbree_LightVariant = std::variant<
HdEmbree_Rect,
HdEmbree_Sphere>;

struct HdEmbree_LightTexture
{
std::vector<GfVec3f> pixels;
int width = 0;
int height = 0;
};

struct HdEmbree_Shaping
{
GfVec3f focusTint;
Expand All @@ -67,7 +74,9 @@ struct HdEmbree_LightData
GfMatrix3f normalXformLightToWorld;
GfMatrix4f xformWorldToLight;
GfVec3f color;
HdEmbree_LightTexture texture;
float intensity = 1.0f;
float diffuse = 1.0f;
float exposure = 0.0f;
float colorTemperature = 6500.0f;
bool enableColorTemperature = false;
Expand Down
5 changes: 5 additions & 0 deletions pxr/imaging/plugin/hdEmbree/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ class HdEmbreeMesh final : public HdMesh {
/// embree state.
virtual void Finalize(HdRenderParam *renderParam) override;

bool EmbreeMeshIsDoubleSided() const
{
return _doubleSided;
}

protected:
// Initialize the given representation of this Rprim.
// This is called prior to syncing the prim, the first time the repr
Expand Down
40 changes: 38 additions & 2 deletions pxr/imaging/plugin/hdEmbree/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,19 @@ struct _LightSample {
float invPdfW;
};

GfVec3f
_SampleLightTexture(HdEmbree_LightTexture const& texture, float s, float t)
{
if (texture.pixels.empty()) {
return GfVec3f(0.0f);
}

int x = float(texture.width) * s;
int y = float(texture.height) * t;

return texture.pixels.at(y*texture.width + x);
}

_ShapeSample
_SampleRect(GfMatrix4f const& xf, GfMatrix3f const& normalXform, float width,
float height, float u1, float u2)
Expand Down Expand Up @@ -364,7 +377,9 @@ _SampleCylinder(GfMatrix4f const& xf, GfMatrix3f const& normalXform,
GfVec3f
_EvalLightBasic(HdEmbree_LightData const& light)
{
GfVec3f Le = light.color * light.intensity * powf(2.0f, light.exposure);
// Our current material model is always 100% diffuse, so diffuse parameter
// is a stright multiplier
GfVec3f Le = light.color * light.intensity * light.diffuse * powf(2.0f, light.exposure);
if (light.enableColorTemperature) {
Le = GfCompMult(Le,
_BlackbodyTemperatureAsRgb(light.colorTemperature));
Expand Down Expand Up @@ -393,6 +408,12 @@ _EvalAreaLight(HdEmbree_LightData const& light, _ShapeSample const& ss,
_EvalLightBasic(light)
: GfVec3f(0.0f);

// Multiply by the texture, if there is one
if (!light.texture.pixels.empty()) {
Le = GfCompMult(Le, _SampleLightTexture(light.texture, ss.uv[0],
1.0f - ss.uv[1]));
}

// If normalize is enabled, we need to divide the luminance by the surface
// area of the light, which for an area light is equivalent to multiplying
// by the area pdf, which is itself the reciprocal of the surface area
Expand Down Expand Up @@ -1617,8 +1638,23 @@ HdEmbreeRenderer::_ComputeLighting(
float vis = _Visibility(position, ls.wI, ls.dist * 0.99f);

// Add exitant luminance
float cosOffNormal = GfDot(ls.wI, normal);
if (cosOffNormal < 0.0f) {
bool doubleSided = false;
HdEmbreeMesh *mesh =
dynamic_cast<HdEmbreeMesh*>(prototypeContext->rprim);
if (mesh) {
doubleSided = mesh->EmbreeMeshIsDoubleSided();
}

if (doubleSided) {
cosOffNormal *= -1.0f;
} else {
cosOffNormal = 0.0f;
}
}
finalColor += ls.Li
* _DotZeroClip(ls.wI, normal)
* cosOffNormal
* brdf
* vis
* ls.invPdfW;
Expand Down