Merge pull request #7078 from zzmp/fix/light-intensity

Reimplement light attenuation for spot and point lights
This commit is contained in:
Brad Hefta-Gaub 2016-02-25 16:08:28 -08:00
commit 82cbf19bca
18 changed files with 217 additions and 139 deletions

View file

@ -72,10 +72,13 @@
};
}
function createEmitNumberPropertyUpdateFunction(propertyName) {
function createEmitNumberPropertyUpdateFunction(propertyName, decimals) {
decimals = decimals == undefined ? 4 : decimals;
return function() {
var value = parseFloat(this.value).toFixed(decimals);
EventBridge.emitWebEvent(
'{ "type":"update", "properties":{"' + propertyName + '":' + parseFloat(this.value).toFixed(4) + '}}'
'{ "type":"update", "properties":{"' + propertyName + '":' + value + '}}'
);
};
}
@ -323,6 +326,7 @@
var elLightColorBlue = document.getElementById("property-light-color-blue");
var elLightIntensity = document.getElementById("property-light-intensity");
var elLightFalloffRadius = document.getElementById("property-light-falloff-radius");
var elLightExponent = document.getElementById("property-light-exponent");
var elLightCutoff = document.getElementById("property-light-cutoff");
@ -604,9 +608,10 @@
elLightColorGreen.value = properties.color.green;
elLightColorBlue.value = properties.color.blue;
elLightIntensity.value = properties.intensity;
elLightExponent.value = properties.exponent;
elLightCutoff.value = properties.cutoff;
elLightIntensity.value = properties.intensity.toFixed(1);
elLightFalloffRadius.value = properties.falloffRadius.toFixed(1);
elLightExponent.value = properties.exponent.toFixed(2);
elLightCutoff.value = properties.cutoff.toFixed(2);
} else if (properties.type == "Zone") {
for (var i = 0; i < elZoneSections.length; i++) {
elZoneSections[i].style.display = 'block';
@ -795,9 +800,10 @@
}
})
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity'));
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity', 1));
elLightFalloffRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('falloffRadius', 1));
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent', 2));
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff', 2));
elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl'));
@ -1043,25 +1049,25 @@
<div class="text-section property">
<div class="label">Line Height</div>
<div class="value">
<input class="coord" type='number' id="property-text-line-height" min="0" step="0.005">
<input class="coord" type="number" id="property-text-line-height" min="0" step="0.005">
</div>
</div>
<div class="text-section property">
<div class="label">Text Color</div>
<div class="value">
<div class='color-picker' id="property-text-text-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
<div class="input-area">R <input class="coord" type="number" id="property-text-text-color-red"></div>
<div class="input-area">G <input class="coord" type="number" id="property-text-text-color-green"></div>
<div class="input-area">B <input class="coord" type="number" id="property-text-text-color-blue"></div>
</div>
</div>
<div class="text-section property">
<div class="label">Background Color</div>
<div class="value">
<div class='color-picker' id="property-text-background-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
<div class="input-area">R <input class="coord" type="number" id="property-text-background-color-red"></div>
<div class="input-area">G <input class="coord" type="number" id="property-text-background-color-green"></div>
<div class="input-area">B <input class="coord" type="number" id="property-text-background-color-blue"></div>
</div>
</div>
@ -1085,32 +1091,32 @@
<div class="label">Light Color</div>
<div class="value">
<div class='color-picker' id="property-zone-key-light-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></div>
<div class="input-area">R <input class="coord" type="number" id="property-zone-key-light-color-red" min="0" max="255" step="1"></div>
<div class="input-area">G <input class="coord" type="number" id="property-zone-key-light-color-green" min="0" max="255" step="1"></div>
<div class="input-area">B <input class="coord" type="number" id="property-zone-key-light-color-blue" min="0" max="255" step="1"></div>
</div>
</div>
<div class="zone-section keyLight-section property">
<div class="label">Light Intensity</div>
<div class="value">
<input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1">
<input class="coord" type="number" id="property-zone-key-intensity" min="0" max="10" step="0.1">
</div>
</div>
<div class="zone-section keyLight-section property">
<div class="label">Light Direction</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></div>
<div class="input-area">Pitch <input class="coord" type="number" id="property-zone-key-light-direction-x"></div>
<div class="input-area">Yaw <input class="coord" type="number" id="property-zone-key-light-direction-y"></div>
<div class="input-area">Roll <input class="coord" type="number" id="property-zone-key-light-direction-z"></div>
</div>
</div>
<div class="zone-section keyLight-section property">
<div class="label">Ambient Intensity</div>
<div class="value">
<input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1">
<input class="coord" type="number" id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1">
</div>
</div>
@ -1129,19 +1135,19 @@
<div class="zone-section stage-section property">
<div class="label">Stage Latitude</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1">
<input class="coord" type="number" id="property-zone-stage-latitude" min="-90" max="90" step="1">
</div>
</div>
<div class="zone-section stage-section property">
<div class="label">Stage Longitude</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1">
<input class="coord" type="number" id="property-zone-stage-longitude" min="-180" max="180" step="1">
</div>
</div>
<div class="zone-section stage-section property">
<div class="label">Stage Altitude</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-altitude" step="1">
<input class="coord" type="number" id="property-zone-stage-altitude" step="1">
</div>
</div>
@ -1155,13 +1161,13 @@
<div class="zone-section stage-section property">
<div class="label">Stage Day</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1">
<input class="coord" type="number" id="property-zone-stage-day" min="0" max="365" step="1">
</div>
</div>
<div class="zone-section stage-section property">
<div class="label">Stage Hour</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5">
<input class="coord" type="number" id="property-zone-stage-hour" min="0" max="24" step="0.5">
</div>
</div>
@ -1186,9 +1192,9 @@
<div class="label">Skybox Color</div>
<div class="value">
<div class='color-picker' id="property-zone-skybox-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-zone-skybox-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-skybox-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
<div class="input-area">R <input class="coord" type="number" id="property-zone-skybox-color-red"></div>
<div class="input-area">G <input class="coord" type="number" id="property-zone-skybox-color-green"></div>
<div class="input-area">B <input class="coord" type="number" id="property-zone-skybox-color-blue"></div>
</div>
</div>
@ -1264,23 +1270,23 @@
<div class="property">
<div class="label">Registration</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-reg-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type='number' id="property-reg-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type='number' id="property-reg-z"><div class="prop-z"></div></div>
<div class="input-area">X <input class="coord" type="number" id="property-reg-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type="number" id="property-reg-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type="number" id="property-reg-z"><div class="prop-z"></div></div>
</div>
</div>
<div class="property">
<div class="label">Dimensions</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-dim-x" step="0.1"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type='number' id="property-dim-y" step="0.1"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type='number' id="property-dim-z" step="0.1"><div class="prop-z"></div></div>
<div class="input-area">X <input class="coord" type="number" id="property-dim-x" step="0.1"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type="number" id="property-dim-y" step="0.1"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type="number" id="property-dim-z" step="0.1"><div class="prop-z"></div></div>
<div>
<input type="button" id="reset-to-natural-dimensions" value="Reset to Natural Dimensions">
</div>
<div class="input-area">
<input class="" type='number' id="dimension-rescale-pct" value=100>%
<input class="" type="number" id="dimension-rescale-pct" value=100>%
</div>
<span>
<input type="button" id="dimension-rescale-button" value="Rescale">
@ -1291,9 +1297,9 @@
<div class="poly-vox-section property">
<div class="label">Voxel Volume Size</div>
<div class="value">
<div class="input-area">X <br> <input class="coord" type='number' id="property-voxel-volume-size-x"></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></div>
<div class="input-area">X <br> <input class="coord" type="number" id="property-voxel-volume-size-x"></div>
<div class="input-area">Y <br><input class="coord" type="number" id="property-voxel-volume-size-y"></div>
<div class="input-area">Z <br><input class="coord" type="number" id="property-voxel-volume-size-z"></div>
</div>
<div class="label">Surface Extractor</div>
@ -1325,9 +1331,9 @@
<div class="property">
<div class="label">Rotation</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-rot-x" step="0.1"></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-rot-y" step="0.1"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-rot-z"step="0.1"></div>
<div class="input-area">Pitch <input class="coord" type="number" id="property-rot-x" step="0.1"></div>
<div class="input-area">Yaw <input class="coord" type="number" id="property-rot-y" step="0.1"></div>
<div class="input-area">Roll <input class="coord" type="number" id="property-rot-z"step="0.1"></div>
</div>
</div>
@ -1339,66 +1345,66 @@
<div class="property">
<div class="label">Linear Velocity</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lvel-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lvel-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lvel-z"><div class="prop-z"></div></div>
<div class="input-area">X <input class="coord" type="number" id="property-lvel-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type="number" id="property-lvel-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type="number" id="property-lvel-z"><div class="prop-z"></div></div>
</div>
</div>
<div class="property">
<div class="label">Linear Damping</div>
<div class="value">
<input class="coord" type='number' id="property-ldamping">
<input class="coord" type="number" id="property-ldamping">
</div>
</div>
<div class="property">
<div class="label">Angular Velocity</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-avel-x"></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-avel-y"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-avel-z"></div>
<div class="input-area">Pitch <input class="coord" type="number" id="property-avel-x"></div>
<div class="input-area">Yaw <input class="coord" type="number" id="property-avel-y"></div>
<div class="input-area">Roll <input class="coord" type="number" id="property-avel-z"></div>
</div>
</div>
<div class="property">
<div class="label">Angular Damping</div>
<div class="value">
<input class="coord" type='number' id="property-adamping">
<input class="coord" type="number" id="property-adamping">
</div>
</div>
<div class="property">
<div class="label">Restitution</div>
<div class="value">
<input class="coord" type='number' id="property-restitution">
<input class="coord" type="number" id="property-restitution">
</div>
</div>
<div class="property">
<div class="label">Friction</div>
<div class="value">
<input class="coord" type='number' id="property-friction">
<input class="coord" type="number" id="property-friction">
</div>
</div>
<div class="property">
<div class="label">Gravity</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-grav-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type='number' id="property-grav-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type='number' id="property-grav-z"><div class="prop-z"></div></div>
<div class="input-area">X <input class="coord" type="number" id="property-grav-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type="number" id="property-grav-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type="number" id="property-grav-z"><div class="prop-z"></div></div>
</div>
</div>
<div class="property">
<div class="label">Acceleration</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lacc-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lacc-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lacc-z"><div class="prop-z"></div></div>
<div class="input-area">X <input class="coord" type="number" id="property-lacc-x"><div class="prop-x"></div></div>
<div class="input-area">Y <input class="coord" type="number" id="property-lacc-y"><div class="prop-y"></div></div>
<div class="input-area">Z <input class="coord" type="number" id="property-lacc-z"><div class="prop-z"></div></div>
</div>
</div>
<div class="property">
<div class="label">Density</div>
<div>
<input type='number' id="property-density">
<input type="number" id="property-density">
</div>
</div>
@ -1406,9 +1412,9 @@
<div class="label">Color</div>
<div class="value">
<div id="property-color" class='color-picker'></div>
<div class="input-area">R <input class="coord" type='number' id="property-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></div>
<div class="input-area">R <input class="coord" type="number" id="property-color-red"></div>
<div class="input-area">G <input class="coord" type="number" id="property-color-green"></div>
<div class="input-area">B <input class="coord" type="number" id="property-color-blue"></div>
</div>
</div>
@ -1483,7 +1489,7 @@
<div class="property">
<div class="label">Lifetime</div>
<div class="value">
<input type='number' id="property-lifetime">
<input type="number" id="property-lifetime">
</div>
</div>
@ -1541,25 +1547,25 @@
<div class="model-section property">
<div class="label">Animation FPS</div>
<div class="value">
<input class="coord" type='number' id="property-model-animation-fps">
<input class="coord" type="number" id="property-model-animation-fps">
</div>
</div>
<div class="model-section property">
<div class="label">Animation Frame</div>
<div class="value">
<input class="coord" type='number' id="property-model-animation-frame">
<input class="coord" type="number" id="property-model-animation-frame">
</div>
</div>
<div class="model-section property">
<div class="label">Animation First Frame</div>
<div class="value">
<input class="coord" type='number' id="property-model-animation-first-frame">
<input class="coord" type="number" id="property-model-animation-first-frame">
</div>
</div>
<div class="model-section property">
<div class="label">Animation Last Frame</div>
<div class="value">
<input class="coord" type='number' id="property-model-animation-last-frame">
<input class="coord" type="number" id="property-model-animation-last-frame">
</div>
</div>
<div class="model-section property">
@ -1591,37 +1597,43 @@
<label>Light</label>
</div>
<div class="light-section property">
<div class="label">Color</div>
<div class="value">
<div class='color-picker' id="property-light-color"></div>
<div class="input-area">R <input class="coord" type="number" id="property-light-color-red"></div>
<div class="input-area">G <input class="coord" type="number" id="property-light-color-green"></div>
<div class="input-area">B <input class="coord" type="number" id="property-light-color-blue"></div>
</div>
</div>
<div class="light-section property">
<div class="label">Intensity</div>
<div class="value">
<input class="coord" type="number" id="property-light-intensity" min="0" step="0.1">
</div>
</div>
<div class="light-section property">
<div class="label">Falloff Radius</div>
<div class="value">
<input class="coord" type="number" id="property-light-falloff-radius" min="0" step="0.1">
</div>
</div>
<div class="light-section property">
<span class="label">Spot Light</span>
<span class="value">
<input type='checkbox' id="property-light-spot-light">
</span>
</div>
<div class="light-section property">
<div class="label">Color</div>
<div class="value">
<div class='color-picker' id="property-light-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></div>
</div>
</div>
<div class="light-section property">
<div class="label">Intensity</div>
<div class="value">
<input class="coord" type='number' id="property-light-intensity">
</div>
</div>
<div class="light-section property">
<div class="label">Spot Light Exponent</div>
<div class="value">
<input class="coord" type='number' id="property-light-exponent">
<input class="coord" type="number" id="property-light-exponent" step="0.01">
</div>
</div>
<div class="light-section property">
<div class="label">Spot Light Cutoff (degrees)</div>
<div class="value">
<input class="coord" type='number' id="property-light-cutoff">
<input class="coord" type="number" id="property-light-cutoff" step="0.01">
</div>
</div>
</div>

View file

@ -430,6 +430,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) {
// add local lights
const float BASE_LIGHT_DISTANCE = 2.0f;
const float LIGHT_FALLOFF_RADIUS = 0.01f;
const float LIGHT_EXPONENT = 1.0f;
const float LIGHT_CUTOFF = glm::radians(80.0f);
float distance = BASE_LIGHT_DISTANCE * getUniformScale();
@ -438,7 +439,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
glm::vec3 direction = orientation * light.direction;
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
distance * 2.0f, light.color, 0.5f, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
distance * 2.0f, light.color, 0.5f, LIGHT_FALLOFF_RADIUS, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
}
}

View file

@ -36,15 +36,16 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
glm::vec3 color = toGlm(getXColor());
float intensity = getIntensity();
float falloffRadius = getFalloffRadius();
float exponent = getExponent();
float cutoff = glm::radians(getCutoff());
if (_isSpotlight) {
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position, largestDiameter / 2.0f,
color, intensity, rotation, exponent, cutoff);
color, intensity, falloffRadius, rotation, exponent, cutoff);
} else {
DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f,
color, intensity);
color, intensity, falloffRadius);
}
#ifdef WANT_DEBUG

View file

@ -245,6 +245,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_DYNAMIC, dynamic);
CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight);
CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity);
CHECK_PROPERTY_CHANGE(PROP_FALLOFF_RADIUS, falloffRadius);
CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent);
CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff);
CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked);
@ -445,6 +446,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
if (_type == EntityTypes::Light) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FALLOFF_RADIUS, falloffRadius);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff);
}
@ -597,6 +599,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic);
COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(falloffRadius, float, setFalloffRadius);
COPY_PROPERTY_FROM_QSCRIPTVALUE(exponent, float, setExponent);
COPY_PROPERTY_FROM_QSCRIPTVALUE(cutoff, float, setCutoff);
COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked);
@ -762,6 +765,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, dynamic, unused);
ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool);
ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float);
ADD_PROPERTY_TO_MAP(PROP_FALLOFF_RADIUS, FalloffRadius, falloffRadius, float);
ADD_PROPERTY_TO_MAP(PROP_EXPONENT, Exponent, exponent, float);
ADD_PROPERTY_TO_MAP(PROP_CUTOFF, Cutoff, cutoff, float);
ADD_PROPERTY_TO_MAP(PROP_LOCKED, Locked, locked, bool);
@ -1043,6 +1047,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity());
APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, properties.getFalloffRadius());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff());
}
@ -1332,6 +1337,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INTENSITY, float, setIntensity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FALLOFF_RADIUS, float, setFalloffRadius);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
}
@ -1477,6 +1483,7 @@ void EntityItemProperties::markAllChanged() {
_dynamicChanged = true;
_intensityChanged = true;
_falloffRadiusChanged = true;
_exponentChanged = true;
_cutoffChanged = true;
_lockedChanged = true;
@ -1719,6 +1726,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (intensityChanged()) {
out += "intensity";
}
if (falloffRadiusChanged()) {
out += "falloffRadius";
}
if (exponentChanged()) {
out += "exponent";
}

View file

@ -35,6 +35,7 @@
#include "EntityItemPropertiesMacros.h"
#include "EntityTypes.h"
#include "EntityPropertyFlags.h"
#include "LightEntityItem.h"
#include "LineEntityItem.h"
#include "ParticleEffectEntityItem.h"
#include "PolyVoxEntityItem.h"
@ -129,10 +130,11 @@ public:
DEFINE_PROPERTY(PROP_COLLISIONLESS, Collisionless, collisionless, bool, ENTITY_ITEM_DEFAULT_COLLISIONLESS);
DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t, ENTITY_COLLISION_MASK_DEFAULT);
DEFINE_PROPERTY(PROP_DYNAMIC, Dynamic, dynamic, bool, ENTITY_ITEM_DEFAULT_DYNAMIC);
DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, false);
DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, 1.0f);
DEFINE_PROPERTY(PROP_EXPONENT, Exponent, exponent, float, 0.0f);
DEFINE_PROPERTY(PROP_CUTOFF, Cutoff, cutoff, float, ENTITY_ITEM_DEFAULT_CUTOFF);
DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, LightEntityItem::DEFAULT_IS_SPOTLIGHT);
DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, LightEntityItem::DEFAULT_INTENSITY);
DEFINE_PROPERTY(PROP_FALLOFF_RADIUS, FalloffRadius, falloffRadius, float, LightEntityItem::DEFAULT_FALLOFF_RADIUS);
DEFINE_PROPERTY(PROP_EXPONENT, Exponent, exponent, float, LightEntityItem::DEFAULT_EXPONENT);
DEFINE_PROPERTY(PROP_CUTOFF, Cutoff, cutoff, float, LightEntityItem::DEFAULT_CUTOFF);
DEFINE_PROPERTY(PROP_LOCKED, Locked, locked, bool, ENTITY_ITEM_DEFAULT_LOCKED);
DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString, "");
DEFINE_PROPERTY_REF(PROP_USER_DATA, UserData, userData, QString, ENTITY_ITEM_DEFAULT_USER_DATA);
@ -359,6 +361,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Dynamic, dynamic, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, IsSpotlight, isSpotlight, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Intensity, intensity, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, FalloffRadius, falloffRadius, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Exponent, exponent, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cutoff, cutoff, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, "");

View file

@ -72,8 +72,6 @@ const bool ENTITY_ITEM_DEFAULT_COLLISIONLESS = false;
const bool ENTITY_ITEM_DEFAULT_DYNAMIC = false;
const bool ENTITY_ITEM_DEFAULT_BILLBOARDED = false;
const float ENTITY_ITEM_DEFAULT_CUTOFF = PI / 2;
const QString ENTITY_ITEM_DEFAULT_NAME = QString("");
#endif // hifi_EntityItemPropertiesDefaults_h

View file

@ -167,6 +167,8 @@ enum EntityPropertyList {
PROP_COLLISION_MASK, // one byte of collision group flags
PROP_FALLOFF_RADIUS, // for Light entity
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -21,6 +21,12 @@
#include "EntityTreeElement.h"
#include "LightEntityItem.h"
const bool LightEntityItem::DEFAULT_IS_SPOTLIGHT = false;
const float LightEntityItem::DEFAULT_INTENSITY = 1.0f;
const float LightEntityItem::DEFAULT_FALLOFF_RADIUS = 0.1f;
const float LightEntityItem::DEFAULT_EXPONENT = 0.0f;
const float LightEntityItem::DEFAULT_CUTOFF = PI / 2.0f;
bool LightEntityItem::_lightsArePickable = false;
EntityItemPointer LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -32,12 +38,7 @@ EntityItemPointer LightEntityItem::factory(const EntityItemID& entityID, const E
// our non-pure virtual subclass for now...
LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
_type = EntityTypes::Light;
// default property values
_color[RED_INDEX] = _color[GREEN_INDEX] = _color[BLUE_INDEX] = 0;
_intensity = 1.0f;
_exponent = 0.0f;
_cutoff = PI;
}
void LightEntityItem::setDimensions(const glm::vec3& value) {
@ -62,10 +63,15 @@ EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredP
COPY_ENTITY_PROPERTY_TO_PROPERTIES(intensity, getIntensity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(exponent, getExponent);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(cutoff, getCutoff);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(falloffRadius, getFalloffRadius);
return properties;
}
void LightEntityItem::setFalloffRadius(float value) {
_falloffRadius = glm::max(value, 0.0f);
}
void LightEntityItem::setIsSpotlight(bool value) {
if (value != _isSpotlight) {
_isSpotlight = value;
@ -101,6 +107,7 @@ bool LightEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(intensity, setIntensity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(exponent, setExponent);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(cutoff, setCutoff);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(falloffRadius, setFalloffRadius);
if (somethingChanged) {
bool wantDebug = false;
@ -150,6 +157,7 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity);
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent);
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff);
READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius);
}
return bytesRead;
@ -164,6 +172,7 @@ EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_INTENSITY;
requestedProperties += PROP_EXPONENT;
requestedProperties += PROP_CUTOFF;
requestedProperties += PROP_FALLOFF_RADIUS;
return requestedProperties;
}
@ -181,4 +190,5 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, getIntensity());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, getCutoff());
APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, getFalloffRadius());
}

