284 lines
13 KiB
JavaScript
284 lines
13 KiB
JavaScript
// JavaScript source code
|
|
// Template by Antony Evans
|
|
// sunset API used with attribution to https://sunrise-sunset.org/api
|
|
(function () {
|
|
var sun;
|
|
var sunlight;
|
|
var latitude = 0; // will move to userdata
|
|
var longitude = 0;
|
|
var dayLength; // in seconds will move to userdata
|
|
var time = 0.9; // 0-1 for how far through day we are
|
|
var sunDistance = 2500; // radius for distance of sun
|
|
var updateFreq = 100; // how often we refresh sun position
|
|
var starMap = "";
|
|
const RADPERDEGREE = 0.0174533;
|
|
var useRealTime = true;
|
|
var nightLight;
|
|
var timer1;
|
|
var timer2;
|
|
var sunrise = 0.2484837962962963;
|
|
var sunset = 0.7506828703703704;
|
|
var sunData = {};
|
|
var civil_twilight_begin = 0.22568287037037038; // these defaults are based on London on spring equinox
|
|
var civil_twilight_end = 0.7790393518518518;
|
|
var nautical_twilight_begin = 0.19864583333333333;
|
|
var nautical_twilight_end = 0.8060763888888889;
|
|
var astronomical_twilight_begin = 0.1705324074074074;
|
|
var astronomical_twilight_end = 0.8341898148148148;
|
|
var startSunset = 0.4; //need to adjust for 0 being sunrise to 0 being midnight
|
|
var startTwilight = 0.12; //need to adjust
|
|
|
|
|
|
|
|
function MyObject() {
|
|
// Can be used a constructor
|
|
}
|
|
|
|
MyObject.prototype = {
|
|
preload: function (entityID) {
|
|
// When an entity instance has been loaded into the world, this is triggered.
|
|
Script.setTimeout(function () {
|
|
// this timeout is to ensure the sun and light loads before the script starts
|
|
var properties = Entities.getEntityProperties(entityID);
|
|
timer1 = Script.setInterval(function () {
|
|
// regularly check for updates to USerData
|
|
var tempLongitude = longitude;
|
|
var tempLatitude = latitude;
|
|
properties = Entities.getEntityProperties(entityID);
|
|
var userData = JSON.parse(properties.userData);
|
|
dayLength = userData.dayLength;
|
|
latitude = RADPERDEGREE * userData.latitude;
|
|
longitude = RADPERDEGREE * userData.longitude;
|
|
nightLight = userData.nightLight;
|
|
starMap = userData.nightSkyURL;
|
|
useRealTime = userData.useRealTime;
|
|
|
|
if ((longitude !== tempLongitude) || (latitude !== tempLatitude)) {
|
|
// update sunset/sunrise times because we changed userdata location
|
|
print("updating sunrise");
|
|
var request = new XMLHttpRequest();
|
|
var lat = latitude / RADPERDEGREE + 0.0001; //small addition fixes bug when supply integers not floats
|
|
var lng = longitude / RADPERDEGREE + 0.0001;
|
|
request.open('GET', 'https://api.sunrise-sunset.org/json?lat=' + lat.toString() + '&lng=' + lng.toString() + '&date=today', false);
|
|
request.onreadystatechange = function () {
|
|
var status = request.status;
|
|
if ((status >= 200) && (status < 400)) {
|
|
if (request.responseText) {
|
|
var sunData = JSON.parse(request.responseText);
|
|
print(JSON.stringify(request.responseText));
|
|
sunrise = convertDateToDayFraction(sunData.results.sunrise);
|
|
sunset = convertDateToDayFraction(sunData.results.sunset);
|
|
civil_twilight_begin = convertDateToDayFraction(sunData.results.civil_twilight_begin);
|
|
civil_twilight_end = convertDateToDayFraction(sunData.results.civil_twilight_end);
|
|
nautical_twilight_begin = convertDateToDayFraction(sunData.results.nautical_twilight_begin);
|
|
nautical_twilight_end = convertDateToDayFraction(sunData.results.nautical_twilight_end);
|
|
astronomical_twilight_begin = convertDateToDayFraction(sunData.results.astronomical_twilight_begin);
|
|
astronomical_twilight_end = convertDateToDayFraction(sunData.results.astronomical_twilight_end);
|
|
//print("sunrise: " + sunrise.toString());
|
|
//print("sunset: " + sunset.toString());
|
|
//print("nautical_twilight_end: " + nautical_twilight_begin.toString());
|
|
//print("time: " + time.toString());
|
|
startSunset = - Math.sin(calcAngleFromTime(nautical_twilight_begin)) * Math.cos(latitude);
|
|
//print("startSunset: " + startSunset.toString());
|
|
|
|
startTwilight = - Math.sin(calcAngleFromTime(civil_twilight_begin)) * Math.cos(latitude);
|
|
//print("startTwilight: " + startTwilight.toString());
|
|
}
|
|
}
|
|
};
|
|
// Send request
|
|
request.send();
|
|
}
|
|
}, 1000);
|
|
|
|
|
|
timer2 = Script.setInterval(function () {
|
|
// this is our main script loop that moves the sun etc
|
|
|
|
// time is a fraction between 0 and 1 for how far through the day we are
|
|
if (useRealTime) {
|
|
var d = new Date();
|
|
var n = d.getTimezoneOffset();
|
|
var h = d.getHours();
|
|
var m = d.getMinutes();
|
|
var s = d.getSeconds();
|
|
var ms = d.getMilliseconds();
|
|
time = (h*60 + m + n + (s / 60) + (ms / 60000)) / (24*60) // note this time is UTC fraction of day to match sunset/sunrise times which return in UTC
|
|
|
|
time = ((time < 0) ? 1 + time : time) ;
|
|
time = ((time >= 1) ? time - 1 : time) ;
|
|
//print("time: " + h.toString() + ":" + m.toString());
|
|
} else {
|
|
time += updateFreq/(1000 * dayLength);
|
|
time = ((time < 1) ? time : 0) ;
|
|
}
|
|
|
|
|
|
// print("time is: " + time.toString());
|
|
|
|
setSun(entityID, time, properties.position);
|
|
|
|
// print("Time: " + time);
|
|
}, updateFreq);
|
|
|
|
}, 1500);
|
|
},
|
|
unload: function (entityID) {
|
|
Script.clearInterval(timer1);
|
|
Script.clearInterval(timer2);
|
|
}
|
|
}
|
|
|
|
function convertDateToDayFraction(timeString) {
|
|
var seconds = 0;
|
|
var time = timeString.split(" ");
|
|
if (time[1] == "PM") {seconds += 12*60*60} ;
|
|
time = time[0].split(":");
|
|
seconds += ((time[0] > 11.5) ? 0 : parseInt(time[0])*60*60); //this catches 12 not being 0
|
|
seconds += parseInt(time[1])*60;
|
|
seconds += parseInt(time[2]);
|
|
var output = seconds / (24*60*60) ;
|
|
return output;
|
|
}
|
|
|
|
function calcAngleFromTime(timeInput) {
|
|
var angle = 0;
|
|
if (sunset > sunrise) {
|
|
if (timeInput < sunrise) {
|
|
// nighttime
|
|
angle = Math.PI * (timeInput - sunrise) / (1 - sunset + sunrise);
|
|
} else if (timeInput < sunset) {
|
|
// day time
|
|
angle = Math.PI * (timeInput - sunrise) / (sunset - sunrise);
|
|
} else {
|
|
// night time
|
|
angle = Math.PI * (1+((timeInput - sunset) / (1 - sunset + sunrise))); // at sunset angle is pi then increases from there, creating negative sin angle
|
|
}
|
|
} else {
|
|
// this is when longitude is high and we are on opposite side of world so sunrise is PM UTC
|
|
if (timeInput < sunset) {
|
|
// day time
|
|
angle = Math.PI * (1-((sunset - timeInput) / (1 - sunrise + sunset)));
|
|
} else if (timeInput < sunrise) {
|
|
// night time
|
|
angle = Math.PI * (1+((timeInput - sunset) / (sunrise - sunset))); // goes between pi and 2pi
|
|
} else {
|
|
// day time
|
|
angle = Math.PI * (timeInput - sunrise) / (1 - sunrise + sunset);
|
|
}
|
|
}
|
|
return angle;
|
|
}
|
|
|
|
function setSun(entityID, time, position) {
|
|
|
|
var angle = calcAngleFromTime(time);
|
|
|
|
var x = sunDistance * Math.sin(latitude);
|
|
var y = sunDistance * Math.sin(angle) * Math.cos(latitude);
|
|
var z = sunDistance * Math.cos(angle) * Math.cos(latitude);
|
|
var altitude = y / sunDistance;
|
|
var sunsetPercent;
|
|
var nightPercent;
|
|
var showdows;
|
|
var skyColor;
|
|
var sunColor;
|
|
var hazeColor;
|
|
var nightSky;
|
|
var lightDirection;
|
|
var normalize = Math.sqrt( Math.pow(x,2) + Math.pow(y,2) + Math.pow(z,2)); // this is wrong but is working anyway
|
|
if (altitude > startSunset) {
|
|
// midday sun
|
|
sunsetPercent = 0;
|
|
nightPercent = 0;
|
|
sunColor = { "r": 230, "g": 210, "b": 161 };
|
|
skyColor = { "r": 0, "g": 100, "b": 255};
|
|
hazeColor = { "r": 255, "g": 255, "b": 255};
|
|
nightSky = "";
|
|
shadows = true;
|
|
lightDirection = { "x": - x / normalize, "y": - y / normalize, "z": - z / normalize };
|
|
} else if (altitude > 0) {
|
|
//sunrise
|
|
sunsetPercent = Math.pow(1 - (altitude/startSunset),2);
|
|
nightPercent = 0;
|
|
sunColor = { "r": 255 - sunsetPercent*2, "g": 255 - sunsetPercent*183, "b": 255 - sunsetPercent*172};
|
|
skyColor = { "r": 0, "g": 100 - sunsetPercent*100, "b": 255 - sunsetPercent*255};
|
|
hazeColor = { "r": 255 - sunsetPercent*2, "g": 255 - sunsetPercent*183, "b": 255 - sunsetPercent*172};
|
|
nightSky = "";
|
|
shadows = true;
|
|
lightDirection = { "x": - x / normalize, "y": - y / normalize, "z": - z / normalize };
|
|
} else if (altitude > - startTwilight) {
|
|
// twilight
|
|
sunsetPercent = 1;
|
|
nightPercent = 1-Math.pow((((startTwilight)+altitude)/startTwilight),2);
|
|
sunColor = { "r": 255, "g": 255-(183*(1-nightPercent)), "b": 255 -(172*(1-nightPercent))};
|
|
skyColor = { "r": 0, "g": 0, "b": 0};
|
|
hazeColor = { "r": (255 - 2)*(1-nightPercent), "g": (255 - 183)*(1-nightPercent), "b": (255 - 172)*(1-nightPercent)};
|
|
nightSky = starMap;
|
|
shadows = false;
|
|
lightDirection = { "x": - x / normalize, "y": - y / normalize, "z": - z / normalize };
|
|
} else {
|
|
// night
|
|
sunsetPercent = 1;
|
|
nightPercent = 1;
|
|
sunColor = { "r": 255, "g": 255, "b": 255};
|
|
skyColor = { "r": 0, "g": 0, "b": 0};
|
|
nightSky = starMap;
|
|
shadows = false;
|
|
lightDirection = { "x": - x / normalize, "y": - y / normalize, "z": - z / normalize };
|
|
}
|
|
|
|
var sunID = Entities.findEntitiesByName("Sun", position, 1000, false)[0];
|
|
var sunlightID = Entities.findEntitiesByName("Sunlight", position, 1000, false)[0];
|
|
|
|
// print("sun: " + sunlight);
|
|
// print("sun: " + JSON.stringify(sunID));
|
|
//print("EntityID: " + entityID);
|
|
//print (JSON.stringify(Entities.getEntityProperties(sunID)));
|
|
|
|
var sunSize = 15 + (15 * Math.pow(sunsetPercent,3));
|
|
var result = Entities.editEntity(sunID, {
|
|
"localPosition": { "x": x, "y": y, "z": z },
|
|
"dimensions": {"x": sunSize, "y": sunSize, "z": sunSize},
|
|
"color": sunColor
|
|
});
|
|
Entities.editEntity(entityID, {
|
|
"skybox": {
|
|
"color": skyColor,
|
|
"url": nightSky
|
|
},
|
|
"keyLight": {
|
|
"color": sunColor,
|
|
"intensity": 1 - ((1-nightLight) * nightPercent),
|
|
"direction": lightDirection,
|
|
"castShadows": shadows
|
|
},
|
|
"haze": {
|
|
"hazeRange": 500,
|
|
"hazeColor": hazeColor,
|
|
"hazeEnableGlare": false,
|
|
"hazeGlareColor": "#ffffff",
|
|
"hazeGlareAngle": 20,
|
|
"hazeAltitudeEffect": true,
|
|
"hazeBaseRef": -100,
|
|
"hazeCeiling": (100+200*(sunsetPercent)+((sunsetPercent < 0.9) ? 0 : 300 * Math.pow((sunsetPercent - 0.9)/0.9,2)))*(1-nightPercent),
|
|
"hazeBackgroundBlend": 0.6 - (0.6 * sunsetPercent),
|
|
},
|
|
"bloom" : {
|
|
"bloomIntensity": 0.1 + (0.9 * Math.pow(sunsetPercent,3)),
|
|
"bloomThreshold": 1,
|
|
"bloomSize": -(0.05 + (9.95 * Math.pow(sunsetPercent,3)))
|
|
}
|
|
});
|
|
//print("result: " + result);
|
|
var distanceLight = 0.10;
|
|
Entities.editEntity(sunlightID, {
|
|
"localPosition": { "x": -(distanceLight * x), "y": -(distanceLight * y) , "z": -(distanceLight * z) },
|
|
"color": sunColor,
|
|
"intensity": 100000 // + (90000 * (1 - sunsetPercent))
|
|
});
|
|
// "#fd5e53"
|
|
}
|
|
// This is called every time a new object is created with this script
|
|
return new MyObject()
|
|
}) // Either use this or a return at the very end of the file.
|