Particle sun rendering in computer graphics
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.
Code walkthrough
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!
Importing Babylon.js CDN files
<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 options
<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.
HTML canvas
<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".
Engine and scene creation
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.getElementByIdmethod. 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:sunEngineandcanvas. Inside this function, we use therunRenderLoopmethod provided bysunEngineto create a continuous rendering loop. Within the loop, we check ifsceneToRenderexists and if its active camera is set. If these conditions are met, we render the current scene usingsceneToRender.render().We declare three variables:
sunEngine,sunScene, andsceneToRenderwhich arenullat 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'sEngineclass and configure it accordingly.
Scene customization
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, usingsunEngineas the rendering engine.We create
ArcRotateCamerato control the camera's position and movement.The camera's controls are attached to the
canvasusingattachControlso that we can interact with the scene by dragging and zooming.We create a mesh
emitterto serve as the source for particle emission.Four particle systems are created for different visual effects
surfaceParticlesflareParticlescoronaParticlesstarsParticles
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 usingBABYLON.MeshBuilder.CreateSphereand represents the sun's core.The material of
coreSphereis defined usingBABYLON.StandardMaterialand configured to emit a color like the sun.Sphere emitters,
sunEmitterandstarsEmitter, 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
.emitteremitter type using
particleEmitterTypecolors using
BABYLON.COLORand.addColorGradientsizes using
minSize,maxSize,minScaleX,minScaleYand.addSizeGradientlifetimes using
.minLifeTimeand.maxLifeTimeemit rates using
.emitRateblending modes using
.blendModeangular speeds using
minAngularSpeedandmaxAngularSpeed
Next, the particle systems are started using
start()functions.Finally, our configured
sunSceneis returned.
Complete scene initialization
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. TheasyncEngineCreationfunction returns a default engine, the result of which is saved inwindow.sunEngine.We use the
startRenderLoop(sunEngine, canvas)function to begin the rendering loop. This function repeatedly renders the scene usingsunEngineand our HTML canvas elementcanvas.Then we call
createScene()to create the 3D scene. The result,sunScene, is assigned towindow.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.
Executable code
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
3D sun rendering demonstration
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!
Prewarmed sun code addition
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:
Applications of 3D sun visualization
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