babylonjs-godrays
Version:
Performant and lightweight god rays effect for BabylonJS based on geometry
245 lines (237 loc) • 9.98 kB
JavaScript
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 };