├── LICENSE.md ├── README.md ├── img ├── bump-vs-nobump.png ├── cpu_vs_gpu.png ├── cramped-corners.png ├── discontinuous-edges.png ├── faceted-cube-wireframe.png ├── nearest-neighbour.png ├── normal-mapping.png ├── normalized-faceted-cube-wireframe.png ├── planet-part-2.png ├── planet-part-2b.png ├── planet.png ├── render-to-target.png ├── sphere-wireframe.png ├── spherical-mapping-butthole-2.png ├── tricosine.png ├── tricubic.png ├── trilinear.png ├── uv-coordinates.png └── webgl-cube.png ├── index.html ├── js ├── main.js ├── material.js ├── planet.js ├── spheremap.js ├── starbox.js └── util.js └── lib └── three.js /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Holger Ludvigsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | procedural-planet-part-2 2 | ================= 3 | 4 | Proceural planet in WebGL and three.js - PART 2 5 | 6 | ![Resulting planet](https://github.com/holgerl/procedural-planet-part-2/blob/gh-pages/img/planet-part-2b.png) 7 | 8 | See [the result](http://holgerl.github.io/procedural-planet-part-2/) 9 | 10 | See [the blog post](https://blogg.bekk.no/procedural-planet-in-webgl-and-three-js-part-2-33d99bbb2256) 11 | 12 | Also see [Part 1](https://github.com/holgerl/procedural-planet) of the blog post 13 | -------------------------------------------------------------------------------- /img/bump-vs-nobump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/bump-vs-nobump.png -------------------------------------------------------------------------------- /img/cpu_vs_gpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/cpu_vs_gpu.png -------------------------------------------------------------------------------- /img/cramped-corners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/cramped-corners.png -------------------------------------------------------------------------------- /img/discontinuous-edges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/discontinuous-edges.png -------------------------------------------------------------------------------- /img/faceted-cube-wireframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/faceted-cube-wireframe.png -------------------------------------------------------------------------------- /img/nearest-neighbour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/nearest-neighbour.png -------------------------------------------------------------------------------- /img/normal-mapping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/normal-mapping.png -------------------------------------------------------------------------------- /img/normalized-faceted-cube-wireframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/normalized-faceted-cube-wireframe.png -------------------------------------------------------------------------------- /img/planet-part-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/planet-part-2.png -------------------------------------------------------------------------------- /img/planet-part-2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/planet-part-2b.png -------------------------------------------------------------------------------- /img/planet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/planet.png -------------------------------------------------------------------------------- /img/render-to-target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/render-to-target.png -------------------------------------------------------------------------------- /img/sphere-wireframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/sphere-wireframe.png -------------------------------------------------------------------------------- /img/spherical-mapping-butthole-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/spherical-mapping-butthole-2.png -------------------------------------------------------------------------------- /img/tricosine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/tricosine.png -------------------------------------------------------------------------------- /img/tricubic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/tricubic.png -------------------------------------------------------------------------------- /img/trilinear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/trilinear.png -------------------------------------------------------------------------------- /img/uv-coordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/uv-coordinates.png -------------------------------------------------------------------------------- /img/webgl-cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holgerl/procedural-planet-part-2/ea25d3ffda6f1777caa5403c980c4f761796d4ba/img/webgl-cube.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 19 | 20 | 23 | 24 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.SS = window.SS || {}; 4 | SS.main = SS.main || {}; 5 | 6 | SS.main.main = function() { 7 | window.renderer = new THREE.WebGLRenderer({antialias: true}); 8 | var renderer = window.renderer; 9 | renderer.gammaInput = true; 10 | renderer.gammaOutput = true; 11 | renderer.setClearColor(0x000000, 1); 12 | renderer.setSize(window.innerWidth, window.innerHeight); 13 | renderer.domElement.setAttribute('id', 'renderer'); 14 | document.body.appendChild(renderer.domElement); 15 | 16 | window.scene = new THREE.Scene(); 17 | var ratio = renderer.getContext().drawingBufferWidth / renderer.getContext().drawingBufferHeight; 18 | window.camera = new THREE.PerspectiveCamera(60, ratio, 0.1, 10000); 19 | window.editorCamera = new SS.util.EditorCamera(camera, document, 15, new THREE.Vector2(-Math.PI*(1/4),-Math.PI*(1/4))); 20 | 21 | SS.util.addResizeListener(); 22 | SS.main.addSceneContent(scene); 23 | 24 | SS.main.render(); 25 | } 26 | 27 | SS.main.render = function() { 28 | requestAnimationFrame(SS.main.render); 29 | 30 | window.time = window.time || new Date().getTime(); 31 | var newTime = new Date().getTime(); 32 | var diff = newTime - time; 33 | if (editorCamera.mouseDown == false) { 34 | editorCamera.cameraPos.x += diff/1000*(2*3.1415)*(1/3600/24)*3000; 35 | editorCamera.cameraStartPos = editorCamera.cameraPos; 36 | editorCamera.rotateCamera(); 37 | } 38 | time = newTime; 39 | 40 | window.renderer.render(window.scene, window.camera); 41 | }; 42 | 43 | SS.main.addSceneContent = function(scene) { 44 | window.sunLight = new THREE.PointLight(new THREE.Color(0xffffff), 1.0); 45 | sunLight.position.set(100, 0, 0); 46 | scene.add(sunLight); 47 | 48 | var maps = SS.main.generateTextures(); 49 | 50 | scene.add(new SS.planet.Planet(5, maps.textureMaps, maps.bumpMaps)); 51 | 52 | //scene.add(new SS.starbox.StarBox(4000)); 53 | } 54 | 55 | SS.main.generateTextures = function() { 56 | var textureMaps = []; 57 | var bumpMaps = []; 58 | var resolution = 1024; 59 | 60 | for (var index = 0; index < 6; index++) { 61 | var texture = new THREE.WebGLRenderTarget(resolution, resolution, {minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat}); 62 | 63 | var textureCamera = new THREE.OrthographicCamera(-resolution/2, resolution/2, resolution/2, -resolution/2, -100, 100); 64 | textureCamera.position.z = 10; 65 | 66 | var textureScene = new THREE.Scene(); 67 | var plane = new THREE.Mesh( 68 | new THREE.PlaneGeometry(resolution, resolution), 69 | new SS.material.textureGeneratorMaterial(index) 70 | ); 71 | plane.position.z = -10; 72 | textureScene.add(plane); 73 | 74 | renderer.render(textureScene, textureCamera, texture, true); 75 | 76 | var buffer = new Uint8Array(resolution * resolution * 4); 77 | var gl = renderer.getContext(); 78 | gl.readPixels( 0, 0, resolution, resolution, gl.RGBA, gl.UNSIGNED_BYTE, buffer); 79 | 80 | textureMaps.push(texture); 81 | bumpMaps.push({image: {data: buffer, height: resolution, width: resolution}}); 82 | } 83 | return {textureMaps: textureMaps, bumpMaps: bumpMaps}; 84 | } -------------------------------------------------------------------------------- /js/material.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.SS = window.SS || {}; 4 | SS.material = SS.material || {}; 5 | 6 | SS.material.shaderMaterial = function(textureMap, bumpMap) { 7 | var vertexShader = "\ 8 | varying vec3 vNormal;\ 9 | varying vec3 cameraVector;\ 10 | varying vec3 vPosition;\ 11 | varying vec2 vUv;\ 12 | \ 13 | void main() {\ 14 | vNormal = normal;\ 15 | vec4 vPosition4 = modelMatrix * vec4(position, 1.0);\ 16 | vPosition = vPosition4.xyz;\ 17 | cameraVector = cameraPosition - vPosition;\ 18 | vUv = uv;\ 19 | \ 20 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\ 21 | }\ 22 | "; 23 | 24 | var fragmentShader = "\ 25 | uniform vec3 pointLightPosition;\ 26 | uniform sampler2D map;\ 27 | uniform sampler2D normalMap;\ 28 | \ 29 | varying vec3 vNormal;\ 30 | varying vec3 vPosition;\ 31 | varying vec3 cameraVector;\ 32 | varying vec2 vUv;\ 33 | \ 34 | mat4 rotationMatrix(vec3 axis, float angle) {\ 35 | axis = normalize(axis);\ 36 | float s = sin(angle);\ 37 | float c = cos(angle);\ 38 | float oc = 1.0 - c;\ 39 | \ 40 | return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0,\ 41 | oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0,\ 42 | oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0,\ 43 | 0.0, 0.0, 0.0, 1.0);\ 44 | }\ 45 | \ 46 | vec3 bumpNormal(sampler2D normalMap, vec2 vUv) {\ 47 | vec3 bumpedNormal = normalize(texture2D(normalMap, vUv).xyz * 2.0 - 1.0);\ 48 | \ 49 | vec3 y_axis = vec3(0,1,0);\ 50 | float rot_angle = acos(dot(bumpedNormal,y_axis));\ 51 | vec3 rot_axis = normalize(cross(bumpedNormal,y_axis));\ 52 | return vec3(rotationMatrix(rot_axis, rot_angle) * vec4(vNormal, 1.0));\ 53 | }\ 54 | \ 55 | void main() {\ 56 | float PI = 3.14159265358979323846264;\ 57 | vec3 light = pointLightPosition - vPosition;\ 58 | vec3 cameraDir = normalize(cameraVector);\ 59 | vec3 newNormal = bumpNormal(normalMap, vUv);\ 60 | \ 61 | light = normalize(light);\ 62 | \ 63 | float lightAngle = max(0.0, dot(newNormal, light));\ 64 | float viewAngle = max(0.0, dot(vNormal, cameraDir));\ 65 | float adjustedLightAngle = min(0.6, lightAngle) / 0.6;\ 66 | float adjustedViewAngle = min(0.65, viewAngle) / 0.65;\ 67 | float invertedViewAngle = pow(acos(viewAngle), 3.0) * 0.4;\ 68 | \ 69 | float dProd = 0.0;\ 70 | dProd += 0.5 * lightAngle;\ 71 | dProd += 0.2 * lightAngle * (invertedViewAngle - 0.1);\ 72 | dProd += invertedViewAngle * 0.5 * (max(-0.35, dot(vNormal, light)) + 0.35);\ 73 | dProd *= 0.7 + pow(invertedViewAngle/(PI/2.0), 2.0);\ 74 | \ 75 | dProd *= 0.5;\ 76 | vec4 atmColor = vec4(dProd, dProd, dProd, 1.0);\ 77 | \ 78 | vec4 texelColor = texture2D(map, vUv) * min(asin(lightAngle), 1.0);\ 79 | gl_FragColor = texelColor + min(atmColor, 0.8);\ 80 | /*gl_FragColor = texture2D(map, vUv);*/\ 81 | }\ 82 | "; 83 | 84 | var uniforms = { 85 | "pointLightPosition": {"type": "v3", "value": sunLight.position}, 86 | "map": {"type": "t", "value": textureMap}, 87 | "normalMap": {"type": "t", "value": SS.util.heightToNormalMap(bumpMap, 4.0)} 88 | }; 89 | 90 | return new THREE.ShaderMaterial({ 91 | uniforms: uniforms, 92 | vertexShader: vertexShader, 93 | fragmentShader: fragmentShader, 94 | transparent: true 95 | }); 96 | } 97 | 98 | SS.material.textureGeneratorMaterial = function(index) { 99 | var vertexShader = "\ 100 | varying vec2 vUv;\ 101 | \ 102 | void main() {\ 103 | vUv = uv;\ 104 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\ 105 | }\ 106 | "; 107 | 108 | var fragmentShader = "\ 109 | varying vec2 vUv;\n\ 110 | uniform int index;\n\ 111 | \ 112 | int mod(int x, int m) {\n\ 113 | return int(mod(float(x), float(m)));\n\ 114 | }\n\ 115 | \ 116 | float random5(vec3 co) {\n\ 117 | return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,1.23456))) * 43758.5453);\n\ 118 | }\n\ 119 | \ 120 | \ 121 | float random4(float x, float y, float z) {\n\ 122 | return random5(vec3(x, y, z));\n\ 123 | }\n\ 124 | \ 125 | float random4(int x, int y, int z) {\n\ 126 | return random4(float(x), float(y), float(z));\n\ 127 | }\n\ 128 | \ 129 | float interpolation(float a, float b, float x) {\n\ 130 | float ft = x * 3.1415927;\n\ 131 | float f = (1.0 - cos(ft)) * 0.5;\n\ 132 | return a*(1.0-f) + b*f;\n\ 133 | }\n\ 134 | \ 135 | float tricosine(vec3 coordFloat) {\n\ 136 | vec3 coord0 = vec3(floor(coordFloat.x), floor(coordFloat.y), floor(coordFloat.z));\n\ 137 | vec3 coord1 = vec3(coord0.x+1.0, coord0.y+1.0, coord0.z+1.0);\n\ 138 | float xd = (coordFloat.x - coord0.x)/max(1.0, (coord1.x-coord0.x));\n\ 139 | float yd = (coordFloat.y - coord0.y)/max(1.0, (coord1.y-coord0.y));\n\ 140 | float zd = (coordFloat.z - coord0.z)/max(1.0, (coord1.z-coord0.z));\n\ 141 | float c00 = interpolation(random4(coord0.x, coord0.y, coord0.z), random4(coord1.x, coord0.y, coord0.z), xd);\n\ 142 | float c10 = interpolation(random4(coord0.x, coord1.y, coord0.z), random4(coord1.x, coord1.y, coord0.z), xd);\n\ 143 | float c01 = interpolation(random4(coord0.x, coord0.y, coord1.z), random4(coord1.x, coord0.y, coord1.z), xd);\n\ 144 | float c11 = interpolation(random4(coord0.x, coord1.y, coord1.z), random4(coord1.x, coord1.y, coord1.z), xd);\n\ 145 | float c0 = interpolation(c00, c10, yd);\n\ 146 | float c1 = interpolation(c01, c11, yd);\n\ 147 | float c = interpolation(c0, c1, zd);\n\ 148 | \ 149 | return c;\n\ 150 | }\n\ 151 | \ 152 | float nearestNeighbour(vec3 coordFloat) {\n\ 153 | return random4(int(floor(coordFloat.x)), int(floor(coordFloat.y)), int(floor(coordFloat.z)));\n\ 154 | }\n\ 155 | \ 156 | float helper(float x, float y, float z, float resolution) {\n\ 157 | x = (x+1.0)/2.0*resolution;\n\ 158 | y = (y+1.0)/2.0*resolution;\n\ 159 | z = (z+1.0)/2.0*resolution;\n\ 160 | \n\ 161 | vec3 coordFloat = vec3(x, y, z);\n\ 162 | float interpolated = tricosine(coordFloat);\n\ 163 | return interpolated*2.0 - 1.0;\n\ 164 | }\n\ 165 | \ 166 | vec3 scalarField(float x, float y, float z) {\n\ 167 | float resolution1 = 4.0;\n\ 168 | float resolution2 = 16.0;\n\ 169 | float resolution3 = 32.0;\n\ 170 | float resolution4 = 64.0;\n\ 171 | float resolution5 = 128.0;\n\ 172 | float resolutionMax = 256.0;\n\ 173 | \n\ 174 | vec3 coordFloat = vec3(0.0, 0.0, 0.0);\n\ 175 | \n\ 176 | float level1 = helper(x, y, z, resolution1);\n\ 177 | float level2 = helper(x, y, z, resolution2);\n\ 178 | float level3 = helper(x, y, z, resolution3);\n\ 179 | float level4 = helper(x, y, z, resolution4);\n\ 180 | float level5 = helper(x, y, z, resolution5);\n\ 181 | float levelMax = helper(x, y, z, resolutionMax);\n\ 182 | \n\ 183 | float c = 0.5;\n\ 184 | c *= 1.0 + level1*0.8;\n\ 185 | c *= 1.0 + level2*0.4;\n\ 186 | c *= 1.0 + level3*0.2;\n\ 187 | c *= 1.0 + level4*0.1;\n\ 188 | c *= 1.0 + level5*0.05;\n\ 189 | c *= 1.0 + levelMax*(0.025);\n\ 190 | \n\ 191 | if (c < 0.5) c *= 0.9;\n\ 192 | \n\ 193 | c = clamp(c, 0.0, 1.0);\n\ 194 | \n\ 195 | return vec3(c, c, c);\n\ 196 | }\n\ 197 | \ 198 | vec3 getSphericalCoord(int index, float x, float y, float width) {\n\ 199 | width /= 2.0;\n\ 200 | x -= width;\n\ 201 | y -= width;\n\ 202 | vec3 coord = vec3(0.0, 0.0, 0.0);\n\ 203 | \ 204 | if (index == 0) {coord.x=width; coord.y=-y; coord.z=-x;}\n\ 205 | else if (index == 1) {coord.x=-width; coord.y=-y; coord.z=x;}\n\ 206 | else if (index == 2) {coord.x=x; coord.y=width; coord.z=y;}\n\ 207 | else if (index == 3) {coord.x=x; coord.y=-width; coord.z=-y;}\n\ 208 | else if (index == 4) {coord.x=x; coord.y=-y; coord.z=width;}\n\ 209 | else if (index == 5) {coord.x=-x; coord.y=-y; coord.z=-width;}\n\ 210 | \ 211 | return normalize(coord);\n\ 212 | }\ 213 | \ 214 | void main() {\n\ 215 | float x = vUv.x;\n\ 216 | float y = 1.0 - vUv.y;\n\ 217 | vec3 sphericalCoord = getSphericalCoord(index, x*1024.0, y*1024.0, 1024.0);\n\ 218 | \ 219 | vec3 color = scalarField(sphericalCoord.x, sphericalCoord.y, sphericalCoord.z);\n\ 220 | \ 221 | gl_FragColor = vec4(color.x, color.y, color.z, 1.0);\n\ 222 | }\ 223 | "; 224 | 225 | var uniforms = { 226 | index: {type: "i", value: index} 227 | }; 228 | 229 | return new THREE.ShaderMaterial({ 230 | uniforms: uniforms, 231 | vertexShader: vertexShader, 232 | fragmentShader: fragmentShader, 233 | transparent: true, 234 | depthWrite: false 235 | }); 236 | } -------------------------------------------------------------------------------- /js/planet.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.SS = window.SS || {}; 4 | SS.planet = SS.planet || {}; 5 | 6 | SS.lowgraphics = true; 7 | var maxDetail = SS.lowgraphics ? 16 : 512; //256 = 11 seconds (before), 512 = 5 seconds (now) 8 | 9 | SS.planet.Planet = function(planetRadius, textureMaps, bumpMaps) { 10 | THREE.Object3D.call(this); 11 | 12 | var materialArray = []; 13 | for (var i = 0; i < 6; i++) { 14 | materialArray.push(SS.material.shaderMaterial(textureMaps[i], bumpMaps[i])); 15 | } 16 | 17 | var sphere = new SS.spheremap.Sphere(planetRadius, materialArray); 18 | this.add(sphere); 19 | } 20 | SS.planet.Planet.prototype = Object.create(THREE.Object3D.prototype); -------------------------------------------------------------------------------- /js/spheremap.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.SS = window.SS || {}; 4 | SS.spheremap = SS.spheremap || {}; 5 | 6 | SS.spheremap.Sphere = function(radius, materialArray) { 7 | THREE.Object3D.call(this); 8 | 9 | radius = radius || 1; 10 | 11 | var geometry = new THREE.BoxGeometry(1, 1, 1, 64, 64, 64); 12 | 13 | for (var i in geometry.vertices) { 14 | var vertex = geometry.vertices[i]; 15 | vertex.normalize().multiplyScalar(radius); 16 | } 17 | 18 | SS.util.computeGeometry(geometry); 19 | 20 | var computeVertexNormals = function(geometry) { 21 | for (var f = 0; f < geometry.faces.length; f++) { 22 | var face = geometry.faces[f]; 23 | face.vertexNormals[0] = geometry.vertices[face.a].clone().normalize(); 24 | face.vertexNormals[1] = geometry.vertices[face.b].clone().normalize(); 25 | face.vertexNormals[2] = geometry.vertices[face.c].clone().normalize(); 26 | } 27 | } 28 | 29 | computeVertexNormals(geometry); // TODO: Why is this neccessary? (Why does geometry.computeVertexNormals not work correctly?) 30 | 31 | var sphereMaterial = new THREE.MeshFaceMaterial(materialArray); 32 | var sphere = new THREE.Mesh(geometry, sphereMaterial); 33 | 34 | this.add(sphere); 35 | } 36 | SS.spheremap.Sphere.prototype = Object.create(THREE.Object3D.prototype); -------------------------------------------------------------------------------- /js/starbox.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.SS = window.SS || {}; 4 | SS.starbox = SS.starbox || {}; 5 | 6 | var maxDetail = SS.lowgraphics ? 16 : 512; //256 = 11 seconds (before), 512 = 5 seconds (now) 7 | 8 | SS.starbox.StarBox = function(radius) { 9 | THREE.Object3D.call(this); 10 | 11 | var sphere = new SS.spheremap.Sphere( 12 | SS.starbox.starboxcalarField, 13 | radius, 14 | function() {return new THREE.MeshBasicMaterial({side: THREE.BackSide, depthWrite: false});}, 15 | maxDetail, 16 | false 17 | ); 18 | 19 | this.add(sphere); 20 | } 21 | SS.starbox.StarBox.prototype = Object.create(THREE.Object3D.prototype); 22 | 23 | SS.starbox.starboxcalarField = function(x, y, z) { 24 | var starResolution = maxDetail; 25 | var starDensity = 1/1000; 26 | 27 | var coordFloat = new THREE.Vector3(); 28 | 29 | var starScalarField = function(x, y, z) { 30 | var rand = SS.util.random4(Math.abs(x), Math.abs(y), Math.abs(z)); 31 | return rand < starDensity ? rand/starDensity*(1-0.25) : 0; 32 | } 33 | 34 | var helper = function(x, y, z, scalarField, resolution, interpolationMethod) { 35 | // Because the sphere sample function gives normalized coordinates: 36 | x = (x+1)/2*resolution; 37 | y = (y+1)/2*resolution; 38 | z = (z+1)/2*resolution; 39 | 40 | coordFloat.set(x, y, z); 41 | 42 | return interpolationMethod(coordFloat, scalarField); 43 | } 44 | 45 | var c = helper(x, y, z, starScalarField, starResolution, SS.util.nearestNeighbour); 46 | 47 | c = SS.util.clamp(c, 0, 1); 48 | 49 | return new THREE.Color().setRGB(c, c, c); 50 | } -------------------------------------------------------------------------------- /js/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.SS = window.SS || {}; 4 | SS.util = SS.util || {}; 5 | 6 | SS.util.clamp = function(number, from, to) { 7 | return Math.max(Math.min(number, to), from); 8 | } 9 | 10 | SS.util.randomInt = function(from, to, seed) { 11 | return Math.floor(SS.util.randomFloat(from, to+1, seed)); 12 | } 13 | 14 | SS.util.randomFloat = function(from, to, seed) { 15 | return SS.util.random(seed)*(to-from)+from; 16 | } 17 | 18 | SS.util.random = function(seed) { 19 | var scope = SS.util.random; 20 | 21 | scope.MAX = scope.MAX || Math.pow(2, 32); 22 | scope.a = 1664525; 23 | scope.c = 1013904223; 24 | 25 | scope.seeds = scope.seeds || {}; 26 | 27 | seed = seed || 0; 28 | var key = seed; 29 | if (typeof seed == "string") { 30 | if (scope.seeds[seed] == undefined) { 31 | var numeric = SS.util.numberFromString(seed); 32 | scope.seeds[seed] = numeric; // Memoization 33 | seed = numeric; 34 | } else { 35 | seed = scope.seeds[seed]; 36 | } 37 | } 38 | scope.series = scope.series || {}; 39 | scope.series[key] = scope.series[key] || seed; 40 | 41 | var lastRandom = scope.series[key]; 42 | var newRandom = (scope.a * lastRandom + scope.c) % scope.MAX; 43 | 44 | scope.series[key] = newRandom; 45 | 46 | return newRandom/scope.MAX; 47 | } 48 | 49 | SS.util.resetRandomSeries = function(prefix) { 50 | var toBeCleared = []; 51 | for (var i in SS.util.random.series) { 52 | if (i.indexOf(prefix) == 0) toBeCleared.push(i); 53 | } 54 | for (var i in toBeCleared) { 55 | delete SS.util.random.series[toBeCleared[i]]; 56 | } 57 | } 58 | 59 | SS.util.makeSpecifiedArray1D = function(size, value, array) { 60 | var valueFloat = value; 61 | for (var x = 0; x < size; x++) { 62 | if (typeof(value) == "function") valueFloat = value(x); 63 | array[x] = valueFloat; 64 | } 65 | return array; 66 | } 67 | 68 | window.N = 256*256; 69 | window.G = SS.util.makeSpecifiedArray1D(N, Math.random, new Float32Array(N)); 70 | window.P = SS.util.makeSpecifiedArray1D(N, function() {return SS.util.randomInt(0, N-1)}, new Uint32Array(N)); 71 | 72 | SS.util.random4 = function(i, j, k) { 73 | return G[(i + P[(j + P[k % N]) % N]) % N]; 74 | } 75 | 76 | SS.util.EditorCamera = function(camera, document, startRadius, cameraStartPos, originObject) { 77 | this.camera = camera; 78 | this.mouseDown = false; 79 | this.startRadius = startRadius || 20; 80 | this.startExp = 6; 81 | this.radius = this.startExp; 82 | this.originObject = originObject || {position: new THREE.Vector3()}; 83 | this.cameraStartPos = cameraStartPos || new THREE.Vector2(Math.PI/8, -Math.PI/4); 84 | this.cameraPos = this.cameraStartPos.clone(); 85 | this.mouseClickPos = new THREE.Vector2(); 86 | 87 | var editorCamera = this; 88 | 89 | var addEventListeners = function() { 90 | document.addEventListener('mousemove', function(event) { 91 | var mousePos = new THREE.Vector2(event.clientX, event.clientY); 92 | if (editorCamera.mouseDown == true) { 93 | var diff = mousePos.clone().sub(editorCamera.mouseClickPos).multiplyScalar(1/250); 94 | editorCamera.cameraPos = editorCamera.cameraStartPos.clone().add(diff); 95 | editorCamera.rotateCamera(); 96 | } 97 | }); 98 | 99 | document.addEventListener('mousewheel', function(event) { 100 | var delta = event.wheelDelta/20000; 101 | if (editorCamera.getScaledRadius(editorCamera.radius - delta) >= 0) { 102 | editorCamera.radius -= delta; 103 | editorCamera.zoomCamera(); 104 | } 105 | }); 106 | 107 | document.addEventListener('mousedown', function(event) { 108 | var mousePos = new THREE.Vector2(event.clientX, event.clientY); 109 | editorCamera.mouseClickPos = mousePos; 110 | editorCamera.mouseDown = true; 111 | }); 112 | 113 | document.addEventListener('mouseup', function(event) { 114 | editorCamera.cameraStartPos = editorCamera.cameraPos; 115 | editorCamera.mouseDown = false; 116 | }); 117 | } 118 | 119 | 120 | this.getScaledRadius = function(radius) { 121 | return Math.exp(radius) - Math.exp(this.startExp) + this.startRadius 122 | } 123 | 124 | this.zoomCamera = function() { 125 | this.camera.position.normalize().multiplyScalar(this.getScaledRadius(this.radius)); 126 | } 127 | 128 | this.rotateCamera = function() { 129 | this.camera.position.y = -this.cameraPos.y; 130 | this.camera.position.x = Math.sin(this.cameraPos.x); 131 | this.camera.position.z = Math.cos(this.cameraPos.x); 132 | 133 | this.zoomCamera(); 134 | 135 | this.camera.lookAt(new THREE.Vector3(0, 0, 0)); 136 | 137 | this.camera.position.add(this.originObject.position); 138 | } 139 | 140 | addEventListeners(); 141 | this.rotateCamera(); 142 | } 143 | 144 | SS.util.addResizeListener = function() { 145 | window.addEventListener('resize', function() { 146 | renderer.setSize(window.innerWidth, window.innerHeight); 147 | camera.aspect = window.innerWidth / window.innerHeight; 148 | camera.updateProjectionMatrix(); 149 | }); 150 | } 151 | 152 | SS.util.computeGeometry = function(geometry) { 153 | geometry.makeGroups(); 154 | geometry.computeVertexNormals() 155 | geometry.computeFaceNormals(); 156 | geometry.computeMorphNormals(); 157 | geometry.computeBoundingSphere(); 158 | geometry.computeBoundingBox(); 159 | geometry.computeLineDistances(); 160 | 161 | geometry.verticesNeedUpdate = true; 162 | geometry.elementsNeedUpdate = true; 163 | geometry.uvsNeedUpdate = true; 164 | geometry.normalsNeedUpdate = true; 165 | geometry.tangentsNeedUpdate = true; 166 | geometry.colorsNeedUpdate = true; 167 | geometry.lineDistancesNeedUpdate = true; 168 | geometry.buffersNeedUpdate = true; 169 | geometry.groupsNeedUpdate = true; 170 | } 171 | 172 | SS.util.trilinearInterpolation = function(coordFloat, scalarField, interpolation) { 173 | interpolation = interpolation || function(a, b, x) { 174 | return a*(1-x) + b*x; 175 | } 176 | 177 | var coord0 = {x: Math.floor(coordFloat.x), y: Math.floor(coordFloat.y), z: Math.floor(coordFloat.z)}; 178 | var coord1 = {x: coord0.x+1, y: coord0.y+1, z: coord0.z+1}; 179 | var xd = (coordFloat.x - coord0.x)/Math.max(1, (coord1.x-coord0.x)); 180 | var yd = (coordFloat.y - coord0.y)/Math.max(1, (coord1.y-coord0.y)); 181 | var zd = (coordFloat.z - coord0.z)/Math.max(1, (coord1.z-coord0.z)); 182 | var c00 = interpolation(scalarField(coord0.x, coord0.y, coord0.z), scalarField(coord1.x, coord0.y, coord0.z), xd); 183 | var c10 = interpolation(scalarField(coord0.x, coord1.y, coord0.z), scalarField(coord1.x, coord1.y, coord0.z), xd); 184 | var c01 = interpolation(scalarField(coord0.x, coord0.y, coord1.z), scalarField(coord1.x, coord0.y, coord1.z), xd); 185 | var c11 = interpolation(scalarField(coord0.x, coord1.y, coord1.z), scalarField(coord1.x, coord1.y, coord1.z), xd); 186 | var c0 = interpolation(c00, c10, yd); 187 | var c1 = interpolation(c01, c11, yd); 188 | var c = interpolation(c0, c1, zd); 189 | 190 | return c; 191 | } 192 | 193 | SS.util.nearestNeighbour = function(coordFloat, scalarField) { 194 | return scalarField(Math.floor(coordFloat.x), Math.floor(coordFloat.y), Math.floor(coordFloat.z)); 195 | } 196 | 197 | SS.util.tricosineInterpolation = function(coordFloat, scalarField) { 198 | var interpolation = function(a, b, x) { 199 | var ft = x * 3.1415927; 200 | var f = (1 - Math.cos(ft)) * 0.5; 201 | return a*(1-f) + b*f 202 | } 203 | 204 | return SS.util.trilinearInterpolation(coordFloat, scalarField, interpolation); 205 | } 206 | 207 | SS.util.heightToNormalMap = function(map, intensity) { 208 | var width = map.image.width; 209 | var height = map.image.height; 210 | var nofPixels = width*height; 211 | 212 | intensity = intensity || 1.0; 213 | 214 | var getHeight = function(x, y) { 215 | x = Math.min(x, width-1); 216 | y = Math.min(y, height-1); 217 | return ( 218 | map.image.data[(y*width+x)*4+0]/255 + 219 | map.image.data[(y*width+x)*4+1]/255 + 220 | map.image.data[(y*width+x)*4+2]/255 221 | )/3*intensity; 222 | } 223 | 224 | var normalMap = THREE.ImageUtils.generateDataTexture(width, height, new THREE.Color(0x000000)); 225 | 226 | for (var i = 0; i < nofPixels; i++) { 227 | var x = i%width; 228 | var y = height-Math.floor(i/width); 229 | 230 | var pixel00 = new THREE.Vector3(0, 0, getHeight(x, y)); 231 | var pixel01 = new THREE.Vector3(0, 1, getHeight(x, y+1)); 232 | var pixel10 = new THREE.Vector3(1, 0, getHeight(x+1, y)); 233 | var orto = pixel10.sub(pixel00).cross(pixel01.sub(pixel00)).normalize(); 234 | 235 | normalMap.image.data[i*3+0] = (orto.x/2+0.5)*255; 236 | normalMap.image.data[i*3+1] = (orto.y/2+0.5)*255; 237 | normalMap.image.data[i*3+2] = (orto.z/2+0.5)*255; 238 | } 239 | 240 | return normalMap; 241 | } --------------------------------------------------------------------------------