1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// Copyright 2009 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "SpotLight.h"
#include "math/sampling.h"
#ifndef OSPRAY_TARGET_SYCL
#include "lights/SpotLight_ispc.h"
#else
namespace ispc {
void SpotLight_Transform(const void *self, const void *xfm, void *dyn);
void *SpotLight_sample_addr();
void *SpotLight_sample_instanced_addr();
void *SpotLight_eval_addr();
void *SpotLight_eval_instanced_addr();
} // namespace ispc
#endif
// ispc shared
#include "SpotLightShared.h"
#include "common/InstanceShared.h"
namespace ospray {
ispc::Light *SpotLight::createSh(uint32_t, const ispc::Instance *instance) const
{
ispc::SpotLight *sh =
StructSharedCreate<ispc::SpotLight>(getISPCDevice().getDRTDevice());
#ifndef OSPRAY_TARGET_SYCL
sh->super.sample =
reinterpret_cast<ispc::Light_SampleFunc>(ispc::SpotLight_sample_addr());
sh->super.eval =
reinterpret_cast<ispc::Light_EvalFunc>(ispc::SpotLight_eval_addr());
#endif
sh->super.isVisible = visible;
sh->super.instance = instance;
sh->pre.position = position;
sh->pre.direction = normalize(direction);
intensityDistribution.setSh(sh->intensityDistribution);
// Enable dynamic runtime instancing or apply static transformation
if (instance) {
sh->pre.c0 = intensityDistribution.c0;
if (instance->motionBlur) {
#ifndef OSPRAY_TARGET_SYCL
sh->super.sample = reinterpret_cast<ispc::Light_SampleFunc>(
ispc::SpotLight_sample_instanced_addr());
sh->super.eval = reinterpret_cast<ispc::Light_EvalFunc>(
ispc::SpotLight_eval_instanced_addr());
#endif
} else
ispc::SpotLight_Transform(&sh->pre, instance->xfm, &sh->pre);
} else {
sh->pre.c90 = normalize(cross(intensityDistribution.c0, sh->pre.direction));
sh->pre.c0 = cross(sh->pre.direction, sh->pre.c90);
}
sh->radiance = radiance;
sh->intensity = radIntensity;
sh->cosAngleMax = cosAngleMax;
sh->cosAngleScale = cosAngleScale;
sh->radius = radius;
sh->innerRadius = innerRadius;
sh->areaPdf = uniformSampleRingPDF(radius, innerRadius);
return &sh->super;
}
std::string SpotLight::toString() const
{
return "ospray::SpotLight";
}
void SpotLight::commit()
{
Light::commit();
position = getParam<vec3f>("position", vec3f(0.f));
direction = getParam<vec3f>("direction", vec3f(0.f, 0.f, 1.f));
float openingAngle = getParam<float>("openingAngle", 180.f);
float penumbraAngle = getParam<float>("penumbraAngle", 5.f);
radius = max(0.0f, getParam<float>("radius", 0.f));
innerRadius =
clamp(getParam<float>("innerRadius", 0.f), 0.0f, 0.999f * radius);
// per default perpendicular to direction
intensityDistribution.c0 = std::abs(direction.x) < std::abs(direction.y)
? vec3f(0.0f, direction.z, direction.y)
: vec3f(direction.z, 0.0f, direction.x);
intensityDistribution.readParams(*this);
// check ranges and pre-compute parameters
openingAngle = clamp(openingAngle, 0.f, 360.f);
penumbraAngle = clamp(penumbraAngle, 0.f, 0.5f * openingAngle);
cosAngleMax = std::cos(deg2rad(0.5f * openingAngle));
const float cosAngleMin =
std::cos(deg2rad(0.5f * openingAngle - penumbraAngle));
cosAngleScale = 1.0f / (cosAngleMin - cosAngleMax);
queryIntensityQuantityType(intensityDistribution
? OSP_INTENSITY_QUANTITY_SCALE
: OSP_INTENSITY_QUANTITY_INTENSITY);
processIntensityQuantityType(openingAngle);
}
void SpotLight::processIntensityQuantityType(const float openingAngle)
{
radIntensity = 0.0f;
radiance = 0.0f;
const float halfOpeningAngleRad = M_PI * (openingAngle * 0.5f) / 180.0f;
const float cosHalfOpeningAngle = cos(halfOpeningAngleRad);
const auto sqr = [](const float f) { return f * f; };
const float ringDiskArea = M_PI * (sqr(radius) - sqr(innerRadius));
const float sphericalCapCosInt = M_PI * (1.0f - sqr(cosHalfOpeningAngle));
// converting from the chosen intensity quantity type to radiance
if (intensityDistribution
? intensityQuantity == OSP_INTENSITY_QUANTITY_SCALE
: intensityQuantity == OSP_INTENSITY_QUANTITY_INTENSITY) {
radIntensity = coloredIntensity;
if (radius > 0.0f)
radiance = radIntensity / ringDiskArea;
return;
}
if (!intensityDistribution) {
if (intensityQuantity == OSP_INTENSITY_QUANTITY_POWER) {
// since our spot light implementation includes the cosine term we need
// to consider the integrated cosine cap instead of the usually used
// integrated cap
radIntensity = coloredIntensity / sphericalCapCosInt;
if (radius > 0.0f)
radiance = coloredIntensity / (sphericalCapCosInt * ringDiskArea);
return;
}
if (intensityQuantity == OSP_INTENSITY_QUANTITY_RADIANCE) {
// a virtual spot light has no surface area therefore radIntensity stays 0
if (radius > 0.0f)
radiance = coloredIntensity;
return;
}
}
postStatusMsg(OSP_LOG_WARNING)
<< toString() << " unsupported 'intensityQuantity' value";
}
} // namespace ospray
|