mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 04:48:09 +02:00
Reimplement lighting model
This commit is contained in:
parent
19e318c3f0
commit
399861087d
5 changed files with 60 additions and 26 deletions
|
@ -15,22 +15,26 @@ using namespace model;
|
||||||
Light::Light() :
|
Light::Light() :
|
||||||
_flags(0),
|
_flags(0),
|
||||||
_schemaBuffer(),
|
_schemaBuffer(),
|
||||||
_transform() {
|
_transform(),
|
||||||
|
_maximumRadius(1.0f) {
|
||||||
// only if created from nothing shall we create the Buffer to store the properties
|
// only if created from nothing shall we create the Buffer to store the properties
|
||||||
Schema schema;
|
Schema schema;
|
||||||
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
||||||
|
updateLightRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
Light::Light(const Light& light) :
|
Light::Light(const Light& light) :
|
||||||
_flags(light._flags),
|
_flags(light._flags),
|
||||||
_schemaBuffer(light._schemaBuffer),
|
_schemaBuffer(light._schemaBuffer),
|
||||||
_transform(light._transform) {
|
_transform(light._transform),
|
||||||
|
_maximumRadius(1.0f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Light& Light::operator= (const Light& light) {
|
Light& Light::operator= (const Light& light) {
|
||||||
_flags = (light._flags);
|
_flags = (light._flags);
|
||||||
_schemaBuffer = (light._schemaBuffer);
|
_schemaBuffer = (light._schemaBuffer);
|
||||||
_transform = (light._transform);
|
_transform = (light._transform);
|
||||||
|
_maximumRadius = (light._maximumRadius);
|
||||||
|
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
|
@ -70,21 +74,35 @@ void Light::setAmbientIntensity(float intensity) {
|
||||||
editSchema()._ambientIntensity = intensity;
|
editSchema()._ambientIntensity = intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Light::setSurfaceRadius(float radius) {
|
||||||
|
if (radius <= 0.0f) {
|
||||||
|
radius = 0.1f;
|
||||||
|
}
|
||||||
|
editSchema()._attenuation.x = radius;
|
||||||
|
updateLightRadius();
|
||||||
|
}
|
||||||
void Light::setMaximumRadius(float radius) {
|
void Light::setMaximumRadius(float radius) {
|
||||||
if (radius <= 0.f) {
|
if (radius <= 0.f) {
|
||||||
radius = 1.0f;
|
radius = 1.0f;
|
||||||
}
|
}
|
||||||
editSchema()._attenuation.w = radius;
|
editSchema()._attenuation.y = radius;
|
||||||
updateLightRadius();
|
updateLightRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Light::updateLightRadius() {
|
void Light::updateLightRadius() {
|
||||||
const float CUTOFF_INTENSITY_RATIO = 0.05f;
|
|
||||||
float intensity = getIntensity() * std::max(std::max(getColor().x, getColor().y), getColor().z);
|
float intensity = getIntensity() * std::max(std::max(getColor().x, getColor().y), getColor().z);
|
||||||
float denom = sqrtf(intensity / CUTOFF_INTENSITY_RATIO) - 1.0f;
|
float maximumDistance = getMaximumRadius() - getSurfaceRadius();
|
||||||
float surfaceRadius = getMaximumRadius() / std::max(denom, 1.0f);
|
|
||||||
|
|
||||||
editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CUTOFF_INTENSITY_RATIO, getMaximumRadius());
|
float denom = maximumDistance / getSurfaceRadius() + 1;
|
||||||
|
|
||||||
|
// The cutoff intensity biases the light towards the source.
|
||||||
|
// If the source is small and the intensity high, many points may not be shaded.
|
||||||
|
// If the intensity is >=1.0, the lighting attenuation equation gets borked (see Light.slh).
|
||||||
|
// To maintain sanity, we cap it well before then.
|
||||||
|
const float MAX_CUTOFF_INTENSITY = 0.01f; // intensity = maximumRadius = 1.0f, surfaceRadius = 0.1f
|
||||||
|
float cutoffIntensity = std::min(intensity / (denom * denom), MAX_CUTOFF_INTENSITY);
|
||||||
|
|
||||||
|
editSchema()._attenuation.z = cutoffIntensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
|
@ -74,8 +74,17 @@ public:
|
||||||
|
|
||||||
bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); }
|
bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); }
|
||||||
|
|
||||||
|
// Surface Radius is the physical radius of the light sphere through wich the light energy shines
|
||||||
|
// It's expressed in meters and should be small for realistic lights since its in theory about the
|
||||||
|
// size of a light bulb filament (~1cm = 0.01m)
|
||||||
|
void setSurfaceRadius(float radius);
|
||||||
|
float getSurfaceRadius() const { return getSchema()._attenuation.x; }
|
||||||
|
|
||||||
|
// Maximum radius defines the maximum distance of reach of our light model
|
||||||
|
// This is where our radial attenuation will reach 0 (even though in theory it should be infinity)
|
||||||
|
// If MaximumRadius < SurfaceRadius then the radial attenuation is constant at 100% Intensity
|
||||||
void setMaximumRadius(float radius);
|
void setMaximumRadius(float radius);
|
||||||
float getMaximumRadius() const { return getSchema()._attenuation.w; }
|
float getMaximumRadius() const { return getSchema()._attenuation.y; }
|
||||||
|
|
||||||
// Spot properties
|
// Spot properties
|
||||||
bool isSpot() const { return getType() == SPOT; }
|
bool isSpot() const { return getType() == SPOT; }
|
||||||
|
@ -107,7 +116,7 @@ public:
|
||||||
float _ambientIntensity{0.0f};
|
float _ambientIntensity{0.0f};
|
||||||
Color _color{1.0f};
|
Color _color{1.0f};
|
||||||
float _intensity{1.0f};
|
float _intensity{1.0f};
|
||||||
Vec4 _attenuation{1.0f};
|
Vec4 _attenuation{0.1f, 1.0f, 0.0f, 0.0f};
|
||||||
Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f};
|
Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
Vec4 _shadow{0.0f};
|
Vec4 _shadow{0.0f};
|
||||||
|
|
||||||
|
@ -122,6 +131,7 @@ protected:
|
||||||
UniformBufferView _schemaBuffer;
|
UniformBufferView _schemaBuffer;
|
||||||
Transform _transform;
|
Transform _transform;
|
||||||
gpu::SphericalHarmonics _ambientSphere;
|
gpu::SphericalHarmonics _ambientSphere;
|
||||||
|
float _maximumRadius;
|
||||||
|
|
||||||
const Schema& getSchema() const { return _schemaBuffer.get<Schema>(); }
|
const Schema& getSchema() const { return _schemaBuffer.get<Schema>(); }
|
||||||
Schema& editSchema() { return _schemaBuffer.edit<Schema>(); }
|
Schema& editSchema() { return _schemaBuffer.edit<Schema>(); }
|
||||||
|
|
|
@ -29,15 +29,7 @@ vec3 getLightColor(Light l) { return l._color.rgb; }
|
||||||
float getLightIntensity(Light l) { return l._color.w; }
|
float getLightIntensity(Light l) { return l._color.w; }
|
||||||
float getLightAmbientIntensity(Light l) { return l._direction.w; }
|
float getLightAmbientIntensity(Light l) { return l._direction.w; }
|
||||||
|
|
||||||
float evalLightAttenuation(Light l, float r) {
|
float getLightSpotAngleCos(Light l) {
|
||||||
float d = max(r - l._attenuation.x, 0.0);
|
|
||||||
float denom = d * l._attenuation.y + 1.0;
|
|
||||||
float attenuation = 1.0 / (denom * denom);
|
|
||||||
return max((attenuation - l._attenuation.z)/(1.0 - l._attenuation.z), 0.0);
|
|
||||||
// return clamp(1.0/(l._attenuation.x + l._attenuation.y * r + l._attenuation.z * r * r), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getLightSpotAngleCos(Light l) {
|
|
||||||
return l._spot.x;
|
return l._spot.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,15 +41,19 @@ float evalLightSpotAttenuation(Light l, float cosA) {
|
||||||
return pow(cosA, l._spot.w);
|
return pow(cosA, l._spot.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getLightSquareRadius(Light l) {
|
|
||||||
return l._attenuation.w * l._attenuation.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getLightRadius(Light l) {
|
float getLightRadius(Light l) {
|
||||||
return l._attenuation.w;
|
return l._attenuation.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getLightAttenuationCutoff(Light l) {
|
float getLightSquareRadius(Light l) {
|
||||||
|
return getLightRadius(l) * getLightRadius(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getLightCutoffRadius(Light l) {
|
||||||
|
return l._attenuation.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getLightCutoffIntensity(Light l) {
|
||||||
return l._attenuation.z;
|
return l._attenuation.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +61,16 @@ float getLightShowContour(Light l) {
|
||||||
return l._control.w;
|
return l._control.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float evalLightAttenuation(Light l, float r) {
|
||||||
|
float radius = getLightRadius(l);
|
||||||
|
float cutoff = getLightCutoffIntensity(l);
|
||||||
|
float d = max(r - radius, 0.0);
|
||||||
|
float denom = d/radius + 1.0;
|
||||||
|
float attenuation = min(1.0, 1.0 / (denom * denom));
|
||||||
|
// Scale attenuation using cutoff from maximum radius
|
||||||
|
return max(0, (attenuation - cutoff) / (1 - cutoff));
|
||||||
|
}
|
||||||
|
|
||||||
<@if GPU_FEATURE_PROFILE == GPU_CORE @>
|
<@if GPU_FEATURE_PROFILE == GPU_CORE @>
|
||||||
uniform lightBuffer {
|
uniform lightBuffer {
|
||||||
Light light;
|
Light light;
|
||||||
|
|
|
@ -48,7 +48,7 @@ void main(void) {
|
||||||
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
|
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
|
||||||
|
|
||||||
// Kill if too far from the light center
|
// Kill if too far from the light center
|
||||||
if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) {
|
if (dot(fragLightVec, fragLightVec) > getLightCutoffRadius(light)) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ void main(void) {
|
||||||
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
|
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
|
||||||
|
|
||||||
// Kill if too far from the light center
|
// Kill if too far from the light center
|
||||||
if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) {
|
if (dot(fragLightVec, fragLightVec) > getLightCutoffRadius(light)) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue