You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					569 lines
				
				14 KiB
			
		
		
			
		
	
	
					569 lines
				
				14 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								<!DOCTYPE html>
							 | 
						||
| 
								 | 
							
								<html lang="en">
							 | 
						||
| 
								 | 
							
									<head>
							 | 
						||
| 
								 | 
							
										<title>three.js webgl - gpgpu - protoplanet</title>
							 | 
						||
| 
								 | 
							
										<meta charset="utf-8">
							 | 
						||
| 
								 | 
							
										<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
							 | 
						||
| 
								 | 
							
										<link type="text/css" rel="stylesheet" href="main.css">
							 | 
						||
| 
								 | 
							
									</head>
							 | 
						||
| 
								 | 
							
									<body>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<div id="info">
							 | 
						||
| 
								 | 
							
											<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - <span id="protoplanets"></span> webgl gpgpu debris
							 | 
						||
| 
								 | 
							
										</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<!-- Fragment shader for protoplanet's position -->
							 | 
						||
| 
								 | 
							
										<script id="computeShaderPosition" type="x-shader/x-fragment">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											#define delta ( 1.0 / 60.0 )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											void main() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec2 uv = gl_FragCoord.xy / resolution.xy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 tmpPos = texture2D( texturePosition, uv );
							 | 
						||
| 
								 | 
							
												vec3 pos = tmpPos.xyz;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 tmpVel = texture2D( textureVelocity, uv );
							 | 
						||
| 
								 | 
							
												vec3 vel = tmpVel.xyz;
							 | 
						||
| 
								 | 
							
												float mass = tmpVel.w;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( mass == 0.0 ) {
							 | 
						||
| 
								 | 
							
													vel = vec3( 0.0 );
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												// Dynamics
							 | 
						||
| 
								 | 
							
												pos += vel * delta;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gl_FragColor = vec4( pos, 1.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										</script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<!-- Fragment shader for protoplanet's velocity -->
							 | 
						||
| 
								 | 
							
										<script id="computeShaderVelocity" type="x-shader/x-fragment">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// For PI declaration:
							 | 
						||
| 
								 | 
							
											#include <common>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											#define delta ( 1.0 / 60.0 )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniform float gravityConstant;
							 | 
						||
| 
								 | 
							
											uniform float density;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const float width = resolution.x;
							 | 
						||
| 
								 | 
							
											const float height = resolution.y;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											float radiusFromMass( float mass ) {
							 | 
						||
| 
								 | 
							
												// Calculate radius of a sphere from mass and density
							 | 
						||
| 
								 | 
							
												return pow( ( 3.0 / ( 4.0 * PI ) ) * mass / density, 1.0 / 3.0 );
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											void main()	{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec2 uv = gl_FragCoord.xy / resolution.xy;
							 | 
						||
| 
								 | 
							
												float idParticle = uv.y * resolution.x + uv.x;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 tmpPos = texture2D( texturePosition, uv );
							 | 
						||
| 
								 | 
							
												vec3 pos = tmpPos.xyz;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 tmpVel = texture2D( textureVelocity, uv );
							 | 
						||
| 
								 | 
							
												vec3 vel = tmpVel.xyz;
							 | 
						||
| 
								 | 
							
												float mass = tmpVel.w;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( mass > 0.0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													float radius = radiusFromMass( mass );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													vec3 acceleration = vec3( 0.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Gravity interaction
							 | 
						||
| 
								 | 
							
													for ( float y = 0.0; y < height; y++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														for ( float x = 0.0; x < width; x++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															vec2 secondParticleCoords = vec2( x + 0.5, y + 0.5 ) / resolution.xy;
							 | 
						||
| 
								 | 
							
															vec3 pos2 = texture2D( texturePosition, secondParticleCoords ).xyz;
							 | 
						||
| 
								 | 
							
															vec4 velTemp2 = texture2D( textureVelocity, secondParticleCoords );
							 | 
						||
| 
								 | 
							
															vec3 vel2 = velTemp2.xyz;
							 | 
						||
| 
								 | 
							
															float mass2 = velTemp2.w;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															float idParticle2 = secondParticleCoords.y * resolution.x + secondParticleCoords.x;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															if ( idParticle == idParticle2 ) {
							 | 
						||
| 
								 | 
							
																continue;
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															if ( mass2 == 0.0 ) {
							 | 
						||
| 
								 | 
							
																continue;
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															vec3 dPos = pos2 - pos;
							 | 
						||
| 
								 | 
							
															float distance = length( dPos );
							 | 
						||
| 
								 | 
							
															float radius2 = radiusFromMass( mass2 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															if ( distance == 0.0 ) {
							 | 
						||
| 
								 | 
							
																continue;
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															// Checks collision
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															if ( distance < radius + radius2 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
																if ( idParticle < idParticle2 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
																	// This particle is aggregated by the other
							 | 
						||
| 
								 | 
							
																	vel = ( vel * mass + vel2 * mass2 ) / ( mass + mass2 );
							 | 
						||
| 
								 | 
							
																	mass += mass2;
							 | 
						||
| 
								 | 
							
																	radius = radiusFromMass( mass );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
																}
							 | 
						||
| 
								 | 
							
																else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
																	// This particle dies
							 | 
						||
| 
								 | 
							
																	mass = 0.0;
							 | 
						||
| 
								 | 
							
																	radius = 0.0;
							 | 
						||
| 
								 | 
							
																	vel = vec3( 0.0 );
							 | 
						||
| 
								 | 
							
																	break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
																}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															float distanceSq = distance * distance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															float gravityField = gravityConstant * mass2 / distanceSq;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															gravityField = min( gravityField, 1000.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															acceleration += gravityField * normalize( dPos );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														if ( mass == 0.0 ) {
							 | 
						||
| 
								 | 
							
															break;
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Dynamics
							 | 
						||
| 
								 | 
							
													vel += delta * acceleration;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gl_FragColor = vec4( vel, mass );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										</script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<!-- Particles vertex shader -->
							 | 
						||
| 
								 | 
							
										<script type="x-shader/x-vertex" id="particleVertexShader">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// For PI declaration:
							 | 
						||
| 
								 | 
							
											#include <common>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniform sampler2D texturePosition;
							 | 
						||
| 
								 | 
							
											uniform sampler2D textureVelocity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniform float cameraConstant;
							 | 
						||
| 
								 | 
							
											uniform float density;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											varying vec4 vColor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											float radiusFromMass( float mass ) {
							 | 
						||
| 
								 | 
							
												// Calculate radius of a sphere from mass and density
							 | 
						||
| 
								 | 
							
												return pow( ( 3.0 / ( 4.0 * PI ) ) * mass / density, 1.0 / 3.0 );
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											void main() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 posTemp = texture2D( texturePosition, uv );
							 | 
						||
| 
								 | 
							
												vec3 pos = posTemp.xyz;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 velTemp = texture2D( textureVelocity, uv );
							 | 
						||
| 
								 | 
							
												vec3 vel = velTemp.xyz;
							 | 
						||
| 
								 | 
							
												float mass = velTemp.w;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vColor = vec4( 1.0, mass / 250.0, 0.0, 1.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												vec4 mvPosition = modelViewMatrix * vec4( pos, 1.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												// Calculate radius of a sphere from mass and density
							 | 
						||
| 
								 | 
							
												//float radius = pow( ( 3.0 / ( 4.0 * PI ) ) * mass / density, 1.0 / 3.0 );
							 | 
						||
| 
								 | 
							
												float radius = radiusFromMass( mass );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												// Apparent size in pixels
							 | 
						||
| 
								 | 
							
												if ( mass == 0.0 ) {
							 | 
						||
| 
								 | 
							
													gl_PointSize = 0.0;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												else {
							 | 
						||
| 
								 | 
							
													gl_PointSize = radius * cameraConstant / ( - mvPosition.z );
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gl_Position = projectionMatrix * mvPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										</script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<!-- Particles fragment shader -->
							 | 
						||
| 
								 | 
							
										<script type="x-shader/x-fragment" id="particleFragmentShader">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											varying vec4 vColor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											void main() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( vColor.y == 0.0 ) discard;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												float f = length( gl_PointCoord - vec2( 0.5, 0.5 ) );
							 | 
						||
| 
								 | 
							
												if ( f > 0.5 ) {
							 | 
						||
| 
								 | 
							
													discard;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												gl_FragColor = vColor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										</script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<!-- Import maps polyfill -->
							 | 
						||
| 
								 | 
							
										<!-- Remove this when import maps will be widely supported -->
							 | 
						||
| 
								 | 
							
										<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<script type="importmap">
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												"imports": {
							 | 
						||
| 
								 | 
							
													"three": "../build/three.module.js",
							 | 
						||
| 
								 | 
							
													"three/addons/": "./jsm/"
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										</script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										<script type="module">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											import * as THREE from 'three';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											import Stats from 'three/addons/libs/stats.module.js';
							 | 
						||
| 
								 | 
							
											import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
							 | 
						||
| 
								 | 
							
											import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Texture width for simulation (each texel is a debris particle)
							 | 
						||
| 
								 | 
							
											const WIDTH = 64;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let container, stats;
							 | 
						||
| 
								 | 
							
											let camera, scene, renderer, geometry;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const PARTICLES = WIDTH * WIDTH;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let gpuCompute;
							 | 
						||
| 
								 | 
							
											let velocityVariable;
							 | 
						||
| 
								 | 
							
											let positionVariable;
							 | 
						||
| 
								 | 
							
											let velocityUniforms;
							 | 
						||
| 
								 | 
							
											let particleUniforms;
							 | 
						||
| 
								 | 
							
											let effectController;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											init();
							 | 
						||
| 
								 | 
							
											animate();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function init() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												container = document.createElement( 'div' );
							 | 
						||
| 
								 | 
							
												document.body.appendChild( container );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 5, 15000 );
							 | 
						||
| 
								 | 
							
												camera.position.y = 120;
							 | 
						||
| 
								 | 
							
												camera.position.z = 400;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												scene = new THREE.Scene();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												renderer = new THREE.WebGLRenderer();
							 | 
						||
| 
								 | 
							
												renderer.setPixelRatio( window.devicePixelRatio );
							 | 
						||
| 
								 | 
							
												renderer.setSize( window.innerWidth, window.innerHeight );
							 | 
						||
| 
								 | 
							
												container.appendChild( renderer.domElement );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const controls = new OrbitControls( camera, renderer.domElement );
							 | 
						||
| 
								 | 
							
												controls.minDistance = 100;
							 | 
						||
| 
								 | 
							
												controls.maxDistance = 1000;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												effectController = {
							 | 
						||
| 
								 | 
							
													// Can be changed dynamically
							 | 
						||
| 
								 | 
							
													gravityConstant: 100.0,
							 | 
						||
| 
								 | 
							
													density: 0.45,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Must restart simulation
							 | 
						||
| 
								 | 
							
													radius: 300,
							 | 
						||
| 
								 | 
							
													height: 8,
							 | 
						||
| 
								 | 
							
													exponent: 0.4,
							 | 
						||
| 
								 | 
							
													maxMass: 15.0,
							 | 
						||
| 
								 | 
							
													velocity: 70,
							 | 
						||
| 
								 | 
							
													velocityExponent: 0.2,
							 | 
						||
| 
								 | 
							
													randVelocity: 0.001
							 | 
						||
| 
								 | 
							
												};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												initComputeRenderer();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												stats = new Stats();
							 | 
						||
| 
								 | 
							
												container.appendChild( stats.dom );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												window.addEventListener( 'resize', onWindowResize );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												initGUI();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												initProtoplanets();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												dynamicValuesChanger();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function initComputeRenderer() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gpuCompute = new GPUComputationRenderer( WIDTH, WIDTH, renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( renderer.capabilities.isWebGL2 === false ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													gpuCompute.setDataType( THREE.HalfFloatType );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const dtPosition = gpuCompute.createTexture();
							 | 
						||
| 
								 | 
							
												const dtVelocity = gpuCompute.createTexture();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												fillTextures( dtPosition, dtVelocity );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												velocityVariable = gpuCompute.addVariable( 'textureVelocity', document.getElementById( 'computeShaderVelocity' ).textContent, dtVelocity );
							 | 
						||
| 
								 | 
							
												positionVariable = gpuCompute.addVariable( 'texturePosition', document.getElementById( 'computeShaderPosition' ).textContent, dtPosition );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gpuCompute.setVariableDependencies( velocityVariable, [ positionVariable, velocityVariable ] );
							 | 
						||
| 
								 | 
							
												gpuCompute.setVariableDependencies( positionVariable, [ positionVariable, velocityVariable ] );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												velocityUniforms = velocityVariable.material.uniforms;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												velocityUniforms[ 'gravityConstant' ] = { value: 0.0 };
							 | 
						||
| 
								 | 
							
												velocityUniforms[ 'density' ] = { value: 0.0 };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const error = gpuCompute.init();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( error !== null ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													console.error( error );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function restartSimulation() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const dtPosition = gpuCompute.createTexture();
							 | 
						||
| 
								 | 
							
												const dtVelocity = gpuCompute.createTexture();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												fillTextures( dtPosition, dtVelocity );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gpuCompute.renderTexture( dtPosition, positionVariable.renderTargets[ 0 ] );
							 | 
						||
| 
								 | 
							
												gpuCompute.renderTexture( dtPosition, positionVariable.renderTargets[ 1 ] );
							 | 
						||
| 
								 | 
							
												gpuCompute.renderTexture( dtVelocity, velocityVariable.renderTargets[ 0 ] );
							 | 
						||
| 
								 | 
							
												gpuCompute.renderTexture( dtVelocity, velocityVariable.renderTargets[ 1 ] );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function initProtoplanets() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												geometry = new THREE.BufferGeometry();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const positions = new Float32Array( PARTICLES * 3 );
							 | 
						||
| 
								 | 
							
												let p = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for ( let i = 0; i < PARTICLES; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													positions[ p ++ ] = ( Math.random() * 2 - 1 ) * effectController.radius;
							 | 
						||
| 
								 | 
							
													positions[ p ++ ] = 0; //( Math.random() * 2 - 1 ) * effectController.radius;
							 | 
						||
| 
								 | 
							
													positions[ p ++ ] = ( Math.random() * 2 - 1 ) * effectController.radius;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const uvs = new Float32Array( PARTICLES * 2 );
							 | 
						||
| 
								 | 
							
												p = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for ( let j = 0; j < WIDTH; j ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													for ( let i = 0; i < WIDTH; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														uvs[ p ++ ] = i / ( WIDTH - 1 );
							 | 
						||
| 
								 | 
							
														uvs[ p ++ ] = j / ( WIDTH - 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
							 | 
						||
| 
								 | 
							
												geometry.setAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												particleUniforms = {
							 | 
						||
| 
								 | 
							
													'texturePosition': { value: null },
							 | 
						||
| 
								 | 
							
													'textureVelocity': { value: null },
							 | 
						||
| 
								 | 
							
													'cameraConstant': { value: getCameraConstant( camera ) },
							 | 
						||
| 
								 | 
							
													'density': { value: 0.0 }
							 | 
						||
| 
								 | 
							
												};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												// THREE.ShaderMaterial
							 | 
						||
| 
								 | 
							
												const material = new THREE.ShaderMaterial( {
							 | 
						||
| 
								 | 
							
													uniforms: particleUniforms,
							 | 
						||
| 
								 | 
							
													vertexShader: document.getElementById( 'particleVertexShader' ).textContent,
							 | 
						||
| 
								 | 
							
													fragmentShader: document.getElementById( 'particleFragmentShader' ).textContent
							 | 
						||
| 
								 | 
							
												} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												material.extensions.drawBuffers = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const particles = new THREE.Points( geometry, material );
							 | 
						||
| 
								 | 
							
												particles.matrixAutoUpdate = false;
							 | 
						||
| 
								 | 
							
												particles.updateMatrix();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												scene.add( particles );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function fillTextures( texturePosition, textureVelocity ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const posArray = texturePosition.image.data;
							 | 
						||
| 
								 | 
							
												const velArray = textureVelocity.image.data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const radius = effectController.radius;
							 | 
						||
| 
								 | 
							
												const height = effectController.height;
							 | 
						||
| 
								 | 
							
												const exponent = effectController.exponent;
							 | 
						||
| 
								 | 
							
												const maxMass = effectController.maxMass * 1024 / PARTICLES;
							 | 
						||
| 
								 | 
							
												const maxVel = effectController.velocity;
							 | 
						||
| 
								 | 
							
												const velExponent = effectController.velocityExponent;
							 | 
						||
| 
								 | 
							
												const randVel = effectController.randVelocity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for ( let k = 0, kl = posArray.length; k < kl; k += 4 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Position
							 | 
						||
| 
								 | 
							
													let x, z, rr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													do {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														x = ( Math.random() * 2 - 1 );
							 | 
						||
| 
								 | 
							
														z = ( Math.random() * 2 - 1 );
							 | 
						||
| 
								 | 
							
														rr = x * x + z * z;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													} while ( rr > 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													rr = Math.sqrt( rr );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const rExp = radius * Math.pow( rr, exponent );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Velocity
							 | 
						||
| 
								 | 
							
													const vel = maxVel * Math.pow( rr, velExponent );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const vx = vel * z + ( Math.random() * 2 - 1 ) * randVel;
							 | 
						||
| 
								 | 
							
													const vy = ( Math.random() * 2 - 1 ) * randVel * 0.05;
							 | 
						||
| 
								 | 
							
													const vz = - vel * x + ( Math.random() * 2 - 1 ) * randVel;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													x *= rExp;
							 | 
						||
| 
								 | 
							
													z *= rExp;
							 | 
						||
| 
								 | 
							
													const y = ( Math.random() * 2 - 1 ) * height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const mass = Math.random() * maxMass + 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Fill in texture values
							 | 
						||
| 
								 | 
							
													posArray[ k + 0 ] = x;
							 | 
						||
| 
								 | 
							
													posArray[ k + 1 ] = y;
							 | 
						||
| 
								 | 
							
													posArray[ k + 2 ] = z;
							 | 
						||
| 
								 | 
							
													posArray[ k + 3 ] = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													velArray[ k + 0 ] = vx;
							 | 
						||
| 
								 | 
							
													velArray[ k + 1 ] = vy;
							 | 
						||
| 
								 | 
							
													velArray[ k + 2 ] = vz;
							 | 
						||
| 
								 | 
							
													velArray[ k + 3 ] = mass;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function onWindowResize() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												camera.aspect = window.innerWidth / window.innerHeight;
							 | 
						||
| 
								 | 
							
												camera.updateProjectionMatrix();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												renderer.setSize( window.innerWidth, window.innerHeight );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												particleUniforms[ 'cameraConstant' ].value = getCameraConstant( camera );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function dynamicValuesChanger() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												velocityUniforms[ 'gravityConstant' ].value = effectController.gravityConstant;
							 | 
						||
| 
								 | 
							
												velocityUniforms[ 'density' ].value = effectController.density;
							 | 
						||
| 
								 | 
							
												particleUniforms[ 'density' ].value = effectController.density;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function initGUI() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const gui = new GUI( { width: 280 } );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const folder1 = gui.addFolder( 'Dynamic parameters' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												folder1.add( effectController, 'gravityConstant', 0.0, 1000.0, 0.05 ).onChange( dynamicValuesChanger );
							 | 
						||
| 
								 | 
							
												folder1.add( effectController, 'density', 0.0, 10.0, 0.001 ).onChange( dynamicValuesChanger );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const folder2 = gui.addFolder( 'Static parameters' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'radius', 10.0, 1000.0, 1.0 );
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'height', 0.0, 50.0, 0.01 );
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'exponent', 0.0, 2.0, 0.001 );
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'maxMass', 1.0, 50.0, 0.1 );
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'velocity', 0.0, 150.0, 0.1 );
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'velocityExponent', 0.0, 1.0, 0.01 );
							 | 
						||
| 
								 | 
							
												folder2.add( effectController, 'randVelocity', 0.0, 50.0, 0.1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const buttonRestart = {
							 | 
						||
| 
								 | 
							
													restartSimulation: function () {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														restartSimulation();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												folder2.add( buttonRestart, 'restartSimulation' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												folder1.open();
							 | 
						||
| 
								 | 
							
												folder2.open();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function getCameraConstant( camera ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												return window.innerHeight / ( Math.tan( THREE.MathUtils.DEG2RAD * 0.5 * camera.fov ) / camera.zoom );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function animate() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												requestAnimationFrame( animate );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												render();
							 | 
						||
| 
								 | 
							
												stats.update();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											function render() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												gpuCompute.compute();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												particleUniforms[ 'texturePosition' ].value = gpuCompute.getCurrentRenderTarget( positionVariable ).texture;
							 | 
						||
| 
								 | 
							
												particleUniforms[ 'textureVelocity' ].value = gpuCompute.getCurrentRenderTarget( velocityVariable ).texture;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												renderer.render( scene, camera );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										</script>
							 | 
						||
| 
								 | 
							
									</body>
							 | 
						||
| 
								 | 
							
								</html>
							 |