Babylon.js is Javascript's open-source framework that allows us to build interactive 3D experiences on the web. Having such features makes it a potential library for rendering 3D objects in space.
In this Answer, we will use Babylon.js to create a fascinating 3D rendering of the sun by employing advanced features like particle systems and visualizing various effects, surface textures, flares, and corona particles.
Note: Particle systems in Babylon.js are dynamic visual effects that we can use simulate lots of small elements within a scene. For instance, fire, smoke, rain, etc.
We will go through the code in chunks and understand how various components come together to render a sun in three dimensions using Babylon.js. Let's get started!
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script><script src="https://assets.babylonjs.com/generated/Assets.js"></script><script src="https://cdn.babylonjs.com/recast.js"></script><script src="https://cdn.babylonjs.com/ammo.js"></script><script src="https://cdn.babylonjs.com/havok/HavokPhysics_umd.js"></script><script src="https://cdn.babylonjs.com/cannon.js"></script><script src="https://cdn.babylonjs.com/Oimo.js"></script><script src="https://cdn.babylonjs.com/earcut.min.js"></script><script src="https://cdn.babylonjs.com/babylon.js"></script><script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script><script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script><script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script><script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script><script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script><script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script><script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
In this section, we import external libraries and dependencies required for Babylon.js and its 3D visualizations.
<style>html, body {overflow: hidden;width: 100%;height: 100%;margin: 0;padding: 0;}#canvasClass {width: 100%;height: 100%;touch-action: none;}#canvasArea {width: 100%;height: 100%;}</style>
We define our style <style>
properties to control the appearance of the HTML and body elements. This is mainly done to see the sun's visualization in full screen.
<div id="canvasArea"><canvas id="canvasClass"></canvas></div>
This canvas will serve as the rendering surface for the 3D scene. We give it the ID of "canvasClass".
var canvas = document.getElementById("canvasClass");var startRenderLoop = function(sunEngine, canvas) {sunEngine.runRenderLoop(function() {if (sceneToRender && sceneToRender.activeCamera) {sceneToRender.render();}});}var sunEngine = null;var sunScene = null;var sceneToRender = null;var createDefaultEngine = function() {return new BABYLON.Engine(canvas, true, {preserveDrawingBuffer: true,stencil: true,disableWebGL2Support: false});};
Here, we retrieve the HTML element with the ID "canvasClass" using the document.getElementById
method. This element will serve as our rendering canvas, where the 3D scene will be displayed.
We define a function called startRenderLoop
, which takes two parameters: sunEngine
and canvas
. Inside this function, we use the runRenderLoop
method provided by sunEngine
to create a continuous rendering loop. Within the loop, we check if sceneToRender
exists and if its active camera is set. If these conditions are met, we render the current scene using sceneToRender.render()
.
We declare three variables: sunEngine
, sunScene
, and sceneToRender
which are null
at the start. These variables will be used to manage both the scene and the engine behind it.
We define a function called createDefaultEngine
, where we create a new instance of Babylon's Engine
class and configure it accordingly.
var createScene = function() {var sunScene = new BABYLON.Scene(sunEngine);var camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1, 0.8, 5, new BABYLON.Vector3(0, 0, 0), sunScene);camera.attachControl(canvas, true);sunScene.clearColor = new BABYLON.Color3(0.0, 0.0, 0.0);var stars = BABYLON.Mesh.CreateBox("emitter", 1, sunScene);var surfaceParticles = new BABYLON.ParticleSystem("surfaceParticles", 1600, sunScene);var flareParticles = new BABYLON.ParticleSystem("flareParticles", 20, sunScene);var coronaParticles = new BABYLON.ParticleSystem("coronaParticles", 600, sunScene);var starsParticles = new BABYLON.ParticleSystem("starsParticles", 500, sunScene);surfaceParticles.particleTexture = new BABYLON.Texture("https://raw.githubusercontent.com/PatrickRyanMS/BabylonJStextures/master/ParticleSystems/Sun/T_SunSurface.png", sunScene);flareParticles.particleTexture = new BABYLON.Texture("https://raw.githubusercontent.com/PatrickRyanMS/BabylonJStextures/master/ParticleSystems/Sun/T_SunFlare.png", sunScene);coronaParticles.particleTexture = new BABYLON.Texture("https://raw.githubusercontent.com/PatrickRyanMS/BabylonJStextures/master/ParticleSystems/Sun/T_Star.png", sunScene);starsParticles.particleTexture = new BABYLON.Texture("https://raw.githubusercontent.com/PatrickRyanMS/BabylonJStextures/master/ParticleSystems/Sun/T_Star.png", sunScene);var coreSphere = BABYLON.MeshBuilder.CreateSphere("coreSphere", {diameter: 2.01,segments: 64}, sunScene);var coreMat = new BABYLON.StandardMaterial("coreMat", sunScene)coreMat.emissiveColor = new BABYLON.Color3(0.3773, 0.0930, 0.0266);coreSphere.material = coreMat;var sunEmitter = new BABYLON.SphereParticleEmitter();sunEmitter.radius = 1;sunEmitter.radiusRange = 0;var starsEmitter = new BABYLON.SphereParticleEmitter();starsEmitter.radius = 20;starsEmitter.radiusRange = 0;surfaceParticles.emitter = coreSphere;surfaceParticles.particleEmitterType = sunEmitter;flareParticles.emitter = coreSphere;flareParticles.particleEmitterType = sunEmitter;coronaParticles.emitter = coreSphere;coronaParticles.particleEmitterType = sunEmitter;starsParticles.emitter = stars;starsParticles.particleEmitterType = starsEmitter;starsParticles.color1 = new BABYLON.Color4(0.898, 0.737, 0.718, 1.0);starsParticles.color2 = new BABYLON.Color4(0.584, 0.831, 0.894, 1.0);surfaceParticles.addColorGradient(0, new BABYLON.Color4(0.8509, 0.4784, 0.1019, 0.0));surfaceParticles.addColorGradient(0.4, new BABYLON.Color4(0.6259, 0.3056, 0.0619, 0.5));surfaceParticles.addColorGradient(0.5, new BABYLON.Color4(0.6039, 0.2887, 0.0579, 0.5));surfaceParticles.addColorGradient(1.0, new BABYLON.Color4(0.3207, 0.0713, 0.0075, 0.0));flareParticles.addColorGradient(0, new BABYLON.Color4(1, 0.9612, 0.5141, 0.0));flareParticles.addColorGradient(0.25, new BABYLON.Color4(0.9058, 0.7152, 0.3825, 1.0));flareParticles.addColorGradient(1.0, new BABYLON.Color4(0.6320, 0.0, 0.0, 0.0));coronaParticles.addColorGradient(0, new BABYLON.Color4(0.8509, 0.4784, 0.1019, 0.0));coronaParticles.addColorGradient(0.5, new BABYLON.Color4(0.6039, 0.2887, 0.0579, 0.12));coronaParticles.addColorGradient(1.0, new BABYLON.Color4(0.3207, 0.0713, 0.0075, 0.0));surfaceParticles.minSize = 0.3;surfaceParticles.maxSize = 0.8;flareParticles.minScaleX = 0.3;flareParticles.minScaleY = 0.6;flareParticles.maxScaleX = 1;flareParticles.maxScaleY = 1;coronaParticles.minScaleX = 0.3;coronaParticles.minScaleY = 0.8;coronaParticles.maxScaleX = 1.5;coronaParticles.maxScaleY = 2.5;starsParticles.minSize = 0.1;starsParticles.maxSize = 0.35;flareParticles.addSizeGradient(0, 0);flareParticles.addSizeGradient(1, 1);surfaceParticles.minLifeTime = 7;surfaceParticles.maxLifeTime = 7;flareParticles.minLifeTime = 10;flareParticles.maxLifeTime = 10;coronaParticles.minLifeTime = 3;coronaParticles.maxLifeTime = 3;starsParticles.minLifeTime = 1000000;starsParticles.maxLifeTime = 1000000;surfaceParticles.emitRate = 250;flareParticles.emitRate = 2;coronaParticles.emitRate = 250;starsParticles.manualEmitCount = 1000;starsParticles.maxEmitPower = 0;surfaceParticles.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;flareParticles.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;coronaParticles.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD;starsParticles.blendMode = BABYLON.ParticleSystem.BLENDMODE_STANDARD;surfaceParticles.minAngularSpeed = -0.4;surfaceParticles.maxAngularSpeed = 0.4;flareParticles.minAngularSpeed = 0.0;flareParticles.maxAngularSpeed = 0.0;coronaParticles.minAngularSpeed = 0.0;coronaParticles.maxAngularSpeed = 0.0;starsParticles.minAngularSpeed = 0.0;starsParticles.maxAngularSpeed = 0.0;surfaceParticles.minEmitPower = 0;surfaceParticles.maxEmitPower = 0;surfaceParticles.updateSpeed = 0.005;flareParticles.minEmitPower = 0.001;flareParticles.maxEmitPower = 0.01;coronaParticles.minEmitPower = 0.0;coronaParticles.maxEmitPower = 0.0;starsParticles.minEmitPower = 0.0;starsParticles.maxAngularSpeed = 0.0;surfaceParticles.isBillboardBased = false;flareParticles.isBillboardBased = true;coronaParticles.isBillboardBased = true;starsParticles.isBillboardBased = true;starsParticles.start();surfaceParticles.start();flareParticles.start();coronaParticles.start();return sunScene;}
This is the code where the 3D sun is actually configured, and the scene is returned. Let's go through it in detail.
We start by creating a new Babylon.js scene called sunScene
, using sunEngine
as the rendering engine.
We create ArcRotateCamera
to control the camera's position and movement.
The camera's controls are attached to the canvas
using attachControl
so that we can interact with the scene by dragging and zooming.
We create a mesh emitter
to serve as the source for particle emission.
Four particle systems are created for different visual effects
surfaceParticles
flareParticles
coronaParticles
starsParticles
Each particle system is then assigned a particle texture to depict close to accurate phenomenons.
We now create the sun! A spherical mesh, coreSphere
, is generated using BABYLON.MeshBuilder.CreateSphere
and represents the sun's core.
The material of coreSphere
is defined using BABYLON.StandardMaterial
and configured to emit a color like the sun.
Sphere emitters, sunEmitter
and starsEmitter
, are set up for the particle systems. These emitters determine where particles originate.
This is where most of the customizations reside as particle properties and behavior are configured:
emitter assignment using .emitter
emitter type using particleEmitterType
colors using BABYLON.COLOR
and .addColorGradient
sizes using minSize
, maxSize
, minScaleX
, minScaleY
and .addSizeGradient
lifetimes using .minLifeTime
and .maxLifeTime
emit rates using .emitRate
blending modes using .blendMode
angular speeds using minAngularSpeed
and maxAngularSpeed
Next, the particle systems are started using start()
functions.
Finally, our configured sunScene
is returned.
window.initFunction = async function() {var asyncEngineCreation = async function() {return createDefaultEngine();}window.sunEngine = await asyncEngineCreation();startRenderLoop(sunEngine, canvas);window.sunScene = createScene();};initFunction().then(() => {sceneToRender = sunScene});window.addEventListener("resize", function() {sunEngine.resize();});
We start by defining a function named initFunction
, which will handle the initialization of our rendering environment. The asyncEngineCreation
function returns a default engine, the result of which is saved in window.sunEngine
.
We use the startRenderLoop(sunEngine, canvas)
function to begin the rendering loop. This function repeatedly renders the scene using sunEngine
and our HTML canvas element canvas
.
Then we call createScene()
to create the 3D scene. The result, sunScene
, is assigned to window.sunScene
.
We initiate the scene rendering and set the rendered scene to sceneToRender
. We also ensure the rendering engine is resized if the window dimensions change.
Congratulations, we're done with the code! It all comes together to form this final executable HTML file. Feel free to experiment with it and click "Run" once done.
Note: Since we are importing
files, please ensure that you're connected to the internet when running this HTML file. CDN distributed group of servers
How our sun is customized makes it start rendering from a simple red circle depicting a sun. It starts warming up and reaches its final hot state a few seconds after the code executes.
Interact with the output below and enjoy the realistic rendering!
To render a sun that is already hot, we can add the code below. preWarmStepOffset
and preWarmCycles
have to be defined accordingly.
surfaceParticles.preWarmStepOffset = 10;surfaceParticles.preWarmCycles = 100;flareParticles.preWarmStepOffset = 10;flareParticles.preWarmCycles = 100;coronaParticles.preWarmStepOffset = 10;coronaParticles.preWarmCycles = 100;
The output looks like the following:
Such visualizations can be employed in various applications in the real world, as the following table represents.
Real world applications |
Astronomy related interactive learning |
Virtual planetariums or science centers |
Scientific research |
Space simulations |
Art visualizations |
How well do you know 3D sun visualization in Babylon.js?
To change the speed of the sun’s flares, what property do we configure?
minFlareSpeed
and maxFlareSpeed
minAngularSpeed
and maxAngularSpeed
minRotationSpeed
and maxRotationSpeed
Free Resources