UNPKG

babylonjs-godrays

Version:

Performant and lightweight god rays effect for BabylonJS based on geometry

245 lines (237 loc) 9.98 kB
import { Color3, Mesh, Vector3, VertexData, StandardMaterial } from 'babylonjs'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var raysNo = 0; var layersNo = 0; var godraysNo = 0; var defaultColors = [ Color3.FromHexString("#ffec23"), Color3.FromHexString("#ffb71b"), ]; var defaultConfig = { scale: 1.3, colors: defaultColors, minSpeed: 0.002, maxSpeed: 0.04, minAlpha: 0.1, maxAlpha: 0.4, density: 1, }; var minimizedScale = 0.01; var scaleDelta = 0.001; var Godrays = /** @class */ (function (_super) { __extends(Godrays, _super); function Godrays(scene) { var _this = _super.call(this, "godrays" + (godraysNo++), scene) || this; _this.layers = []; _this.rays = []; _this.aimScale = minimizedScale; _this.layersNumber = 5; _this.raysNumber = 6; _this.raysMinWidth = 0.01; _this.raysMaxWidth = 0.6; _this.raysMinLength = 5; _this.raysMaxLength = 15; _this.raysMinAlpha = 0.1; _this.raysMaxAlpha = 0.4; _this.density = 1; _this.minRotationSpeed = 0.002; _this.maxRotationSpeed = 0.04; _this.colors = defaultColors; _this.layersRotationSpeeds = []; _this.rotating = false; _this.scaling = new Vector3(minimizedScale, minimizedScale, minimizedScale); _this.colors = defaultColors; _this.rotateLayersAndInterpolateScale = _this.rotateLayersAndInterpolateScale.bind(_this); _this.setRaysScale = _this.setRaysScale.bind(_this); _this.createLayers(); _this.rotateLayersAndInterpolateScale(); return _this; } Godrays.prototype.start = function (config) { this.rotating = true; if (config) { this.setConfig(config); } this.aimScale = config && config.scale || 1; this.scaling = new Vector3(minimizedScale, minimizedScale, minimizedScale); }; Godrays.prototype.stop = function () { this.aimScale = minimizedScale; this.rotating = false; }; Godrays.prototype.setConfig = function (config) { this.setColors(config.colors); this.setRaysScale(config.scale); this.setSpeed(config.minSpeed, config.maxSpeed); this.setDensity(config.density); if (config.minAlpha && config.maxAlpha) { this.setAlpha(config.minAlpha, config.maxAlpha); } }; Godrays.prototype.setAlpha = function (minAlpha, maxAlpha) { var _this = this; this.raysMinAlpha = minAlpha; this.raysMaxAlpha = maxAlpha; this.rays.forEach(function (ray) { ray.visibility = getRandomFloat(_this.raysMinAlpha, _this.raysMaxAlpha); }); }; Godrays.prototype.setDensity = function (density) { this.density = density; this.rays.forEach(function (ray) { var shouldEnable = Math.random() < density; ray.setEnabled(shouldEnable); }); }; Godrays.prototype.setSpeed = function (minSpeed, maxSpeed) { var _this = this; this.minRotationSpeed = minSpeed; this.maxRotationSpeed = maxSpeed; this.layers.forEach(function (layer, idx) { return _this.layersRotationSpeeds[idx] = getRandomFloat(_this.minRotationSpeed, _this.maxRotationSpeed); }); }; Godrays.prototype.setRaysScale = function (scale) { this.aimScale = scale; this.scaling = new Vector3(scale, scale, scale); }; Godrays.prototype.setColors = function (colors) { var _this = this; this.colors = colors; this.rays.forEach(function (ray) { var positions = ray.getVerticesData('position'); var indices = ray.getIndices(); var vertexData = new VertexData(); vertexData.positions = positions; vertexData.indices = indices; var randomColor = _this.getRandomColor(); vertexData.colors = _this.getColorData(randomColor); vertexData.applyToMesh(ray); }); }; Godrays.prototype.createLayers = function () { for (var i = 0; i < this.layersNumber; i++) { var layer = this.createLayer(); this.layers.push(layer); layer.position.z = i * 0.01; layer.parent = this; this.layersRotationSpeeds[i] = getRandomFloat(-this.maxRotationSpeed, this.maxRotationSpeed); } }; Godrays.prototype.createLayer = function () { var layer = new Mesh("layer" + (layersNo++), this.getScene()); for (var i = 0; i < this.raysNumber; i++) { var centerWidth = getRandomFloat(this.raysMinWidth, this.raysMaxWidth); var edgesWidth = getRandomFloat(this.raysMinWidth, this.raysMaxWidth); var length_1 = getRandomFloat(this.raysMinLength, this.raysMaxLength); var ray = this.createRay(centerWidth, edgesWidth, length_1); ray.rotation.z = getRandomFloat(0, Math.PI * 2); ray.position.z = raysNo * 0.001; ray.visibility = getRandomFloat(this.raysMinAlpha, this.raysMaxAlpha); ray.parent = layer; } return layer; }; Godrays.prototype.rotateLayersAndInterpolateScale = function () { var _this = this; var currentScaling = this.scaling.x; if (currentScaling !== this.aimScale) { currentScaling += (this.aimScale - currentScaling) * 0.2; this.scaling = new Vector3(currentScaling, currentScaling, currentScaling); } var currentDelta = currentScaling - minimizedScale; if (currentDelta < scaleDelta && this.isEnabled()) { this.setEnabled(false); } else if (currentDelta > scaleDelta && !this.isEnabled()) { this.setEnabled(true); } if (this.rotating) { this.layers.forEach(function (layer, idx) { return layer.rotation.z += _this.layersRotationSpeeds[idx]; }); } requestAnimationFrame(this.rotateLayersAndInterpolateScale); }; Godrays.prototype.createRay = function (centerWidth, edgeWidth, length) { var ray = new Mesh("ray" + (raysNo++), this.getScene()); var halfCenterWidth = centerWidth / 2; var halfEdgeWidth = edgeWidth / 2; var halfLength = length / 2; var centerLPoint = [-halfCenterWidth, 0, 0]; var centerRPoint = [halfCenterWidth, 0, 0]; var edgeLTPoint = [-halfEdgeWidth, -halfLength, 0]; var edgeRTPoint = [halfEdgeWidth, -halfLength, 0]; var edgeLBPoint = [-halfEdgeWidth, halfLength, 0]; var edgeRBPoint = [halfEdgeWidth, halfLength, 0]; var positions = [].concat.apply([], [ centerLPoint, centerRPoint, edgeLTPoint, edgeRTPoint, edgeLBPoint, edgeRBPoint, ]); var indices = [2, 3, 1, 0, 2, 1, 5, 4, 0, 1, 5, 0]; var randomColor = this.getRandomColor(); var colors = this.getColorData(randomColor); var vertexData = new VertexData(); vertexData.positions = positions; vertexData.indices = indices; vertexData.colors = colors; vertexData.applyToMesh(ray); var mat = new StandardMaterial("mat", this.getScene()); // mat.alphaMode = Engine.ALPHA_ADD; mat.specularColor = randomColor; mat.ambientColor = randomColor; mat.emissiveColor = randomColor; mat.diffuseColor = randomColor; ray.material = mat; ray.hasVertexAlpha = true; this.rays.push(ray); return ray; }; Godrays.prototype.getRandomColor = function () { var randomColorIdx = getRandomInt(0, this.colors.length - 1); return this.colors[randomColorIdx]; }; Godrays.prototype.getColorData = function (color) { var randomColorRGB = [color.r, color.g, color.b]; var transparentColor = randomColorRGB.concat([0]); var colors = []; for (var i = 0; i < 6; i++) { colors = colors.concat(transparentColor); } // Making right vertices opaque colors[3] = 1; colors[7] = 1; return colors; }; return Godrays; }(Mesh)); function getRandomInt(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } function getRandomFloat(min, max) { return Math.random() * (max - min) + min; } export { defaultConfig, Godrays };