From 6b29e314c20b672cf83a870724f966d2ad250357 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 25 Feb 2015 19:05:27 -0800 Subject: [PATCH] Adding the Stage of the Scene and exposing control of the sun light from javascript --- interface/src/Application.cpp | 15 +- libraries/gpu/src/gpu/Context.h | 2 +- libraries/gpu/src/gpu/GLBackend.h | 4 +- libraries/model/src/model/Stage.cpp | 442 ++++++++++++++++++ libraries/model/src/model/Stage.h | 200 ++++++++ .../src/SceneScriptingInterface.cpp | 36 ++ .../src/SceneScriptingInterface.h | 43 ++ libraries/script-engine/src/ScriptEngine.cpp | 5 + 8 files changed, 741 insertions(+), 6 deletions(-) create mode 100644 libraries/model/src/model/Stage.cpp create mode 100644 libraries/model/src/model/Stage.h create mode 100644 libraries/script-engine/src/SceneScriptingInterface.cpp create mode 100644 libraries/script-engine/src/SceneScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a7e73da1bd..9b27c6c570 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -82,6 +82,8 @@ #include #include +#include + #include "Application.h" #include "AudioClient.h" #include "InterfaceVersion.h" @@ -2495,7 +2497,10 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { glm::vec3 Application::getSunDirection() { // Sun direction is in fact just the location of the sun relative to the origin - return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition())); + // return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition())); + + auto skyStage = DependencyManager::get()->getSkyStage(); + return skyStage->getSunLight()->getDirection(); } void Application::updateShadowMap() { @@ -2505,7 +2510,7 @@ void Application::updateShadowMap() { glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); - glm::vec3 lightDirection = -getSunDirection(); + glm::vec3 lightDirection = getSunDirection(); glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); @@ -2875,7 +2880,11 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { DependencyManager::get()->setAmbientLightMode(getRenderAmbientLight()); - DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY); + // DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY); + auto skyStage = DependencyManager::get()->getSkyStage(); +// DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, skyStage->_light->getIntensity()); + DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity()); + PROFILE_RANGE("DeferredLighting"); PerformanceTimer perfTimer("lighting"); DependencyManager::get()->render(); diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index b8cba3ded1..8140c91bf6 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -21,7 +21,7 @@ namespace gpu { class GPUObject { public: GPUObject() {} - ~GPUObject() {} + virtual ~GPUObject() {} }; class Batch; diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index e3450ae71a..806ba0b1eb 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -32,7 +32,7 @@ public: static void checkGLError(); - class GLBuffer { + class GLBuffer : public GPUObject { public: Stamp _stamp; GLuint _buffer; @@ -44,7 +44,7 @@ public: static void syncGPUObject(const Buffer& buffer); static GLuint getBufferID(const Buffer& buffer); - class GLTexture { + class GLTexture : public GPUObject { public: Stamp _storageStamp; Stamp _contentStamp; diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp new file mode 100644 index 0000000000..64aa504965 --- /dev/null +++ b/libraries/model/src/model/Stage.cpp @@ -0,0 +1,442 @@ +// +// Stage.cpp +// libraries/model/src/model +// +// Created by Sam Gateau on 2/24/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Stage.h" + +#include +using namespace model; + + +void EarthSunModel::updateAll() const { + updateWorldToSurface(); + updateSurfaceToEye(); + updateSun(); +} + +Mat4d EarthSunModel::evalWorldToGeoLocationMat(double longitude, double latitude, double absAltitude, double scale) { + + + // Longitude is along Z axis but - from east to west + Mat4d rotLon = glm::rotate(glm::radians(longitude), Vec3d(0.0, 0.0, 1.0)); + + // latitude is along X axis + from south to north + Mat4d rotLat = glm::rotate(-glm::radians(latitude), Vec3d(1.0, 0.0, 0.0)); + + // translation is movin to the earth surface + altiture at the radius along Y axis + Mat4d surfaceT = glm::translate(Vec3d(0.0, -absAltitude, 0.0)); + + // Mat4d worldScale = glm::scale(Vec3d(scale)); + + Mat4d worldToGeoLocMat = surfaceT * rotLat * rotLon; + + return worldToGeoLocMat; +} + +void EarthSunModel::updateWorldToSurface() const { + // Check if the final position is too close to the earth center ? + double absAltitude = _earthRadius + _altitude; + if ( absAltitude < 0.01) { + absAltitude = 0.01; + } + + // Final world to local Frame + _worldToSurfaceMat = evalWorldToGeoLocationMat(_longitude, _latitude, absAltitude, _scale); + // and the inverse + _surfaceToWorldMat = glm::inverse(_worldToSurfaceMat); + + _surfacePos = Vec3d(_surfaceToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0)); +} + +void EarthSunModel::updateSurfaceToEye() const +{ + + _surfaceToEyeMat = glm::inverse(_eyeToSurfaceMat); + _worldToEyeMat = _surfaceToEyeMat * _worldToSurfaceMat; + _eyeToWorldMat = _surfaceToWorldMat * _eyeToSurfaceMat; + _eyePos = Vec3d(_eyeToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0) ); + _eyeDir = Vec3d(_eyeToWorldMat * Vec4d(0.0, 0.0, -1.0, 0.0) ); +} + +void EarthSunModel::updateSun() const { + // Longitude is along Y axis but - from east to west + Mat4d rotSunLon; + + Mat4d rotSun = evalWorldToGeoLocationMat(_sunLongitude, _sunLatitude, _earthRadius, _scale); + rotSun = glm::inverse(rotSun); + + _sunDir = Vec3d(rotSun * Vec4d(0.0, 1.0, 0.0, 0.0)); + + // sun direction is looking up toward Y axis at the specified sun lat, long + Vec3d lssd = Vec3d(_worldToSurfaceMat * Vec4d(_sunDir.x, _sunDir.y, _sunDir.z, 0.0)); + _surfaceSunDir = glm::normalize(Vec3(lssd.x, lssd.y, lssd.z)); +} + + +float moduloRange(float val, float minVal, float maxVal) { + float range = maxVal - minVal; + float rval = (val - minVal) / range; + float intval; + return modf(rval, &intval) * range + minVal; +} + +void EarthSunModel::setLatitude(float lat) { + _latitude = moduloRange(lat, -90.0f, 90.0f); + invalidate(); +} +void EarthSunModel::setLongitude(float lon) { + _longitude = moduloRange(lon, -180.0f, 180.0f); + invalidate(); +} +void EarthSunModel::setAltitude(float altitude) { + _altitude = moduloRange(altitude, -1000.f, 100000.f); + invalidate(); +} + +void EarthSunModel::setSunLatitude(float lat) { + _sunLatitude = moduloRange(lat, -90.0f, 90.0f); + invalidate(); +} +void EarthSunModel::setSunLongitude(float lon) { + _sunLongitude = moduloRange(lon, -180.0f, 180.0f); + invalidate(); +} + +const int NUM_DAYS_PER_YEAR = 365; +const float NUM_HOURS_PER_DAY = 24.0f; + +SunSkyStage::SunSkyStage() : + _sunLight(new Light()) +{ + _sunLight->setType(Light::SUN); + + setSunIntensity(1.0f); + setSunColor(Vec3(1.0f, 1.0f, 1.0f)); + + // setOriginLocation(45.0f, 20.0f, 1.0f); + setDayTime(18.0f); + setYearTime(60.0f); +} + +SunSkyStage::~SunSkyStage() { +} + +void SunSkyStage::setDayTime(float hour) { + _dayTime = moduloRange(hour, 0.f, NUM_HOURS_PER_DAY); + invalidate(); +} + +void SunSkyStage::setYearTime(unsigned int day) { + _yearTime = day % NUM_DAYS_PER_YEAR; + invalidate(); +} + +void SunSkyStage::setOriginLocation(float longitude, float latitude, float altitude) { + _earthSunModel.setLongitude(longitude); + _earthSunModel.setLatitude(latitude); + _earthSunModel.setAltitude(altitude); + invalidate(); +} + +void SunSkyStage::setSunColor(const Vec3& color) { + _sunLight->setColor(color); +} +void SunSkyStage::setSunIntensity(float intensity) { + _sunLight->setIntensity(intensity); +} + +void SunSkyStage::updateGraphicsObject() const { + // Always update the sunLongitude based on the current dayTIme and the current origin + _earthSunModel.setSunLongitude(_earthSunModel.getLongitude() + (-180.0 + 360.0 * _dayTime / NUM_HOURS_PER_DAY)); + + // And update the sunLAtitude as the declinaison depending of the time of the year + _earthSunModel.setSunLatitude(-(23.0 + 44.0/60.0)*cos(glm::radians((360.0/365.0)*(_yearTime + 10)))); + + Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); + + _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); +} + + + + + + +// +// Environment.cpp +// interface/src +// +// Created by Andrzej Kapolka on 5/6/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "InterfaceConfig.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Application.h" +#include "Camera.h" +#include "world.h" + +#include "Environment.h" + +uint qHash(const HifiSockAddr& sockAddr) { + if (sockAddr.getAddress().isNull()) { + return 0; // shouldn't happen, but if it does, zero is a perfectly valid hash + } + quint32 address = sockAddr.getAddress().toIPv4Address(); + return sockAddr.getPort() + qHash(QByteArray::fromRawData((char*) &address, + sizeof(address))); +} + +Environment::Environment() + : _initialized(false) { +} + +Environment::~Environment() { + if (_initialized) { + delete _skyFromAtmosphereProgram; + delete _skyFromSpaceProgram; + } +} + +void Environment::init() { + if (_initialized) { + qDebug("[ERROR] Environment is already initialized."); + return; + } + + _skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations); + _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); + + // start off with a default-constructed environment data + _data[HifiSockAddr()][0]; + + _initialized = true; +} + +void Environment::resetToDefault() { + _data.clear(); + _data[HifiSockAddr()][0]; +} + +void Environment::renderAtmospheres(Camera& camera) { + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + foreach (const ServerData& serverData, _data) { + // TODO: do something about EnvironmentData + foreach (const EnvironmentData& environmentData, serverData) { + renderAtmosphere(camera, environmentData); + } + } +} + +glm::vec3 Environment::getGravity (const glm::vec3& position) { + // + // 'Default' gravity pulls you downward in Y when you are near the X/Z plane + const glm::vec3 DEFAULT_GRAVITY(0.0f, -1.0f, 0.0f); + glm::vec3 gravity(DEFAULT_GRAVITY); + float DEFAULT_SURFACE_RADIUS = 30.0f; + float gravityStrength; + + // Weaken gravity with height + if (position.y > 0.0f) { + gravityStrength = 1.0f / powf((DEFAULT_SURFACE_RADIUS + position.y) / DEFAULT_SURFACE_RADIUS, 2.0f); + gravity *= gravityStrength; + } + + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + foreach (const ServerData& serverData, _data) { + foreach (const EnvironmentData& environmentData, serverData) { + glm::vec3 vector = environmentData.getAtmosphereCenter(position) - position; + float surfaceRadius = environmentData.getAtmosphereInnerRadius(); + if (glm::length(vector) <= surfaceRadius) { + // At or inside a planet, gravity is as set for the planet + gravity += glm::normalize(vector) * environmentData.getGravity(); + } else { + // Outside a planet, the gravity falls off with distance + gravityStrength = 1.0f / powf(glm::length(vector) / surfaceRadius, 2.0f); + gravity += glm::normalize(vector) * environmentData.getGravity() * gravityStrength; + } + } + } + + return gravity; +} + +const EnvironmentData Environment::getClosestData(const glm::vec3& position) { + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + EnvironmentData closest; + float closestDistance = FLT_MAX; + foreach (const ServerData& serverData, _data) { + foreach (const EnvironmentData& environmentData, serverData) { + float distance = glm::distance(position, environmentData.getAtmosphereCenter(position)) - + environmentData.getAtmosphereOuterRadius(); + if (distance < closestDistance) { + closest = environmentData; + closestDistance = distance; + } + } + } + return closest; +} + +bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, + float radius, glm::vec3& penetration) { + // collide with the "floor" + bool found = findCapsulePlanePenetration(start, end, radius, glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), penetration); + + glm::vec3 middle = (start + end) * 0.5f; + + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + foreach (const ServerData& serverData, _data) { + foreach (const EnvironmentData& environmentData, serverData) { + if (environmentData.getGravity() == 0.0f) { + continue; // don't bother colliding with gravity-less environments + } + glm::vec3 environmentPenetration; + if (findCapsuleSpherePenetration(start, end, radius, environmentData.getAtmosphereCenter(middle), + environmentData.getAtmosphereInnerRadius(), environmentPenetration)) { + penetration = addPenetrations(penetration, environmentPenetration); + found = true; + } + } + } + return found; +} + +int Environment::parseData(const HifiSockAddr& senderAddress, const QByteArray& packet) { + // push past the packet header + int bytesRead = numBytesForPacketHeader(packet); + + // push past flags, sequence, timestamp + bytesRead += sizeof(OCTREE_PACKET_FLAGS); + bytesRead += sizeof(OCTREE_PACKET_SEQUENCE); + bytesRead += sizeof(OCTREE_PACKET_SENT_TIME); + + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + EnvironmentData newData; + while (bytesRead < packet.size()) { + int dataLength = newData.parseData(reinterpret_cast(packet.data()) + bytesRead, + packet.size() - bytesRead); + + // update the mapping by address/ID + _data[senderAddress][newData.getID()] = newData; + + bytesRead += dataLength; + } + + // remove the default mapping, if any + _data.remove(HifiSockAddr()); + + return bytesRead; +} + +ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { + ProgramObject* program = new ProgramObject(); + QByteArray prefix = QString(PathUtils::resourcesPath() + "/shaders/SkyFrom" + from).toUtf8(); + program->addShaderFromSourceFile(QGLShader::Vertex, prefix + ".vert"); + program->addShaderFromSourceFile(QGLShader::Fragment, prefix + ".frag"); + program->link(); + + locations[CAMERA_POS_LOCATION] = program->uniformLocation("v3CameraPos"); + locations[LIGHT_POS_LOCATION] = program->uniformLocation("v3LightPos"); + locations[INV_WAVELENGTH_LOCATION] = program->uniformLocation("v3InvWavelength"); + locations[CAMERA_HEIGHT2_LOCATION] = program->uniformLocation("fCameraHeight2"); + locations[OUTER_RADIUS_LOCATION] = program->uniformLocation("fOuterRadius"); + locations[OUTER_RADIUS2_LOCATION] = program->uniformLocation("fOuterRadius2"); + locations[INNER_RADIUS_LOCATION] = program->uniformLocation("fInnerRadius"); + locations[KR_ESUN_LOCATION] = program->uniformLocation("fKrESun"); + locations[KM_ESUN_LOCATION] = program->uniformLocation("fKmESun"); + locations[KR_4PI_LOCATION] = program->uniformLocation("fKr4PI"); + locations[KM_4PI_LOCATION] = program->uniformLocation("fKm4PI"); + locations[SCALE_LOCATION] = program->uniformLocation("fScale"); + locations[SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleDepth"); + locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleOverScaleDepth"); + locations[G_LOCATION] = program->uniformLocation("g"); + locations[G2_LOCATION] = program->uniformLocation("g2"); + + return program; +} + +void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) { + glm::vec3 center = data.getAtmosphereCenter(camera.getPosition()); + + glPushMatrix(); + glTranslatef(center.x, center.y, center.z); + + glm::vec3 relativeCameraPos = camera.getPosition() - center; + float height = glm::length(relativeCameraPos); + + // use the appropriate shader depending on whether we're inside or outside + ProgramObject* program; + int* locations; + if (height < data.getAtmosphereOuterRadius()) { + program = _skyFromAtmosphereProgram; + locations = _skyFromAtmosphereUniformLocations; + + } else { + program = _skyFromSpaceProgram; + locations = _skyFromSpaceUniformLocations; + } + + // the constants here are from Sean O'Neil's GPU Gems entry + // (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp + program->bind(); + program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos); + glm::vec3 lightDirection = glm::normalize(data.getSunLocation()); + program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection); + program->setUniformValue(locations[INV_WAVELENGTH_LOCATION], + 1 / powf(data.getScatteringWavelengths().r, 4.0f), + 1 / powf(data.getScatteringWavelengths().g, 4.0f), + 1 / powf(data.getScatteringWavelengths().b, 4.0f)); + program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height); + program->setUniformValue(locations[OUTER_RADIUS_LOCATION], data.getAtmosphereOuterRadius()); + program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], data.getAtmosphereOuterRadius() * data.getAtmosphereOuterRadius()); + program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius()); + program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness()); + program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness()); + program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI); + program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI); + program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())); + program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f); + program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], + (1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())) / 0.25f); + program->setUniformValue(locations[G_LOCATION], -0.990f); + program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + DependencyManager::get()->renderSphere(1.0f, 100, 50, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); //Draw a unit sphere + glDepthMask(GL_TRUE); + + program->release(); + + glPopMatrix(); +} diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h new file mode 100644 index 0000000000..9b2922e163 --- /dev/null +++ b/libraries/model/src/model/Stage.h @@ -0,0 +1,200 @@ +// +// Stage.h +// libraries/model/src/model +// +// Created by Sam Gateau on 2/24/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_model_Stage_h +#define hifi_model_Stage_h + +#include "Light.h" + +namespace model { + +typedef glm::dvec3 Vec3d; +typedef glm::dvec4 Vec4d; +typedef glm::dmat4 Mat4d; +typedef glm::mat4 Mat4; + +class EarthSunModel { +public: + enum Preset + { + Toulouse = 0, + SanFrancisco, + Sydney, + Num_Presets, + }; + static const std::string PresetNames[Num_Presets]; + //void assignPreset( Preset p); + //Preset preset() const { return mPreset; } + + void setScale(float scale); + float getScale() const { return _scale; } + + void setLatitude(float lat); + float getLatitude() const { return _latitude; } + void setLongitude(float lon); + float getLongitude() const { return _longitude; } + void setAltitude(float altitude); + float getAltitude() const { return _altitude; } + + const Vec3d& getSurfacePos() const { valid(); return _surfacePos; } + + const Mat4d& getSurfaceToWorldMat() const { valid(); return _surfaceToWorldMat; } + const Mat4d& getWoldToSurfaceMat() const { valid(); return _worldToSurfaceMat; } + + const Mat4d& getEyeToSurfaceMat() const { valid(); return _eyeToSurfaceMat; } + const Mat4d& getSurfaceToEyeMat() const { valid(); return _surfaceToEyeMat; } + + const Mat4d& getEyeToWorldMat() const { valid(); return _eyeToWorldMat; } + const Mat4d& getWorldToEyeMat() const { valid(); return _worldToEyeMat; } + + + //or set the surfaceToEye mat directly + void setEyeToSurfaceMat( const Mat4d& e2s); + + const Vec3d& getEyePos() const { valid(); return _eyePos; } + const Vec3d& getEyeDir() const { valid(); return _eyeDir; } + + void setSunLongitude(float lon); + float getSunLongitude() const { return _sunLongitude; } + + void setSunLatitude(float lat); + float getSunLatitude() const { return _sunLatitude; } + + const Vec3d& getWorldSunDir() const { valid(); return _sunDir; } + const Vec3d& getSurfaceSunDir() const { valid(); return _surfaceSunDir; } + + + EarthSunModel() { valid(); } + +protected: + double _scale = 1000.0; //Km + double _earthRadius = 6360.0; + + double _longitude = 0.0; + double _latitude = 0.0; + double _altitude = 0.01; + mutable Vec3d _surfacePos; + mutable Mat4d _worldToSurfaceMat; + mutable Mat4d _surfaceToWorldMat; + void updateWorldToSurface() const; + + mutable Mat4d _surfaceToEyeMat; + mutable Mat4d _eyeToSurfaceMat; + mutable Vec3d _eyeDir; + mutable Vec3d _eyePos; + void updateSurfaceToEye() const; + + mutable Mat4d _worldToEyeMat; + mutable Mat4d _eyeToWorldMat; + + double _sunLongitude = 0.0; + double _sunLatitude = 0.0; + mutable Vec3d _sunDir; + mutable Vec3d _surfaceSunDir; + void updateSun() const; + + mutable bool _invalid = true; + void invalidate() const { _invalid = true; } + void valid() const { if (_invalid) { updateAll(); _invalid = false; } } + void updateAll() const; + + static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale); +}; + +namespace gpu { + class Batch; +}; + +class ProgramObject; + +class Skybox { +public: + void recordBatch(gpu::Batch& batch, const Transform& viewTransform, const Mat4& projection); + + Skybox(); + ~Skybox(); +protected: + ProgramObject* createSkyProgram(const char* from, int* locations); + ProgramObject* _skyFromAtmosphereProgram; + ProgramObject* _skyFromSpaceProgram; + enum { + CAMERA_POS_LOCATION, + LIGHT_POS_LOCATION, + INV_WAVELENGTH_LOCATION, + CAMERA_HEIGHT2_LOCATION, + OUTER_RADIUS_LOCATION, + OUTER_RADIUS2_LOCATION, + INNER_RADIUS_LOCATION, + KR_ESUN_LOCATION, + KM_ESUN_LOCATION, + KR_4PI_LOCATION, + KM_4PI_LOCATION, + SCALE_LOCATION, + SCALE_DEPTH_LOCATION, + SCALE_OVER_SCALE_DEPTH_LOCATION, + G_LOCATION, + G2_LOCATION, + LOCATION_COUNT + }; + + int _skyFromAtmosphereUniformLocations[LOCATION_COUNT]; + int _skyFromSpaceUniformLocations[LOCATION_COUNT]; +}; + +// Sun sky stage generates the rendering primitives to display a scene realistically +// at the specified location and time around earth +class SunSkyStage { +public: + + SunSkyStage(); + ~SunSkyStage(); + + // time of the day (local to the position) expressed in decimal hour in the range [0.0, 24.0] + void setDayTime(float hour); + float getDayTime() const { return _dayTime; } + + // time of the year expressed in day in the range [0, 365] + void setYearTime(unsigned int day); + unsigned int getYearTime() const { return _yearTime; } + + // Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km] + void setOriginLocation(float longitude, float latitude, float surfaceAltitude); + float getOriginLatitude() const { return _earthSunModel.getLatitude(); } + float getOriginLongitude() const { return _earthSunModel.getLongitude(); } + float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } + + // Sun properties + void setSunColor(const Vec3& color); + const Vec3& getSunColor() const { return getSunLight()->getColor(); } + void setSunIntensity(float intensity); + float getSunIntensity() const { return getSunLight()->getIntensity(); } + + LightPointer getSunLight() const { valid(); return _sunLight; } + +protected: + LightPointer _sunLight; + + // default day is 1st of january at noun + float _dayTime = 12.0f; + int _yearTime = 0; + + mutable EarthSunModel _earthSunModel; + + mutable bool _invalid = true; + void invalidate() const { _invalid = true; } + void valid() const { if (_invalid) { updateGraphicsObject(); _invalid = false; } } + void updateGraphicsObject() const; +}; + +typedef QSharedPointer< SunSkyStage > SunSkyStagePointer; + +}; + +#endif diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp new file mode 100644 index 0000000000..ff255a3e5e --- /dev/null +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -0,0 +1,36 @@ +// +// SceneScriptingInterface.cpp +// interface/src/scripting +// +// Created by Sam Gateau on 2/24/15. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "SceneScriptingInterface.h" + + Q_INVOKABLE void setOriginGeoLocation(float longitude, float latitude, float altitude); +void SceneScriptingInterface::setOriginLocation(float longitude, float latitude, float altitude) { + _skyStage->setOriginLocation(longitude, latitude, altitude); +} +void SceneScriptingInterface::setSunColor(const glm::vec3& color) { + _skyStage->setSunColor(color); +} +void SceneScriptingInterface::setSunIntensity(float intensity) { + _skyStage->setSunIntensity(intensity); +} + +void SceneScriptingInterface::setDayTime(float hour) { + _skyStage->setDayTime(hour); +} +void SceneScriptingInterface::setYearTime(int day) { + _skyStage->setYearTime(day); +} + +model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { + return _skyStage; +} \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h new file mode 100644 index 0000000000..3fc909f9a0 --- /dev/null +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -0,0 +1,43 @@ +// +// SceneScriptingInterface.h +// interface/src/scripting +// +// Created by Sam Gateau on 2/24/15. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SceneScriptingInterface_h +#define hifi_SceneScriptingInterface_h + +#include + +#include + +#include "model/Stage.h" + +class SceneScriptingInterface : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + Q_INVOKABLE void setOriginLocation(float longitude, float latitude, float altitude); + + Q_INVOKABLE void setSunColor(const glm::vec3& color); + Q_INVOKABLE void setSunIntensity(float intensity); + + Q_INVOKABLE void setDayTime(float hour); + Q_INVOKABLE void setYearTime(int day); + + model::SunSkyStagePointer getSkyStage() const; + +protected: + SceneScriptingInterface() {}; + ~SceneScriptingInterface() {}; + + model::SunSkyStagePointer _skyStage = model::SunSkyStagePointer(new model::SunSkyStage()); +}; + +#endif // hifi_SceneScriptingInterface_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0956374238..aed5d91410 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -39,6 +39,8 @@ #include "TypedArrays.h" #include "XMLHttpRequestClass.h" +#include "SceneScriptingInterface.h" + #include "MIDIEvent.h" EntityScriptingInterface ScriptEngine::_entityScriptingInterface; @@ -208,6 +210,8 @@ void ScriptEngine::init() { _isInitialized = true; + auto sceneScriptingInterface = DependencyManager::set(); + _entityScriptingInterface.init(); // register various meta-types @@ -251,6 +255,7 @@ void ScriptEngine::init() { registerGlobalObject("Vec3", &_vec3Library); registerGlobalObject("Uuid", &_uuidLibrary); registerGlobalObject("AnimationCache", DependencyManager::get().data()); + registerGlobalObject("Scene", DependencyManager::get().data()); // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));