mirror of
https://github.com/beestat/app.git
synced 2026-02-26 13:10:23 -05:00
284 lines
7.3 KiB
JavaScript
284 lines
7.3 KiB
JavaScript
/**
|
|
* Scene methods split from scene.js.
|
|
*/
|
|
|
|
|
|
/**
|
|
* Add a skybox background. Generated using Spacescape with the Unity export
|
|
* settings. After export: bottom is rotated CW 90°; top is roted 90°CCW.
|
|
*
|
|
* nx -> bk
|
|
* ny -> dn
|
|
* nz -> lf
|
|
* px -> ft
|
|
* py -> up
|
|
* pz -> rt
|
|
*
|
|
* @link https://www.mapcore.org/topic/24535-online-tools-to-convert-cubemaps-to-panoramas-and-vice-versa/
|
|
* @link https://jaxry.github.io/panorama-to-cubemap/
|
|
* @link http://alexcpeterson.com/spacescape/
|
|
*/
|
|
beestat.component.scene.prototype.add_skybox_ = function() {
|
|
const loader = new THREE.CubeTextureLoader();
|
|
loader.setPath('img/visualize/skybox/');
|
|
const texture = loader.load([
|
|
'front.png',
|
|
'back.png',
|
|
'up.png',
|
|
'down.png',
|
|
'right.png',
|
|
'left.png'
|
|
]);
|
|
this.scene_.background = texture;
|
|
};
|
|
|
|
|
|
/**
|
|
* Create a radial glow texture used for the sun halo sprite.
|
|
*
|
|
* @return {THREE.Texture}
|
|
*/
|
|
beestat.component.scene.prototype.create_sun_glow_texture_ = function() {
|
|
const size = 256;
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = size;
|
|
canvas.height = size;
|
|
|
|
const context = canvas.getContext('2d');
|
|
const gradient = context.createRadialGradient(
|
|
size / 2,
|
|
size / 2,
|
|
0,
|
|
size / 2,
|
|
size / 2,
|
|
size / 2
|
|
);
|
|
|
|
gradient.addColorStop(0.0, 'rgba(255, 255, 235, 1.0)');
|
|
gradient.addColorStop(0.25, 'rgba(255, 230, 150, 0.75)');
|
|
gradient.addColorStop(0.6, 'rgba(255, 170, 80, 0.25)');
|
|
gradient.addColorStop(1.0, 'rgba(255, 120, 50, 0.0)');
|
|
|
|
context.fillStyle = gradient;
|
|
context.fillRect(0, 0, size, size);
|
|
|
|
const texture = new THREE.CanvasTexture(canvas);
|
|
texture.needsUpdate = true;
|
|
|
|
return texture;
|
|
};
|
|
|
|
|
|
/**
|
|
* Create a soft star sprite texture.
|
|
*
|
|
* @return {THREE.Texture}
|
|
*/
|
|
beestat.component.scene.prototype.create_star_texture_ = function() {
|
|
const size = 64;
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = size;
|
|
canvas.height = size;
|
|
|
|
const context = canvas.getContext('2d');
|
|
const gradient = context.createRadialGradient(
|
|
size / 2,
|
|
size / 2,
|
|
0,
|
|
size / 2,
|
|
size / 2,
|
|
size / 2
|
|
);
|
|
gradient.addColorStop(0.0, 'rgba(255, 255, 255, 1)');
|
|
gradient.addColorStop(0.2, 'rgba(245, 250, 255, 0.95)');
|
|
gradient.addColorStop(0.65, 'rgba(210, 225, 255, 0.25)');
|
|
gradient.addColorStop(1.0, 'rgba(200, 220, 255, 0)');
|
|
|
|
context.fillStyle = gradient;
|
|
context.fillRect(0, 0, size, size);
|
|
|
|
const texture = new THREE.CanvasTexture(canvas);
|
|
texture.needsUpdate = true;
|
|
return texture;
|
|
};
|
|
|
|
|
|
/**
|
|
* Create a circular particle texture for snow.
|
|
*
|
|
* @return {THREE.Texture}
|
|
*/
|
|
beestat.component.scene.prototype.create_snow_particle_texture_ = function() {
|
|
const size = 64;
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = size;
|
|
canvas.height = size;
|
|
|
|
const context = canvas.getContext('2d');
|
|
const gradient = context.createRadialGradient(
|
|
size / 2,
|
|
size / 2,
|
|
0,
|
|
size / 2,
|
|
size / 2,
|
|
size / 2
|
|
);
|
|
gradient.addColorStop(0.0, 'rgba(255, 255, 255, 1.0)');
|
|
gradient.addColorStop(0.4, 'rgba(245, 250, 255, 0.9)');
|
|
gradient.addColorStop(1.0, 'rgba(240, 245, 255, 0.0)');
|
|
|
|
context.fillStyle = gradient;
|
|
context.fillRect(0, 0, size, size);
|
|
|
|
const texture = new THREE.CanvasTexture(canvas);
|
|
texture.needsUpdate = true;
|
|
|
|
return texture;
|
|
};
|
|
|
|
|
|
/**
|
|
* Create a soft circular particle texture for rain.
|
|
*
|
|
* @return {THREE.Texture}
|
|
*/
|
|
beestat.component.scene.prototype.create_rain_particle_texture_ = function() {
|
|
const width = 56;
|
|
const height = 56;
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
|
|
const context = canvas.getContext('2d');
|
|
const gradient = context.createRadialGradient(
|
|
width / 2,
|
|
height / 2,
|
|
0,
|
|
width / 2,
|
|
height / 2,
|
|
width * 0.5
|
|
);
|
|
gradient.addColorStop(0.0, 'rgba(195, 218, 255, 0.95)');
|
|
gradient.addColorStop(0.55, 'rgba(175, 205, 255, 0.55)');
|
|
gradient.addColorStop(1.0, 'rgba(165, 198, 255, 0.0)');
|
|
context.fillStyle = gradient;
|
|
context.fillRect(0, 0, width, height);
|
|
|
|
const texture = new THREE.CanvasTexture(canvas);
|
|
texture.needsUpdate = true;
|
|
|
|
return texture;
|
|
};
|
|
|
|
|
|
/**
|
|
* Create a soft cloud texture used for weather cloud sprites.
|
|
*
|
|
* @return {THREE.Texture}
|
|
*/
|
|
beestat.component.scene.prototype.create_cloud_texture_ = function() {
|
|
const size = 256;
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = size;
|
|
canvas.height = size;
|
|
const context = canvas.getContext('2d');
|
|
|
|
const circles = [
|
|
{'x': 0.36, 'y': 0.56, 'r': 0.2},
|
|
{'x': 0.5, 'y': 0.5, 'r': 0.24},
|
|
{'x': 0.64, 'y': 0.56, 'r': 0.2},
|
|
{'x': 0.5, 'y': 0.64, 'r': 0.22}
|
|
];
|
|
|
|
circles.forEach(function(circle) {
|
|
const gradient = context.createRadialGradient(
|
|
size * circle.x,
|
|
size * circle.y,
|
|
0,
|
|
size * circle.x,
|
|
size * circle.y,
|
|
size * circle.r
|
|
);
|
|
gradient.addColorStop(0.0, 'rgba(255,255,255,0.9)');
|
|
gradient.addColorStop(0.55, 'rgba(240,245,255,0.55)');
|
|
gradient.addColorStop(1.0, 'rgba(240,245,255,0.0)');
|
|
context.fillStyle = gradient;
|
|
context.beginPath();
|
|
context.arc(size * circle.x, size * circle.y, size * circle.r, 0, Math.PI * 2);
|
|
context.fill();
|
|
});
|
|
|
|
const texture = new THREE.CanvasTexture(canvas);
|
|
texture.needsUpdate = true;
|
|
return texture;
|
|
};
|
|
|
|
|
|
/**
|
|
* Draw the moon phase into the reusable moon canvas texture.
|
|
*
|
|
* @param {number} phase Moon phase from SunCalc (0=new, 0.25=first quarter,
|
|
* 0.5=full, 0.75=last quarter).
|
|
*/
|
|
beestat.component.scene.prototype.update_moon_phase_texture_ = function(phase) {
|
|
if (this.moon_phase_canvas_ === undefined) {
|
|
this.moon_phase_canvas_ = document.createElement('canvas');
|
|
this.moon_phase_canvas_.width = 256;
|
|
this.moon_phase_canvas_.height = 256;
|
|
this.moon_phase_texture_ = new THREE.CanvasTexture(this.moon_phase_canvas_);
|
|
}
|
|
|
|
const canvas = this.moon_phase_canvas_;
|
|
const context = canvas.getContext('2d');
|
|
const size = canvas.width;
|
|
const center = size / 2;
|
|
const radius = 110;
|
|
|
|
context.clearRect(0, 0, size, size);
|
|
|
|
// Base dark moon disk.
|
|
context.beginPath();
|
|
context.arc(center, center, radius, 0, Math.PI * 2);
|
|
context.fillStyle = '#2f3442';
|
|
context.fill();
|
|
|
|
// Lit region generated procedurally from phase (no image assets).
|
|
context.save();
|
|
context.beginPath();
|
|
context.arc(center, center, radius, 0, Math.PI * 2);
|
|
context.clip();
|
|
|
|
context.fillStyle = '#dde3ef';
|
|
const terminator = radius * Math.cos(2 * Math.PI * phase);
|
|
const waxing = phase <= 0.5;
|
|
for (let y = -radius; y <= radius; y++) {
|
|
const x_edge = Math.sqrt(Math.max(0, radius * radius - y * y));
|
|
// Curved terminator produces natural crescent/gibbous shapes.
|
|
const x_terminator = terminator * Math.sqrt(Math.max(0, 1 - (y * y) / (radius * radius)));
|
|
let x_start;
|
|
let x_end;
|
|
if (waxing) {
|
|
x_start = Math.max(-x_edge, x_terminator);
|
|
x_end = x_edge;
|
|
} else {
|
|
x_start = -x_edge;
|
|
x_end = Math.min(x_edge, -x_terminator);
|
|
}
|
|
|
|
if (x_end > x_start) {
|
|
context.fillRect(center + x_start, center + y, x_end - x_start, 1);
|
|
}
|
|
}
|
|
context.restore();
|
|
|
|
// Subtle rim to keep the disk readable on the skybox.
|
|
context.beginPath();
|
|
context.arc(center, center, radius, 0, Math.PI * 2);
|
|
context.strokeStyle = 'rgba(255, 255, 255, 0.2)';
|
|
context.lineWidth = 2;
|
|
context.stroke();
|
|
|
|
this.moon_phase_texture_.needsUpdate = true;
|
|
};
|
|
|