improving on the poin light attenuatiion formula

This commit is contained in:
Sam Gateau 2015-01-28 00:09:15 -08:00
parent b9bbd7745f
commit b6836af071
6 changed files with 64 additions and 44 deletions

View file

@ -40,25 +40,19 @@ Light::~Light() {
void Light::setPosition(const Vec3& position) {
_transform.setTranslation(position);
_transform.getMatrix(editSchema()._transform);
editSchema()._position = Vec4(position, 1.f);
}
void Light::setOrientation(const glm::quat& orientation) {
_transform.setRotation(orientation);
_transform.getMatrix(editSchema()._transform);
}
void Light::setDirection(const Vec3& direction) {
glm::mat3 rotation(
Vec3(1.0f, 0.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0f),
-direction);
setOrientation(glm::quat(rotation));
editSchema()._direction = Vec4(direction, 0.f);
}
const Vec3& Light::getDirection() const {
return Vec3(_transform.transform(Vec4(0.0f, 0.0f, 1.0f, 0.0f)));
return Vec3(getSchema()._direction);
}
void Light::setColor(const Color& color) {
@ -69,11 +63,13 @@ void Light::setIntensity(float intensity) {
editSchema()._intensity = intensity;
}
void Light::setAttenuationRadius(float radius) {
void Light::setMaximumRadius(float radius) {
if (radius <= 0.f) {
radius = 1.0f;
}
editSchema()._attenuation = Vec4(1.0f, 2.0f/radius, 1.0f/(radius*radius), radius);
float CutOffIntensityRatio = 0.01f;
float surfaceRadius = radius / (sqrt(1.0f / CutOffIntensityRatio) - 1.f);
editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius);
}
void Light::setSpotCone(float angle) {

View file

@ -74,8 +74,8 @@ public:
bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); }
void setAttenuationRadius(float radius);
float getAttenuationRadius() const { return getSchema()._attenuation.w; }
void setMaximumRadius(float radius);
float getMaximumRadius() const { return getSchema()._attenuation.w; }
// Spot properties
bool isSpot() const { return getType() == SPOT; }
@ -87,7 +87,8 @@ public:
// Schema to access the attribute values of the light
class Schema {
public:
glm::mat4 _transform;
Vec4 _position;
Vec4 _direction;
Color _color;
float _intensity;
Vec4 _attenuation;
@ -97,10 +98,11 @@ public:
Vec4 _control;
Schema() :
_transform(),
_position(0.0f, 0.0f, 0.0f, 1.0f),
_direction(0.0f, 0.0f, -1.0f, 0.f),
_color(1.0f),
_intensity(1.0f),
_attenuation(1.0f, 2.0f, 1.0f, 1.0f),
_attenuation(1.0f, 1.0f, 1.0f, 1.0f),
_spot(0.0f, 0.0f, 0.0f, 0.0f),
_control(0.0f)
{}

View file

@ -275,7 +275,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
model::LightPointer lp = model::LightPointer(new model::Light());
lp->setPosition(position);
lp->setAttenuationRadius(radius);
lp->setMaximumRadius(radius);
lp->setColor(diffuse);
lp->setIntensity(1.0f);
lp->setType(model::Light::POINT);
@ -297,7 +297,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
model::LightPointer ls = model::LightPointer(new model::Light());
ls->setPosition(position);
ls->setDirection(direction);
ls->setAttenuationRadius(radius);
ls->setMaximumRadius(radius);
ls->setSpotCone(cutoff);
ls->setColor(diffuse);
ls->setIntensity(1.0f);
@ -453,6 +453,8 @@ void DeferredLightingEffect::render() {
const glm::vec3& eyePoint = _viewState->getCurrentViewFrustum()->getPosition();
float nearRadius = glm::distance(eyePoint, _viewState->getCurrentViewFrustum()->getNearTopLeft());
glm::mat4 invViewMat;
_viewState->getViewTransform().getMatrix(invViewMat);
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -470,7 +472,9 @@ void DeferredLightingEffect::render() {
batch.setUniformBuffer(_pointLightLocations.lightBufferUnit, light->getSchemaBuffer());
gpu::GLBackend::renderBatch(batch);
}
_spotLight.setUniformValue(_pointLightLocations.radius, light->getAttenuationRadius());
glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat));
// _pointLight.setUniformValue(_pointLightLocations.viewMat, reinterpret_cast< const GLfloat* >(&viewMat));
// _spotLight.setUniformValue(_pointLightLocations.radius, light->getAttenuationRadius());
/*
@ -485,7 +489,7 @@ void DeferredLightingEffect::render() {
*/
glPushMatrix();
float expandedRadius = light->getAttenuationRadius() * (1.0f + SCALE_EXPANSION);
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) {
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -1.0f);
@ -525,7 +529,7 @@ void DeferredLightingEffect::render() {
batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer());
gpu::GLBackend::renderBatch(batch);
}
_spotLight.setUniformValue(_spotLightLocations.radius, light->getAttenuationRadius());
// _spotLight.setUniformValue(_spotLightLocations.radius, light->getAttenuationRadius());
/*
_spotLight.setUniformValue(_spotLightLocations.radius, light.radius);
@ -543,7 +547,7 @@ void DeferredLightingEffect::render() {
glPushMatrix();
float expandedRadius = light->getAttenuationRadius() * (1.0f + SCALE_EXPANSION);
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
float edgeRadius = expandedRadius / glm::cos(light->getSpotConeAngle());
if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < edgeRadius + nearRadius) {
glLoadIdentity();
@ -563,7 +567,7 @@ void DeferredLightingEffect::render() {
glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light->getDirection());
glm::vec3 axis = glm::axis(spotRotation);
glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z);
glTranslatef(0.0f, 0.0f, -light->getAttenuationRadius() * (1.0f + SCALE_EXPANSION * 0.5f));
glTranslatef(0.0f, 0.0f, -light->getMaximumRadius() * (1.0f + SCALE_EXPANSION * 0.5f));
geometryCache->renderCone(expandedRadius * glm::tan(light->getSpotConeAngle()),
expandedRadius, 32, 1);
}
@ -649,6 +653,7 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit
locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale");
locations.radius = program.uniformLocation("radius");
locations.ambientSphere = program.uniformLocation("ambientSphere.L00");
locations.invViewMat = program.uniformLocation("invViewMat");
GLint loc = -1;
#if defined(Q_OS_MAC)
@ -661,8 +666,8 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit
#elif defined(Q_OS_WIN)
loc = glGetUniformBlockIndex(program.programId(), "lightBuffer");
if (loc >= 0) {
glUniformBlockBinding(program.programId(), loc, 1);
locations.lightBufferUnit = 1;
glUniformBlockBinding(program.programId(), loc, 0);
locations.lightBufferUnit = 0;
} else {
locations.lightBufferUnit = -1;
}

View file

@ -105,6 +105,7 @@ private:
int radius;
int ambientSphere;
int lightBufferUnit;
int invViewMat;
};
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);

View file

@ -12,8 +12,8 @@
<@def LIGHT_SLH@>
struct Light {
mat4 _transform;
vec4 _position;
vec4 _direction;
vec4 _color;
vec4 _attenuation;
vec4 _spot;
@ -23,14 +23,18 @@ struct Light {
vec4 _control;
};
vec3 getLightPosition(Light l) { return l._transform[3].xyz; }
vec3 getLightDirection(Light l) { return -l._transform[2].xyz; } // direction is -Z axis
vec3 getLightPosition(Light l) { return l._position.xyz; }
vec3 getLightDirection(Light l) { return l._direction.xyz; } // direction is -Z axis
vec3 getLightColor(Light l) { return l._color.rgb; }
float getLightIntensity(Light l) { return l._color.w; }
float evalLightAttenuation(Light l, float r) {
return clamp(1.0/(l._attenuation.x + l._attenuation.y * r + l._attenuation.z * r * r), 0.0, 1.0);
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 evalLightSpotAttenuation(Light l, float cosA) {
@ -40,6 +44,9 @@ float evalLightSpotAttenuation(Light l, float cosA) {
return clamp(pow(cosA / l._spot.x, l._spot.w), 0.0, 1.0);
}
float getLightSquareRadius(Light l) {
return l._attenuation.w * l._attenuation.w;
}
<@if GLPROFILE == PC_GL@>

View file

@ -21,6 +21,8 @@
// the radius (hard cutoff) of the light effect
uniform float radius;
uniform mat4 invViewMat;
void main(void) {
// get the depth and exit early if it doesn't pass the test
vec2 texCoord = gl_TexCoord[0].st / gl_TexCoord[0].q;
@ -32,18 +34,25 @@ void main(void) {
discard;
}
// compute the view space position using the depth
float z = near / (depth * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0);
vec4 wPos;
wPos = invViewMat * frag.position;
Light light = getLight();
gl_FragColor = vec4(frag.normal, 0.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, texCoord);
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
vec3 lightVector = getLightPosition(light) - wPos.xyz;
if (dot(lightVector, lightVector) > getLightSquareRadius(light)) {
discard;
}
// compute the base color based on OpenGL lighting model
vec4 lightVector = gl_LightSource[1].position - position;
float lightDistance = length(lightVector);
lightVector = lightVector / lightDistance;
float lightAttenuation = evalLightAttenuation(light, lightDistance);
gl_FragColor.xyz *= lightAttenuation;
/*
float diffuse = dot(frag.normal, lightVector);
float diffuse = dot(normalizedNormal, lightVector);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient +
@ -59,6 +68,6 @@ void main(void) {
normalizedNormal));
vec4 specularColor = texture2D(specularMap, texCoord);
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
gl_FragColor = vec4(frag.normal, 0.0);
*/
// gl_FragColor = vec4(frag.normal, 0.0);
}