diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index e6c06bb1ae..e4826dcfeb 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -41,7 +41,8 @@ panel.newSlider("Year Time", 0, 364, ); panel.newSlider("Day Time", 0, 24, - function(value) { Scene.setStageDayTime(value); }, + + function(value) { Scene.setStageDayTime(value); panel.update("Light Direction"); }, function() { return Scene.getStageDayTime(); }, function(value) { var hour = Math.floor(value); @@ -72,12 +73,36 @@ function runStageTime() { } Script.setInterval(runStageTime, tickTackPeriod); +panel.newCheckbox("Enable Earth Sun Model", + function(value) { Scene.setStageEarthSunModelEnable((value != 0)); }, + function() { return Scene.isStageEarthSunModelEnabled(); }, + function(value) { return (value); } +); + +panel.newDirectionBox("Light Direction", + function(value) { Scene.setSunDirection(value); }, + function() { return Scene.getSunDirection(); }, + function(value) { return value.x.toFixed(2) + "," + value.y.toFixed(2) + "," + value.z.toFixed(2); } +); + panel.newSlider("Light Intensity", 0.0, 5, function(value) { Scene.setSunIntensity(value); }, function() { return Scene.getSunIntensity(); }, function(value) { return (value).toFixed(2); } ); +panel.newSlider("Ambient Light Intensity", 0.0, 1.0, + function(value) { Scene.setSunAmbientIntensity(value); }, + function() { return Scene.getSunAmbientIntensity(); }, + function(value) { return (value).toFixed(2); } +); + +panel.newColorBox("Light Color", + function(value) { Scene.setSunColor(value); }, + function() { return Scene.getSunColor(); }, + function(value) { return (value); } // "(" + value.x + "," = value.y + "," + value.z + ")"; } +); + Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 205b19c9f9..0182bf8db0 100755 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -12,6 +12,129 @@ // The Slider class Slider = function(x,y,width,thumbSize) { + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + + this.thumbSize = thumbSize; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; + + this.clickOffsetX = 0; + this.isMoving = false; + + this.updateThumb = function() { + thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; + + this.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; + + this.onMouseMoveEvent = function(event) { + if (this.isMoving) { + newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + this.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + // Public members: + + this.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + this.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + this.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + this.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + this.onValueChanged = function(value) {}; + + this.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; + + this.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + this.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; +} + +// The Checkbox class +Checkbox = function(x,y,width,thumbSize) { this.thumb = Overlays.addOverlay("text", { backgroundColor: { red: 255, green: 255, blue: 255 }, @@ -52,6 +175,10 @@ Slider = function(x,y,width,thumbSize) { Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); }; + this.isClickableOverlayItem = function(item) { + return item == this.background; + }; + this.onMouseMoveEvent = function(event) { if (this.isMoving) { newThumbX = event.x - this.clickOffsetX; @@ -67,7 +194,11 @@ Slider = function(x,y,width,thumbSize) { } }; - this.onMousePressEvent = function(event) { + this.onMousePressEvent = function(event, clickedOverlay) { + if (this.background != clickedOverlay) { + this.isMoving = false; + return; + } this.isMoving = true; var clickOffset = event.x - this.thumbX; if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { @@ -118,6 +249,167 @@ Slider = function(x,y,width,thumbSize) { }; } +// The ColorBox class +ColorBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 3; + var sliderWidth = width; + this.red = new Slider(x, y, width, slideHeight); + this.green = new Slider(x, y + slideHeight, width, slideHeight); + this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); + this.red.setBackgroundColor({x: 1, y: 0, z: 0}); + this.green.setBackgroundColor({x: 0, y: 1, z: 0}); + this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); + + this.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) + || this.green.isClickableOverlayItem(item) + || this.blue.isClickableOverlayItem(item); + }; + + this.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; + } + + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); + }; + + this.onMouseReleaseEvent = function(event) { + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; + + this.setterFromWidget = function(value) { + var color = self.getValue(); + self.onValueChanged(color); + self.updateRGBSliders(color); + }; + + this.red.onValueChanged = this.setterFromWidget; + this.green.onValueChanged = this.setterFromWidget; + this.blue.onValueChanged = this.setterFromWidget; + + this.updateRGBSliders = function(color) { + this.red.setThumbColor({x: color.x, y: 0, z: 0}); + this.green.setThumbColor({x: 0, y: color.y, z: 0}); + this.blue.setThumbColor({x: 0, y: 0, z: color.z}); + }; + + // Public members: + this.setValue = function(value) { + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); + }; + + this.getValue = function() { + var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; + return value; + }; + + this.destroy = function() { + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); + }; + + this.onValueChanged = function(value) {}; +} + +// The DirectionBox class +DirectionBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 2; + var sliderWidth = width; + this.yaw = new Slider(x, y, width, slideHeight); + this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + this.yaw.minValue = -180; + this.yaw.maxValue = +180; + + this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + this.pitch.minValue = -1; + this.pitch.maxValue = +1; + + this.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) + || this.pitch.isClickableOverlayItem(item); + }; + + this.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + this.onMouseReleaseEvent = function(event) { + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; + + this.setterFromWidget = function(value) { + var yawPitch = self.getValue(); + self.onValueChanged(yawPitch); + }; + + this.yaw.onValueChanged = this.setterFromWidget; + this.pitch.onValueChanged = this.setterFromWidget; + + // Public members: + this.setValue = function(direction) { + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; + } + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; + + this.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ*dirZ); + var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; + return value; + }; + + this.destroy = function() { + this.yaw.destroy(); + this.pitch.destroy(); + }; + + this.onValueChanged = function(value) {}; +} var textFontSize = 16; @@ -167,7 +459,12 @@ function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, }; this.setterFromWidget = function(value) { setter(value); - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + // ANd loop back the value after the final setter has been called + var value = getter(); + if (this.widget) { + this.widget.setValue(value); + } + Overlays.editOverlay(this.value, {text: this.displayer(value)}); }; @@ -219,9 +516,9 @@ Panel = function(x, y) { for (var i in this.items) { var widget = this.items[i].widget; - if (clickedOverlay == widget.background) { + if (widget.isClickableOverlayItem(clickedOverlay)) { this.activeWidget = widget; - this.activeWidget.onMousePressEvent(event); + this.activeWidget.onMousePressEvent(event, clickedOverlay); // print("clicked... widget=" + i); break; } @@ -237,21 +534,63 @@ Panel = function(x, y) { this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { - var sliderItem = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); slider.minValue = minValue; slider.maxValue = maxValue; - slider.onValueChanged = function(value) { sliderItem.setterFromWidget(value); }; - sliderItem.widget = slider; - sliderItem.setter(getValue()); - this.items[name] = sliderItem; + item.widget = slider; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; this.nextY += rawYDelta; // print("created Item... slider=" + name); }; + this.newCheckbox = function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = checkbox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... slider=" + name); + }; + + this.newColorBox = function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = colorBox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... colorBox=" + name); + }; + + this.newDirectionBox= function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = directionBox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... directionBox=" + name); + }; + this.destroy = function() { for (var i in this.items) { this.items[i].destroy(); @@ -273,6 +612,15 @@ Panel = function(x, y) { } return null; } + + this.update = function(name) { + var item = this.items[name]; + if (item != null) { + return item.setter(item.getter()); + } + return null; + } + }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0227003cb1..3e7b17764d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3048,7 +3048,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { DependencyManager::get()->setAmbientLightMode(getRenderAmbientLight()); auto skyStage = DependencyManager::get()->getSkyStage(); - DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity()); + DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity()); DependencyManager::get()->setGlobalAtmosphere(skyStage->getAtmosphere()); PROFILE_RANGE("DeferredLighting"); diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index ea77412140..e8c01c68aa 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -64,6 +64,10 @@ void Light::setIntensity(float intensity) { editSchema()._intensity = intensity; } +void Light::setAmbientIntensity(float intensity) { + editSchema()._ambientIntensity = intensity; +} + void Light::setMaximumRadius(float radius) { if (radius <= 0.f) { radius = 1.0f; diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 8f6c663668..30e3a8edad 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -244,6 +244,10 @@ public: void setShowContour(float show); float getShowContour() const { return getSchema()._control.w; } + // If the light has an ambient (Indirect) component, then the Ambientintensity can be used to control its contribution to the lighting + void setAmbientIntensity(float intensity); + float getAmbientIntensity() const { return getSchema()._ambientIntensity; } + // Spherical Harmonics storing the Ambien lighting approximation used for the Sun typed light void setAmbientSphere(const SphericalHarmonics& sphere) { _ambientSphere = sphere; } const SphericalHarmonics& getAmbientSphere() const { return _ambientSphere; } @@ -254,14 +258,14 @@ public: public: Vec4 _position{0.0f, 0.0f, 0.0f, 1.0f}; Vec3 _direction{0.0f, 0.0f, -1.0f}; - float _spare0{0.0f}; + float _ambientIntensity{0.0f}; Color _color{1.0f}; float _intensity{1.0f}; Vec4 _attenuation{1.0f}; Vec4 _spot{0.0f, 0.0f, 0.0f, 3.0f}; Vec4 _shadow{0.0f}; - Vec4 _control{0.0f}; + Vec4 _control{0.0f, 0.0f, 0.0f, 0.0f}; Schema() {} }; diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 41c6e075cf..1aaf0e8327 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -27,6 +27,7 @@ vec3 getLightDirection(Light l) { return l._direction.xyz; } // direction is -Z 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); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index b72aa16497..68c13e5a7c 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -203,6 +203,7 @@ SunSkyStage::SunSkyStage() : _sunLight->setType(Light::SUN); setSunIntensity(1.0f); + setSunAmbientIntensity(0.5f); setSunColor(Vec3(1.0f, 1.0f, 1.0f)); // Default origin location is a special place in the world... @@ -249,12 +250,26 @@ void SunSkyStage::setOriginLocation(float longitude, float latitude, float altit invalidate(); } +void SunSkyStage::setEarthSunModelEnable(bool isEnabled) { + _earthSunModelEnable = isEnabled; + invalidate(); +} + void SunSkyStage::setSunColor(const Vec3& color) { _sunLight->setColor(color); } void SunSkyStage::setSunIntensity(float intensity) { _sunLight->setIntensity(intensity); } +void SunSkyStage::setSunAmbientIntensity(float intensity) { + _sunLight->setAmbientIntensity(intensity); +} + +void SunSkyStage::setSunDirection(const Vec3& direction) { + if (!isEarthSunModelEnabled()) { + _sunLight->setDirection(direction); + } +} // THe sun declinaison calculus is taken from https://en.wikipedia.org/wiki/Position_of_the_Sun double evalSunDeclinaison(double dayNumber) { @@ -271,19 +286,19 @@ void SunSkyStage::updateGraphicsObject() const { // And update the sunLAtitude as the declinaison depending of the time of the year _earthSunModel.setSunLatitude(evalSunDeclinaison(_yearTime)); - Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); - _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); + if (isEarthSunModelEnabled()) { + Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); + _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); - double originAlt = _earthSunModel.getAltitude(); - _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); + double originAlt = _earthSunModel.getAltitude(); + _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); + } static int firstTime = 0; if (firstTime == 0) { firstTime++; gpu::Shader::makeProgram(*(_skyPipeline->getProgram())); - } - } void SunSkyStage::setSkybox(const SkyboxPointer& skybox) { diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 30c96259ca..eca290b852 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -203,12 +203,22 @@ public: float getOriginLongitude() const { return _earthSunModel.getLongitude(); } float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } + // Enable / disable the effect of the time and location on the sun direction and color + void setEarthSunModelEnable(bool isEnabled); + bool isEarthSunModelEnabled() const { return _earthSunModelEnable; } + // Sun properties void setSunColor(const Vec3& color); const Vec3& getSunColor() const { return getSunLight()->getColor(); } void setSunIntensity(float intensity); float getSunIntensity() const { return getSunLight()->getIntensity(); } + void setSunAmbientIntensity(float intensity); + float getSunAmbientIntensity() const { return getSunLight()->getAmbientIntensity(); } + // The sun direction is expressed in the world space + void setSunDirection(const Vec3& direction); + const Vec3& getSunDirection() const { return getSunLight()->getDirection(); } + LightPointer getSunLight() const { valid(); return _sunLight; } AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; } @@ -223,10 +233,10 @@ protected: gpu::PipelinePointer _skyPipeline; - float _dayTime; - int _yearTime; - + float _dayTime = 12.0f; + int _yearTime = 0; mutable EarthSunModel _earthSunModel; + bool _earthSunModelEnable = true; mutable bool _invalid = true; void invalidate() const { _invalid = true; } diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index ecb1f503c7..cbf7c31d1f 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -66,7 +66,7 @@ vec3 evalAmbienGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec3 color = diffuse.rgb * getLightColor(light) * 0.5; + vec3 color = diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); @@ -83,7 +83,7 @@ vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 no vec3 fragEyeDir = normalize(fragEyeVector.xyz); vec3 ambientNormal = fragNormal.xyz; - vec3 color = diffuse.rgb * 0.5 * evalSphericalLight(ambientSphere, ambientNormal).xyz; + vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, ambientNormal).xyz * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); @@ -112,7 +112,7 @@ vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, ve vec3 diffuseLight = lightAttenuation * lightmap; // ambient is a tiny percentage of the lightmap and only when in the shadow - vec3 ambientLight = (1 - lightAttenuation) * 0.5 * lightmap; + vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); return diffuse * (ambientLight + diffuseLight); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 440f75e32e..bddb1815bf 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -554,11 +554,12 @@ void DeferredLightingEffect::setAmbientLightMode(int preset) { } } -void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity) { +void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) { auto light = _allocatedLights.front(); light->setDirection(direction); light->setColor(diffuse); light->setIntensity(intensity); + light->setAmbientIntensity(ambientIntensity); } void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 6d0d131029..0d3d370fd4 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -73,7 +73,7 @@ public: // update global lighting void setAmbientLightMode(int preset); - void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity); + void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity); void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } void setGlobalSkybox(const model::SkyboxPointer& skybox); diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 5a8f591410..557938c78a 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -50,7 +50,7 @@ void SceneScriptingInterface::setSunColor(const glm::vec3& color) { _skyStage->setSunColor(color); } -const glm::vec3& SceneScriptingInterface::getSunColor() const { +glm::vec3 SceneScriptingInterface::getSunColor() const { return _skyStage->getSunColor(); } @@ -62,6 +62,30 @@ float SceneScriptingInterface::getSunIntensity() const { return _skyStage->getSunIntensity(); } +void SceneScriptingInterface::setSunAmbientIntensity(float intensity) { + _skyStage->setSunAmbientIntensity(intensity); +} + +float SceneScriptingInterface::getSunAmbientIntensity() const { + return _skyStage->getSunAmbientIntensity(); +} + +void SceneScriptingInterface::setSunDirection(const glm::vec3& direction) { + _skyStage->setSunDirection(direction); +} + +glm::vec3 SceneScriptingInterface::getSunDirection() const { + return _skyStage->getSunDirection(); +} + +void SceneScriptingInterface::setStageEarthSunModelEnable(bool isEnabled) { + _skyStage->setEarthSunModelEnable(isEnabled); +} + +bool SceneScriptingInterface::isStageEarthSunModelEnabled() const { + return _skyStage->isEarthSunModelEnabled(); +} + model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 352bc1e78f..e847b7ff68 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -38,10 +38,24 @@ public: Q_INVOKABLE void setStageYearTime(int day); Q_INVOKABLE int getStageYearTime() const; + Q_INVOKABLE void setStageEarthSunModelEnable(bool isEnabled); + Q_INVOKABLE bool isStageEarthSunModelEnabled() const; + + Q_INVOKABLE void setSunColor(const glm::vec3& color); - Q_INVOKABLE const glm::vec3& getSunColor() const; + Q_INVOKABLE glm::vec3 getSunColor() const; Q_INVOKABLE void setSunIntensity(float intensity); Q_INVOKABLE float getSunIntensity() const; + Q_INVOKABLE void setSunAmbientIntensity(float intensity); + Q_INVOKABLE float getSunAmbientIntensity() const; + + // Only valid if stage Earth Sun model is disabled + Q_INVOKABLE void setSunDirection(const glm::vec3& direction); + + Q_INVOKABLE glm::vec3 getSunDirection() const; + + + model::SunSkyStagePointer getSkyStage() const;