View file

@ -16,6 +16,12 @@
class LightEntityItem : public EntityItem {
public:
static const bool DEFAULT_IS_SPOTLIGHT;
static const float DEFAULT_INTENSITY;
static const float DEFAULT_FALLOFF_RADIUS;
static const float DEFAULT_EXPONENT;
static const float DEFAULT_CUTOFF;
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
LightEntityItem(const EntityItemID& entityItemID);
@ -65,6 +71,9 @@ public:
float getIntensity() const { return _intensity; }
void setIntensity(float value) { _intensity = value; }
float getFalloffRadius() const { return _falloffRadius; }
void setFalloffRadius(float value);
float getExponent() const { return _exponent; }
void setExponent(float value) { _exponent = value; }
@ -78,10 +87,11 @@ protected:
// properties of a light
rgbColor _color;
bool _isSpotlight;
float _intensity;
float _exponent;
float _cutoff;
bool _isSpotlight { DEFAULT_IS_SPOTLIGHT };
float _intensity { DEFAULT_INTENSITY };
float _falloffRadius { DEFAULT_FALLOFF_RADIUS };
float _exponent { DEFAULT_EXPONENT };
float _cutoff { DEFAULT_CUTOFF };
static bool _lightsArePickable;
};

View file

@ -12,19 +12,18 @@
using namespace model;
Light::Light() :
_flags(0),
_schemaBuffer(),
_transform() {
Light::Light() {
// only if created from nothing shall we create the Buffer to store the properties
Schema schema;
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
updateLightRadius();
}
Light::Light(const Light& light) :
_flags(light._flags),
_schemaBuffer(light._schemaBuffer),
_transform(light._transform) {
_transform(light._transform)
{
}
Light& Light::operator= (const Light& light) {
@ -70,18 +69,36 @@ void Light::setAmbientIntensity(float intensity) {
editSchema()._ambientIntensity = intensity;
}
void Light::setFalloffRadius(float radius) {
if (radius <= 0.0f) {
radius = 0.1f;
}
editSchema()._attenuation.x = radius;
updateLightRadius();
}
void Light::setMaximumRadius(float radius) {
if (radius <= 0.f) {
radius = 1.0f;
}
editSchema()._attenuation.w = radius;
editSchema()._attenuation.y = radius;
updateLightRadius();
}
void Light::updateLightRadius() {
float CutOffIntensityRatio = 0.05f;
float surfaceRadius = getMaximumRadius() / (sqrtf((getIntensity() * std::max(std::max(getColor().x, getColor().y), getColor().z)) / CutOffIntensityRatio) - 1.0f);
editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, getMaximumRadius());
// This function relies on the attenuation equation:
// I = Li / (1 + (d + Lr)/Lr)^2
// where I = calculated intensity, Li = light intensity, Lr = light falloff radius, d = distance from surface
// see: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
// note that falloff radius replaces surface radius in linked example
// This equation is biased back by Lr so that all lights act as true points, regardless of surface radii
const float MIN_CUTOFF_INTENSITY = 0.001f;
// Get cutoff radius at minimum intensity
float intensity = getIntensity() * std::max(std::max(getColor().x, getColor().y), getColor().z);
float cutoffRadius = getFalloffRadius() * ((glm::sqrt(intensity / MIN_CUTOFF_INTENSITY) - 1) - 1);
// If it is less than max radius, store it to buffer to avoid extra shading
editSchema()._attenuation.z = std::min(getMaximumRadius(), cutoffRadius);
}
#include <math.h>

View file

@ -74,8 +74,17 @@ public:
bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); }
// FalloffRradius is the physical radius of the light sphere through which energy shines,
// expressed in meters. It is used only to calculate the falloff curve of the light.
// Actual rendered lights will all have surface radii approaching 0.
void setFalloffRadius(float radius);
float getFalloffRadius() const { return getSchema()._attenuation.x; }
// Maximum radius is the cutoff radius of the light energy, expressed in meters.
// It is used to bound light entities, and *will not* affect the falloff curve of the light.
// Setting it low will result in a noticeable cutoff.
void setMaximumRadius(float radius);
float getMaximumRadius() const { return getSchema()._attenuation.w; }
float getMaximumRadius() const { return getSchema()._attenuation.y; }
// Spot properties
bool isSpot() const { return getType() == SPOT; }
@ -107,7 +116,7 @@ public:
float _ambientIntensity{0.0f};
Color _color{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 _shadow{0.0f};
@ -120,7 +129,7 @@ public:
protected:
Flags _flags;
Flags _flags{ 0 };
UniformBufferView _schemaBuffer;
Transform _transform;

View file

@ -66,14 +66,6 @@ vec3 getLightColor(Light l) { return l._color.rgb; }
float getLightIntensity(Light l) { return l._color.w; }
float getLightAmbientIntensity(Light l) { return l._direction.w; }
float evalLightAttenuation(Light l, float r) {
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;
}
@ -86,22 +78,33 @@ float evalLightSpotAttenuation(Light l, float cosA) {
return pow(cosA, l._spot.w);
}
float getLightSquareRadius(Light l) {
return l._attenuation.w * l._attenuation.w;
}
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.z;
}
float getLightCutoffSquareRadius(Light l) {
return getLightCutoffRadius(l) * getLightCutoffRadius(l);
}
float getLightShowContour(Light l) {
return l._control.w;
}
float evalLightAttenuation(Light l, float d) {
float radius = getLightRadius(l);
float denom = d / radius + 1.0;
float attenuation = min(1.0, 1.0 / (denom * denom));
return attenuation;
}
SphericalHarmonics getLightAmbientSphere(Light l) {
return l._ambientSphere;
}

