Compare commits
1 Commits
master
...
subdivisio
Author | SHA1 | Date | |
---|---|---|---|
496b2a58e3 |
32
README.md
32
README.md
@ -1,32 +0,0 @@
|
|||||||
# Hexsphere and Icosahedron Viewer
|
|
||||||
|
|
||||||
View live at: https://www.hallada.net/planet/
|
|
||||||
|
|
||||||
Renders shapes generated from my other project
|
|
||||||
[icosahedron](https://crates.io/crates/icosahedron) ([github
|
|
||||||
repo](https://github.com/thallada/icosahedron)) using
|
|
||||||
[regl.js](https://github.com/regl-project/regl).
|
|
||||||
|
|
||||||
Since this is hosted on Github, which has a 100 MB file limit. The most detailed
|
|
||||||
shapes available for rendering are the hexsphere at detail level 6 and the
|
|
||||||
icosahedron at detail level 7.
|
|
||||||
|
|
||||||
## Running
|
|
||||||
|
|
||||||
Checkout and then run:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
Compiles files to the `/docs` folder which is the folder set up for Github pages
|
|
||||||
hosting.
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
Any output needs to be committed for it to appear on Github pages.
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
theme: none
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,51 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset=utf-8 />
|
|
||||||
<title>Icosahedrons and Hexspheres Generated in Rust</title>
|
|
||||||
<style>
|
|
||||||
html, body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 100%;
|
|
||||||
color: #eee;
|
|
||||||
background-color: black;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
canvas { width: 100%; height: 100%; }
|
|
||||||
div.loading-container { display: flex; align-items: center; justify-content: center; height: 100%; }
|
|
||||||
div.select-container { position: fixed; top: 0px; width: 100%; z-index: 1; margin: 10px; }
|
|
||||||
p.loading { font-size: 32px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="select-container">
|
|
||||||
<label>
|
|
||||||
Rendered Shape:
|
|
||||||
<select id="shape-select">
|
|
||||||
<option value="hexsphere_0">Hexsphere 0</option>
|
|
||||||
<option value="hexsphere_1">Hexsphere 1</option>
|
|
||||||
<option value="hexsphere_2">Hexsphere 2</option>
|
|
||||||
<option value="hexsphere_3">Hexsphere 3</option>
|
|
||||||
<option value="hexsphere_4" selected>Hexsphere 4</option>
|
|
||||||
<option value="hexsphere_5">Hexsphere 5</option>
|
|
||||||
<option value="hexsphere_6">Hexsphere 6</option>
|
|
||||||
<option value="hexsphere_7">Hexsphere 7</option>
|
|
||||||
<option value="icosahedron_0">Icosahedron 0</option>
|
|
||||||
<option value="icosahedron_1">Icosahedron 1</option>
|
|
||||||
<option value="icosahedron_2">Icosahedron 2</option>
|
|
||||||
<option value="icosahedron_3">Icosahedron 3</option>
|
|
||||||
<option value="icosahedron_4">Icosahedron 4</option>
|
|
||||||
<option value="icosahedron_5">Icosahedron 5</option>
|
|
||||||
<option value="icosahedron_6">Icosahedron 6</option>
|
|
||||||
<option value="icosahedron_7">Icosahedron 7</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<span id="shape-loading" style="display: none">Loading...</span>
|
|
||||||
</div>
|
|
||||||
<div class="loading-container">
|
|
||||||
<p class="loading">Loading...</p>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript" src="main.js"></script></body>
|
|
||||||
</html>
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
img/detail-0.png
BIN
img/detail-0.png
Binary file not shown.
Before Width: | Height: | Size: 8.0 KiB |
BIN
img/detail-1.png
BIN
img/detail-1.png
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
BIN
img/detail-8.png
BIN
img/detail-8.png
Binary file not shown.
Before Width: | Height: | Size: 1.2 MiB |
@ -5,22 +5,19 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"start": "webpack-dev-server --mode development --watch --progress --hot --host 0.0.0.0 --port 8888 --public mule.hallada.net:8888",
|
"start": "webpack-dev-server --mode development --watch-poll --progress --hot",
|
||||||
"build": "webpack"
|
"build": "webpack"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"angle-normals": "^1.0.0",
|
|
||||||
"regl": "^1.3.11",
|
|
||||||
"regl-camera": "^2.1.1",
|
|
||||||
"three": "^0.101.1",
|
"three": "^0.101.1",
|
||||||
"three-orbit-controls": "^82.1.0"
|
"three-orbit-controls": "^82.1.0",
|
||||||
|
"three-subdivision-modifier": "^1.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"file-loader": "^3.0.1",
|
"file-loader": "^3.0.1",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"url-loader": "^3.0.0",
|
|
||||||
"webpack": "^4.29.0",
|
"webpack": "^4.29.0",
|
||||||
"webpack-cli": "^3.2.1",
|
"webpack-cli": "^3.2.1",
|
||||||
"webpack-dev-server": "^3.1.14"
|
"webpack-dev-server": "^3.1.14"
|
||||||
|
@ -2,49 +2,12 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset=utf-8 />
|
<meta charset=utf-8 />
|
||||||
<title>Icosahedrons and Hexspheres Generated in Rust</title>
|
<title>My first three.js app</title>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body { margin: 0; padding: 0; overflow: hidden; }
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 100%;
|
|
||||||
color: #eee;
|
|
||||||
background-color: black;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
canvas { width: 100%; height: 100%; }
|
canvas { width: 100%; height: 100%; }
|
||||||
div.loading-container { display: flex; align-items: center; justify-content: center; height: 100%; }
|
|
||||||
div.select-container { position: fixed; top: 0px; width: 100%; z-index: 1; margin: 10px; }
|
|
||||||
p.loading { font-size: 32px; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="select-container">
|
|
||||||
<label>
|
|
||||||
Rendered Shape:
|
|
||||||
<select id="shape-select">
|
|
||||||
<option value="hexsphere_0">Hexsphere 0</option>
|
|
||||||
<option value="hexsphere_1">Hexsphere 1</option>
|
|
||||||
<option value="hexsphere_2">Hexsphere 2</option>
|
|
||||||
<option value="hexsphere_3">Hexsphere 3</option>
|
|
||||||
<option value="hexsphere_4" selected>Hexsphere 4</option>
|
|
||||||
<option value="hexsphere_5">Hexsphere 5</option>
|
|
||||||
<option value="hexsphere_6">Hexsphere 6</option>
|
|
||||||
<option value="icosahedron_0">Icosahedron 0</option>
|
|
||||||
<option value="icosahedron_1">Icosahedron 1</option>
|
|
||||||
<option value="icosahedron_2">Icosahedron 2</option>
|
|
||||||
<option value="icosahedron_3">Icosahedron 3</option>
|
|
||||||
<option value="icosahedron_4">Icosahedron 4</option>
|
|
||||||
<option value="icosahedron_5">Icosahedron 5</option>
|
|
||||||
<option value="icosahedron_6">Icosahedron 6</option>
|
|
||||||
<option value="icosahedron_7">Icosahedron 7</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<span id="shape-loading" style="display: none">Loading...</span>
|
|
||||||
</div>
|
|
||||||
<div class="loading-container">
|
|
||||||
<p class="loading">Loading...</p>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
156
src/index.js
Normal file
156
src/index.js
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
var OrbitControls = require("three-orbit-controls")(THREE);
|
||||||
|
var SubdivisionModifier = require("three-subdivision-modifier");
|
||||||
|
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
var camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||||
|
|
||||||
|
var geometry = new THREE.IcosahedronBufferGeometry(5, 1);
|
||||||
|
|
||||||
|
var position = geometry.getAttribute("position");
|
||||||
|
var colors = [];
|
||||||
|
var color = new THREE.Color(Math.random(), Math.random(), Math.random());
|
||||||
|
for (var i = 0; i < position.count / 3; i += 1) {
|
||||||
|
color.setRGB(i / (position.count / 3), i / (position.count / 3), i / (position.count / 3));
|
||||||
|
colors.push(color.r, color.g, color.b);
|
||||||
|
colors.push(color.r, color.g, color.b);
|
||||||
|
colors.push(color.r, color.g, color.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disposeArray() {
|
||||||
|
this.array = null;
|
||||||
|
}
|
||||||
|
geometry.addAttribute("color", new THREE.Float32BufferAttribute(colors, 3).onUpload(disposeArray));
|
||||||
|
var material = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors });
|
||||||
|
var sphere = new THREE.Mesh(geometry, material);
|
||||||
|
// scene.add(sphere);
|
||||||
|
|
||||||
|
var polyhedronMesh = new THREE.Object3D();
|
||||||
|
var faces;
|
||||||
|
|
||||||
|
function displayPolyhedron(data)
|
||||||
|
{
|
||||||
|
scene.remove(polyhedronMesh);
|
||||||
|
polyhedronMesh = polyhedronDataToMesh(data);
|
||||||
|
scene.add(polyhedronMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
function polyhedronDataToMesh(data)
|
||||||
|
{
|
||||||
|
var polyhedron = new THREE.Object3D();
|
||||||
|
|
||||||
|
// convert vertex data to THREE.js vectors
|
||||||
|
var vertex = [];
|
||||||
|
for (var i = 0; i < data.vertex.length; i++)
|
||||||
|
vertex.push( new THREE.Vector3( data.vertex[i][0], data.vertex[i][1], data.vertex[i][2] ).multiplyScalar(100) );
|
||||||
|
// var vertexGeometry = new THREE.SphereGeometry( 6, 12, 6 );
|
||||||
|
// var vertexMaterial = new THREE.MeshLambertMaterial( { color: 0x222244 } );
|
||||||
|
// var vertexSingleMesh = new THREE.Mesh( vertexGeometry );
|
||||||
|
// var vertexAmalgam = new THREE.Geometry();
|
||||||
|
// for (var i = 0; i < data.vertex.length; i++)
|
||||||
|
// {
|
||||||
|
// var vMesh = vertexSingleMesh.clone();
|
||||||
|
// vMesh.position = vertex[i];
|
||||||
|
// THREE.GeometryUtils.merge( vertexAmalgam, vMesh );
|
||||||
|
// }
|
||||||
|
// var vertexMesh = new THREE.Mesh( vertexAmalgam, vertexMaterial );
|
||||||
|
// polyhedron.add( vertexMesh );
|
||||||
|
|
||||||
|
// // convert edge data to cylinders
|
||||||
|
// var edgeMaterial = new THREE.MeshLambertMaterial( {color: 0x666666} );
|
||||||
|
// var edgeAmalgam = new THREE.Geometry();
|
||||||
|
// for (var i = 0; i < data.edge.length; i++)
|
||||||
|
// {
|
||||||
|
// var index0 = data.edge[i][0];
|
||||||
|
// var index1 = data.edge[i][1];
|
||||||
|
// var eMesh = cylinderMesh( vertex[index0], vertex[index1], edgeMaterial );
|
||||||
|
// THREE.GeometryUtils.merge( edgeAmalgam, eMesh );
|
||||||
|
// }
|
||||||
|
// var edgeMesh = new THREE.Mesh( edgeAmalgam, edgeMaterial );
|
||||||
|
// polyhedron.add( edgeMesh );
|
||||||
|
|
||||||
|
// convert face data to a single (triangulated) geometry
|
||||||
|
var faceMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors, side: THREE.FrontSide, transparent: false, opacity:0.8 } );
|
||||||
|
var faceColors =
|
||||||
|
{
|
||||||
|
3: new THREE.Color( 0xcc0000 ),
|
||||||
|
4: new THREE.Color( 0x00cc00 ),
|
||||||
|
5: new THREE.Color( 0x0000cc ),
|
||||||
|
6: new THREE.Color( 0xcccc00 ),
|
||||||
|
7: new THREE.Color( 0x999999 ),
|
||||||
|
8: new THREE.Color( 0x990099 ),
|
||||||
|
9: new THREE.Color( 0xff6600 ),
|
||||||
|
10: new THREE.Color( 0x6666ff )
|
||||||
|
};
|
||||||
|
|
||||||
|
var geometry = new THREE.Geometry();
|
||||||
|
geometry.vertices = vertex;
|
||||||
|
var faceIndex = 0;
|
||||||
|
for (var faceNum = 0; faceNum < data.face.length; faceNum++)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < data.face[faceNum].length - 2; i++)
|
||||||
|
{
|
||||||
|
geometry.faces[faceIndex] = new THREE.Face3( data.face[faceNum][0], data.face[faceNum][i+1], data.face[faceNum][i+2] );
|
||||||
|
geometry.faces[faceIndex].color = faceColors[data.face[faceNum].length];
|
||||||
|
faceIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry.computeFaceNormals();
|
||||||
|
geometry.computeVertexNormals();
|
||||||
|
|
||||||
|
var modifier = new SubdivisionModifier(5);
|
||||||
|
modifier.modify(geometry);
|
||||||
|
|
||||||
|
for ( var i = 0; i < geometry.faces.length; i ++ ) {
|
||||||
|
var face = geometry.faces[ i ];
|
||||||
|
for ( var j = 0; j < 3; j ++ ) {
|
||||||
|
// var vertexIndex = face[ faceIndices[ j ] ];
|
||||||
|
// var vertex = geometry.vertices[ vertexIndex ];
|
||||||
|
|
||||||
|
var hue = Math.random();
|
||||||
|
var color = new THREE.Color().setHSL( hue, 1, 0.5 );
|
||||||
|
|
||||||
|
face.vertexColors[ j ] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
faces = new THREE.Mesh(geometry, faceMaterial);
|
||||||
|
faces.scale.multiplyScalar(1.01);
|
||||||
|
polyhedron.add(faces);
|
||||||
|
|
||||||
|
return polyhedron;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayPolyhedron({
|
||||||
|
"name":"Truncated Icosahedron",
|
||||||
|
"category":["Archimedean Solid"],
|
||||||
|
"vertex":[[0,0,1.021],[0.4035482,0,0.9378643],[-0.2274644,0.3333333,0.9378643],[-0.1471226,-0.375774,0.9378643],[0.579632,0.3333333,0.7715933],[0.5058321,-0.375774,0.8033483],[-0.6020514,0.2908927,0.7715933],[-0.05138057,0.6666667,0.7715933],[0.1654988,-0.6080151,0.8033483],[-0.5217096,-0.4182147,0.7715933],[0.8579998,0.2908927,0.4708062],[0.3521676,0.6666667,0.6884578],[0.7841999,-0.4182147,0.5025612],[-0.657475,0.5979962,0.5025612],[-0.749174,-0.08488134,0.6884578],[-0.3171418,0.8302373,0.5025612],[0.1035333,-0.8826969,0.5025612],[-0.5836751,-0.6928964,0.4708062],[0.8025761,0.5979962,0.2017741],[0.9602837,-0.08488134,0.3362902],[0.4899547,0.8302373,0.3362902],[0.7222343,-0.6928964,0.2017741],[-0.8600213,0.5293258,0.1503935],[-0.9517203,-0.1535518,0.3362902],[-0.1793548,0.993808,0.1503935],[0.381901,-0.9251375,0.2017741],[-0.2710537,-0.9251375,0.3362902],[-0.8494363,-0.5293258,0.2017741],[0.8494363,0.5293258,-0.2017741],[1.007144,-0.1535518,-0.06725804],[0.2241935,0.993808,0.06725804],[0.8600213,-0.5293258,-0.1503935],[-0.7222343,0.6928964,-0.2017741],[-1.007144,0.1535518,0.06725804],[-0.381901,0.9251375,-0.2017741],[0.1793548,-0.993808,-0.1503935],[-0.2241935,-0.993808,-0.06725804],[-0.8025761,-0.5979962,-0.2017741],[0.5836751,0.6928964,-0.4708062],[0.9517203,0.1535518,-0.3362902],[0.2710537,0.9251375,-0.3362902],[0.657475,-0.5979962,-0.5025612],[-0.7841999,0.4182147,-0.5025612],[-0.9602837,0.08488134,-0.3362902],[-0.1035333,0.8826969,-0.5025612],[0.3171418,-0.8302373,-0.5025612],[-0.4899547,-0.8302373,-0.3362902],[-0.8579998,-0.2908927,-0.4708062],[0.5217096,0.4182147,-0.7715933],[0.749174,0.08488134,-0.6884578],[0.6020514,-0.2908927,-0.7715933],[-0.5058321,0.375774,-0.8033483],[-0.1654988,0.6080151,-0.8033483],[0.05138057,-0.6666667,-0.7715933],[-0.3521676,-0.6666667,-0.6884578],[-0.579632,-0.3333333,-0.7715933],[0.1471226,0.375774,-0.9378643],[0.2274644,-0.3333333,-0.9378643],[-0.4035482,0,-0.9378643],[0,0,-1.021]],
|
||||||
|
"edge":[[0,3],[3,8],[8,5],[5,1],[1,0],[2,7],[7,15],[15,13],[13,6],[6,2],[4,10],[10,18],[18,20],[20,11],[11,4],[9,14],[14,23],[23,27],[27,17],[17,9],[12,21],[21,31],[31,29],[29,19],[19,12],[16,26],[26,36],[36,35],[35,25],[25,16],[22,32],[32,42],[42,43],[43,33],[33,22],[24,30],[30,40],[40,44],[44,34],[34,24],[28,39],[39,49],[49,48],[48,38],[38,28],[37,47],[47,55],[55,54],[54,46],[46,37],[41,45],[45,53],[53,57],[57,50],[50,41],[51,52],[52,56],[56,59],[59,58],[58,51],[1,4],[11,7],[2,0],[6,14],[9,3],[5,12],[19,10],[17,26],[16,8],[25,21],[13,22],[33,23],[20,30],[24,15],[29,39],[28,18],[34,32],[27,37],[46,36],[38,40],[35,45],[41,31],[43,47],[50,49],[44,52],[51,42],[54,53],[48,56],[58,55],[57,59]],
|
||||||
|
"face":[[0,3,8,5,1],[2,7,15,13,6],[4,10,18,20,11],[9,14,23,27,17],[12,21,31,29,19],[16,26,36,35,25],[22,32,42,43,33],[24,30,40,44,34],[28,39,49,48,38],[37,47,55,54,46],[41,45,53,57,50],[51,52,56,59,58],[0,1,4,11,7,2],[0,2,6,14,9,3],[1,5,12,19,10,4],[3,9,17,26,16,8],[5,8,16,25,21,12],[6,13,22,33,23,14],[7,11,20,30,24,15],[10,19,29,39,28,18],[13,15,24,34,32,22],[17,27,37,46,36,26],[18,28,38,40,30,20],[21,25,35,45,41,31],[23,33,43,47,37,27],[29,31,41,50,49,39],[32,34,44,52,51,42],[35,36,46,54,53,45],[38,48,56,52,44,40],[42,51,58,55,47,43],[48,49,50,57,59,56],[53,54,55,58,59,57]]});
|
||||||
|
|
||||||
|
var controls = new OrbitControls(camera);
|
||||||
|
|
||||||
|
camera.position.z = 15;
|
||||||
|
controls.update()
|
||||||
|
|
||||||
|
var renderer = new THREE.WebGLRenderer();
|
||||||
|
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||||
|
document.body.appendChild( renderer.domElement );
|
||||||
|
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
controls.update();
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
animate();
|
@ -1,132 +0,0 @@
|
|||||||
import hexsphere_0 from "./shapes/hexsphere_r1_d0.bin"
|
|
||||||
import hexsphere_1 from "./shapes/hexsphere_r1_d1.bin"
|
|
||||||
import hexsphere_2 from "./shapes/hexsphere_r1_d2.bin"
|
|
||||||
import hexsphere_3 from "./shapes/hexsphere_r1_d3.bin"
|
|
||||||
import hexsphere_4 from "./shapes/hexsphere_r1_d4.bin"
|
|
||||||
import hexsphere_5 from "./shapes/hexsphere_r1_d5.bin"
|
|
||||||
import hexsphere_6 from "./shapes/hexsphere_r1_d6.bin"
|
|
||||||
import icosahedron_0 from "./shapes/icosahedron_r1_d0.bin"
|
|
||||||
import icosahedron_1 from "./shapes/icosahedron_r1_d1.bin"
|
|
||||||
import icosahedron_2 from "./shapes/icosahedron_r1_d2.bin"
|
|
||||||
import icosahedron_3 from "./shapes/icosahedron_r1_d3.bin"
|
|
||||||
import icosahedron_4 from "./shapes/icosahedron_r1_d4.bin"
|
|
||||||
import icosahedron_5 from "./shapes/icosahedron_r1_d5.bin"
|
|
||||||
import icosahedron_6 from "./shapes/icosahedron_r1_d6.bin"
|
|
||||||
import icosahedron_7 from "./shapes/icosahedron_r1_d7.bin"
|
|
||||||
|
|
||||||
const shapes = {
|
|
||||||
"hexsphere_0": hexsphere_0,
|
|
||||||
"hexsphere_1": hexsphere_1,
|
|
||||||
"hexsphere_2": hexsphere_2,
|
|
||||||
"hexsphere_3": hexsphere_3,
|
|
||||||
"hexsphere_4": hexsphere_4,
|
|
||||||
"hexsphere_5": hexsphere_5,
|
|
||||||
"hexsphere_6": hexsphere_6,
|
|
||||||
"icosahedron_0": icosahedron_0,
|
|
||||||
"icosahedron_1": icosahedron_1,
|
|
||||||
"icosahedron_2": icosahedron_2,
|
|
||||||
"icosahedron_3": icosahedron_3,
|
|
||||||
"icosahedron_4": icosahedron_4,
|
|
||||||
"icosahedron_5": icosahedron_5,
|
|
||||||
"icosahedron_6": icosahedron_6,
|
|
||||||
"icosahedron_7": icosahedron_7,
|
|
||||||
}
|
|
||||||
|
|
||||||
const regl = require("regl")({
|
|
||||||
extensions: ["OES_element_index_uint"],
|
|
||||||
})
|
|
||||||
const camera = require("regl-camera")(regl, {
|
|
||||||
center: [0, 0, 0],
|
|
||||||
distance: 3,
|
|
||||||
})
|
|
||||||
|
|
||||||
const drawShape = hexsphere => regl({
|
|
||||||
vert: `
|
|
||||||
precision mediump float;
|
|
||||||
uniform mat4 projection, view;
|
|
||||||
attribute vec3 position, normal, color;
|
|
||||||
varying vec3 fragNormal, fragPosition, fragColor;
|
|
||||||
void main() {
|
|
||||||
fragNormal = normal;
|
|
||||||
fragPosition = position;
|
|
||||||
fragColor = color;
|
|
||||||
gl_Position = projection * view * vec4(position, 1.0);
|
|
||||||
}`,
|
|
||||||
|
|
||||||
frag: `
|
|
||||||
precision mediump float;
|
|
||||||
struct Light {
|
|
||||||
vec3 color;
|
|
||||||
vec3 position;
|
|
||||||
};
|
|
||||||
uniform Light lights[1];
|
|
||||||
varying vec3 fragNormal, fragPosition, fragColor;
|
|
||||||
void main() {
|
|
||||||
vec3 normal = normalize(fragNormal);
|
|
||||||
vec3 light = vec3(0.1, 0.1, 0.1);
|
|
||||||
for (int i = 0; i < 1; i++) {
|
|
||||||
vec3 lightDir = normalize(lights[i].position - fragPosition);
|
|
||||||
float diffuse = max(0.0, dot(lightDir, normal));
|
|
||||||
light += diffuse * lights[i].color;
|
|
||||||
}
|
|
||||||
gl_FragColor = vec4(fragColor * light, 1.0);
|
|
||||||
}`,
|
|
||||||
|
|
||||||
attributes: {
|
|
||||||
position: hexsphere.positions,
|
|
||||||
normal: hexsphere.normals,
|
|
||||||
color: hexsphere.colors,
|
|
||||||
},
|
|
||||||
elements: hexsphere.cells,
|
|
||||||
uniforms: {
|
|
||||||
"lights[0].color": [1, 1, 1],
|
|
||||||
"lights[0].position": ({ tick }) => {
|
|
||||||
const t = 0.008 * tick
|
|
||||||
return [
|
|
||||||
1000 * Math.cos(t),
|
|
||||||
1000 * Math.sin(t),
|
|
||||||
1000 * Math.sin(t)
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
let draw = null
|
|
||||||
|
|
||||||
const loadShape = shape => {
|
|
||||||
fetch(shape)
|
|
||||||
.then(response => response.arrayBuffer())
|
|
||||||
.then(buffer => {
|
|
||||||
let reader = new DataView(buffer);
|
|
||||||
let numVertices = reader.getUint32(0, true);
|
|
||||||
let numCells = reader.getUint32(4, true);
|
|
||||||
const shapeData = {
|
|
||||||
positions: new Float32Array(buffer, 8, numVertices * 3),
|
|
||||||
normals: new Float32Array(buffer, numVertices * 12 + 8, numVertices * 3),
|
|
||||||
colors: new Float32Array(buffer, numVertices * 24 + 8, numVertices * 3),
|
|
||||||
cells: new Uint32Array(buffer, numVertices * 36 + 8, numCells * 3),
|
|
||||||
}
|
|
||||||
draw = drawShape(shapeData)
|
|
||||||
regl.frame(() => {
|
|
||||||
regl.clear({
|
|
||||||
depth: 1,
|
|
||||||
color: [0, 0, 0, 1]
|
|
||||||
})
|
|
||||||
|
|
||||||
camera(() => {
|
|
||||||
draw()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
shapeSelectLoading.style.display = "none"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const shapeSelect = document.querySelector("select#shape-select")
|
|
||||||
const shapeSelectLoading = document.querySelector("#shape-loading")
|
|
||||||
shapeSelect.value = "hexsphere_4"
|
|
||||||
loadShape(hexsphere_4)
|
|
||||||
|
|
||||||
shapeSelect.addEventListener("change", event => {
|
|
||||||
shapeSelectLoading.style.display = "inline"
|
|
||||||
loadShape(shapes[event.target.value])
|
|
||||||
})
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,186 +0,0 @@
|
|||||||
import * as THREE from "three";
|
|
||||||
|
|
||||||
const OrbitControls = require("three-orbit-controls")(THREE);
|
|
||||||
|
|
||||||
const scene = new THREE.Scene();
|
|
||||||
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
|
|
||||||
|
|
||||||
console.time("init geo");
|
|
||||||
const geometry = new THREE.IcosahedronGeometry(1, 1);
|
|
||||||
console.timeEnd("init geo");
|
|
||||||
console.log(geometry);
|
|
||||||
|
|
||||||
console.time("Hexsphere");
|
|
||||||
const vertToFaces = {};
|
|
||||||
const newVertices = [];
|
|
||||||
const colors = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < geometry.faces.length; i += 1) {
|
|
||||||
const face = geometry.faces[i];
|
|
||||||
|
|
||||||
if (vertToFaces[face.a]) {
|
|
||||||
vertToFaces[face.a].push(i);
|
|
||||||
} else {
|
|
||||||
vertToFaces[face.a] = [i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vertToFaces[face.b]) {
|
|
||||||
vertToFaces[face.b].push(i);
|
|
||||||
} else {
|
|
||||||
vertToFaces[face.b] = [i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vertToFaces[face.c]) {
|
|
||||||
vertToFaces[face.c].push(i);
|
|
||||||
} else {
|
|
||||||
vertToFaces[face.c] = [i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(vertToFaces);
|
|
||||||
|
|
||||||
const originalVertCount = geometry.vertices.length;
|
|
||||||
|
|
||||||
const calculateCentroid = (pa, pb, pc) => {
|
|
||||||
const vabHalf = pb.clone().sub(pa).divideScalar(2);
|
|
||||||
const pabHalf = pa.clone().add(vabHalf);
|
|
||||||
const centroid = pc.clone().sub(pabHalf).multiplyScalar(1/3).add(pabHalf);
|
|
||||||
return centroid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const faceCentroids = {};
|
|
||||||
for (let i = 0; i < geometry.faces.length; i += 1) {
|
|
||||||
const face = geometry.faces[i];
|
|
||||||
const vertexA = geometry.vertices[face.a];
|
|
||||||
const vertexB = geometry.vertices[face.b];
|
|
||||||
const vertexC = geometry.vertices[face.c];
|
|
||||||
|
|
||||||
faceCentroids[i] = calculateCentroid(vertexA, vertexB, vertexC);
|
|
||||||
}
|
|
||||||
|
|
||||||
const findAdjacentFace = (vertexIndex, faces) => {
|
|
||||||
for (let i = 0; i < faces.length; i += 1) {
|
|
||||||
const faceIndex = faces[i];
|
|
||||||
const face = geometry.faces[faceIndex];
|
|
||||||
if ([face.a, face.b, face.c].includes(vertexIndex)) return faceIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const findCenterPoint = faces => {
|
|
||||||
const centerPoint = new THREE.Vector3(0, 0, 0);
|
|
||||||
for (let i = 0; i < faces.length; i += 1) {
|
|
||||||
centerPoint.add(faceCentroids[faces[i]]);
|
|
||||||
}
|
|
||||||
centerPoint.divideScalar(faces.length);
|
|
||||||
return centerPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
const midCentroidCache = {};
|
|
||||||
const calculateMidCentroid = (vertexIndex, faces, centroid) => {
|
|
||||||
const adjFaceIndex = findAdjacentFace(vertexIndex, faces);
|
|
||||||
const adjCentroid = faceCentroids[adjFaceIndex];
|
|
||||||
const midCentroidKey = vertexIndex + ",F" + adjFaceIndex;
|
|
||||||
let midCentroid = midCentroidCache[midCentroidKey];
|
|
||||||
if (!midCentroid) {
|
|
||||||
midCentroid = centroid.clone().lerp(adjCentroid, 0.5);
|
|
||||||
midCentroidCache[midCentroidKey] = midCentroid;
|
|
||||||
}
|
|
||||||
return midCentroid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
console.time("dual");
|
|
||||||
let hexCount = 0;
|
|
||||||
let pentCount = 0;
|
|
||||||
for (let i = 0; i < originalVertCount; i += 1) {
|
|
||||||
const faces = vertToFaces[i];
|
|
||||||
if (faces.length === 6) {
|
|
||||||
hexCount += 1;
|
|
||||||
} else if (faces.length === 5) {
|
|
||||||
pentCount += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const color = new THREE.Color(Math.random(), Math.random(), Math.random());
|
|
||||||
const centerPoint = findCenterPoint(faces);
|
|
||||||
|
|
||||||
for (let j = 0; j < faces.length; j += 1) {
|
|
||||||
const faceIndex = faces[j];
|
|
||||||
const face = geometry.faces[faceIndex];
|
|
||||||
const sortedVerts = [face.a, face.b, face.c].filter(vert => vert !== i);
|
|
||||||
sortedVerts.unshift(i)
|
|
||||||
|
|
||||||
const centroid = faceCentroids[faceIndex];
|
|
||||||
const midBCentroid = calculateMidCentroid(sortedVerts[1], faces, centroid);
|
|
||||||
const midCCentroid = calculateMidCentroid(sortedVerts[2], faces, centroid);
|
|
||||||
|
|
||||||
newVertices.push(
|
|
||||||
centerPoint.x, centerPoint.y, centerPoint.z,
|
|
||||||
centroid.x, centroid.y, centroid.z,
|
|
||||||
midBCentroid.x, midBCentroid.y, midBCentroid.z,
|
|
||||||
|
|
||||||
centerPoint.x, centerPoint.y, centerPoint.z,
|
|
||||||
centroid.x, centroid.y, centroid.z,
|
|
||||||
midCCentroid.x, midCCentroid.y, midCCentroid.z,
|
|
||||||
);
|
|
||||||
|
|
||||||
colors.push(
|
|
||||||
color.r, color.g, color.b,
|
|
||||||
color.r, color.g, color.b,
|
|
||||||
color.r, color.g, color.b,
|
|
||||||
|
|
||||||
color.r, color.g, color.b,
|
|
||||||
color.r, color.g, color.b,
|
|
||||||
color.r, color.g, color.b,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.timeEnd("dual");
|
|
||||||
console.log(`hexagons: ${hexCount}`);
|
|
||||||
console.log(`pentagons: ${pentCount}`);
|
|
||||||
|
|
||||||
function disposeArray() {
|
|
||||||
this.array = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.time("find geo");
|
|
||||||
const newGeometry = new THREE.BufferGeometry();
|
|
||||||
newGeometry.addAttribute("position", new THREE.Float32BufferAttribute(newVertices, 3).onUpload(disposeArray));
|
|
||||||
newGeometry.addAttribute("color", new THREE.Float32BufferAttribute(colors, 3).onUpload(disposeArray));
|
|
||||||
newGeometry.computeFaceNormals();
|
|
||||||
newGeometry.computeVertexNormals();
|
|
||||||
const nonBuffer = new THREE.Geometry().fromBufferGeometry(newGeometry);
|
|
||||||
console.log(nonBuffer);
|
|
||||||
console.timeEnd("find geo");
|
|
||||||
|
|
||||||
|
|
||||||
console.time("other render");
|
|
||||||
const material = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors, side: THREE.DoubleSide });
|
|
||||||
const sphere = new THREE.Mesh(newGeometry, material);
|
|
||||||
scene.add(sphere);
|
|
||||||
|
|
||||||
const controls = new OrbitControls(camera);
|
|
||||||
|
|
||||||
camera.position.z = 15;
|
|
||||||
controls.update()
|
|
||||||
|
|
||||||
const renderer = new THREE.WebGLRenderer();
|
|
||||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
|
||||||
document.body.appendChild( renderer.domElement );
|
|
||||||
console.timeEnd("other render");
|
|
||||||
console.timeEnd("Hexsphere");
|
|
||||||
|
|
||||||
window.addEventListener('resize', onWindowResize, false);
|
|
||||||
|
|
||||||
function onWindowResize() {
|
|
||||||
camera.aspect = window.innerWidth / window.innerHeight;
|
|
||||||
camera.updateProjectionMatrix();
|
|
||||||
controls.update();
|
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
function animate() {
|
|
||||||
renderer.render(scene, camera);
|
|
||||||
requestAnimationFrame(animate);
|
|
||||||
}
|
|
||||||
|
|
||||||
animate();
|
|
@ -2,25 +2,15 @@ const path = require("path");
|
|||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: "./src/regl_index.js",
|
entry: "./src/index.js",
|
||||||
output: {
|
output: {
|
||||||
filename: "main.js",
|
filename: "main.js",
|
||||||
path: path.resolve(__dirname, "docs")
|
path: path.resolve(__dirname, "dist")
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.(png|jpg|gif|bin)$/,
|
test: /\.(png|jpg|gif)$/,
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'file-loader',
|
|
||||||
options: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.json$/,
|
|
||||||
type: 'javascript/auto',
|
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
|
Loading…
Reference in New Issue
Block a user