View file

@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityAdd:
case PacketType::EntityEdit:
case PacketType::EntityData:
return VERSION_ATMOSPHERE_REMOVED;
return VERSION_LIGHT_HAS_FALLOFF_RADIUS;
case PacketType::AvatarData:
case PacketType::BulkAvatarData:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SoftAttachmentSupport);

View file

@ -167,6 +167,7 @@ const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53;
const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54;
const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55;
const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56;
const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57;
enum class AvatarMixerPacketVersion : PacketVersion {
TranslationSupport = 17,

View file

@ -98,12 +98,12 @@ void DeferredLightingEffect::init() {
}
void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color,
float intensity) {
addSpotLight(position, radius, color, intensity);
float intensity, float falloffRadius) {
addSpotLight(position, radius, color, intensity, falloffRadius);
}
void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,
float intensity, const glm::quat& orientation, float exponent, float cutoff) {
float intensity, float falloffRadius, const glm::quat& orientation, float exponent, float cutoff) {
unsigned int lightID = (unsigned int)(_pointLights.size() + _spotLights.size() + _globalLights.size());
if (lightID >= _allocatedLights.size()) {
@ -115,7 +115,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
lp->setMaximumRadius(radius);
lp->setColor(color);
lp->setIntensity(intensity);
//lp->setShowContour(quadraticAttenuation);
lp->setFalloffRadius(falloffRadius);
if (exponent == 0.0f && cutoff == PI) {
lp->setType(model::Light::POINT);

View file

@ -36,11 +36,12 @@ public:
/// Adds a point light to render for the current frame.
void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f),
float intensity = 0.5f);
float intensity = 0.5f, float falloffRadius = 0.01f);
/// Adds a spot light to render for the current frame.
void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f),
float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
float intensity = 0.5f, float falloffRadius = 0.01f,
const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
void prepare(RenderArgs* args);
void render(const render::RenderContextPointer& renderContext);

View file

@ -48,7 +48,7 @@ void main(void) {
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
// Kill if too far from the light center
if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) {
if (dot(fragLightVec, fragLightVec) > getLightCutoffSquareRadius(light)) {
discard;
}

View file

@ -47,7 +47,7 @@ void main(void) {
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
// Kill if too far from the light center
if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) {
if (dot(fragLightVec, fragLightVec) > getLightCutoffSquareRadius(light)) {
discard;
}