Compare commits
14 Commits
subdivisio
...
master
Author | SHA1 | Date | |
---|---|---|---|
069f4e1878 | |||
31cb65caa5 | |||
d94b6b18af | |||
f90d8fce00 | |||
856cdafcb4 | |||
1dce74a9ea | |||
35bb35415a | |||
2ddcc0bbd3 | |||
69ac45b21c | |||
d062708cec | |||
1743145944 | |||
3b75f81d49 | |||
ec1a200aaf | |||
113de04cbe |
32
README.md
Normal file
32
README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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.
|
BIN
docs/4cc86edf6517c35dd8aecdbf6a4b1a2e.bin
Normal file
BIN
docs/4cc86edf6517c35dd8aecdbf6a4b1a2e.bin
Normal file
Binary file not shown.
BIN
docs/5293ee29e3db7bbd05f03823aa9bd53a.bin
Normal file
BIN
docs/5293ee29e3db7bbd05f03823aa9bd53a.bin
Normal file
Binary file not shown.
BIN
docs/670398984b2a839f0da3039cd8ae215a.bin
Normal file
BIN
docs/670398984b2a839f0da3039cd8ae215a.bin
Normal file
Binary file not shown.
BIN
docs/6f2d59ca82e22144ee26889cc862912f.bin
Normal file
BIN
docs/6f2d59ca82e22144ee26889cc862912f.bin
Normal file
Binary file not shown.
BIN
docs/80e3348d39fbc859dfe0bb2cda08c5b1.bin
Normal file
BIN
docs/80e3348d39fbc859dfe0bb2cda08c5b1.bin
Normal file
Binary file not shown.
BIN
docs/88a1fb4d8c42c36a027c7ab503de7511.bin
Normal file
BIN
docs/88a1fb4d8c42c36a027c7ab503de7511.bin
Normal file
Binary file not shown.
BIN
docs/8ab0cc172cd882ef6b69422eaa5a502d.bin
Normal file
BIN
docs/8ab0cc172cd882ef6b69422eaa5a502d.bin
Normal file
Binary file not shown.
BIN
docs/8c72ff38eff4b3d878b6e59563fb2558.bin
Normal file
BIN
docs/8c72ff38eff4b3d878b6e59563fb2558.bin
Normal file
Binary file not shown.
1
docs/_config.yml
Normal file
1
docs/_config.yml
Normal file
@ -0,0 +1 @@
|
|||||||
|
theme: none
|
BIN
docs/a7a417e76651f9fa75e63e45e22095e6.bin
Normal file
BIN
docs/a7a417e76651f9fa75e63e45e22095e6.bin
Normal file
Binary file not shown.
BIN
docs/aad316ae2f3185e637764ab20f4536ee.bin
Normal file
BIN
docs/aad316ae2f3185e637764ab20f4536ee.bin
Normal file
Binary file not shown.
BIN
docs/b8f9c879c9c795656294aa401ac3854c.bin
Normal file
BIN
docs/b8f9c879c9c795656294aa401ac3854c.bin
Normal file
Binary file not shown.
BIN
docs/c40f782b6d48c16bbdfa867a67914314.bin
Normal file
BIN
docs/c40f782b6d48c16bbdfa867a67914314.bin
Normal file
Binary file not shown.
BIN
docs/c5d1e42d1b2c2960ef12ca75b5e71fc1.bin
Normal file
BIN
docs/c5d1e42d1b2c2960ef12ca75b5e71fc1.bin
Normal file
Binary file not shown.
BIN
docs/dcbe4e47e8a4cb4c76f00dc2ca584ea3.bin
Normal file
BIN
docs/dcbe4e47e8a4cb4c76f00dc2ca584ea3.bin
Normal file
Binary file not shown.
BIN
docs/f988ae2257d2f750090c9bda21c58f10.bin
Normal file
BIN
docs/f988ae2257d2f750090c9bda21c58f10.bin
Normal file
Binary file not shown.
51
docs/index.html
Normal file
51
docs/index.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<!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>
|
2
docs/main.js
Normal file
2
docs/main.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/main.js.map
Normal file
1
docs/main.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
img/detail-0.png
Normal file
BIN
img/detail-0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
img/detail-1.png
Normal file
BIN
img/detail-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
img/detail-8.png
Normal file
BIN
img/detail-8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
@ -5,19 +5,22 @@
|
|||||||
"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-poll --progress --hot",
|
"start": "webpack-dev-server --mode development --watch --progress --hot --host 0.0.0.0 --port 8888 --public mule.hallada.net:8888",
|
||||||
"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,12 +2,49 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset=utf-8 />
|
<meta charset=utf-8 />
|
||||||
<title>My first three.js app</title>
|
<title>Icosahedrons and Hexspheres Generated in Rust</title>
|
||||||
<style>
|
<style>
|
||||||
html, body { margin: 0; padding: 0; overflow: hidden; }
|
html, body {
|
||||||
|
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
156
src/index.js
@ -1,156 +0,0 @@
|
|||||||
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();
|
|
132
src/regl_index.js
Normal file
132
src/regl_index.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
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])
|
||||||
|
})
|
BIN
src/shapes/hexsphere_r1_d0.bin
Normal file
BIN
src/shapes/hexsphere_r1_d0.bin
Normal file
Binary file not shown.
BIN
src/shapes/hexsphere_r1_d1.bin
Normal file
BIN
src/shapes/hexsphere_r1_d1.bin
Normal file
Binary file not shown.
BIN
src/shapes/hexsphere_r1_d2.bin
Normal file
BIN
src/shapes/hexsphere_r1_d2.bin
Normal file
Binary file not shown.
BIN
src/shapes/hexsphere_r1_d3.bin
Normal file
BIN
src/shapes/hexsphere_r1_d3.bin
Normal file
Binary file not shown.
BIN
src/shapes/hexsphere_r1_d4.bin
Normal file
BIN
src/shapes/hexsphere_r1_d4.bin
Normal file
Binary file not shown.
BIN
src/shapes/hexsphere_r1_d5.bin
Normal file
BIN
src/shapes/hexsphere_r1_d5.bin
Normal file
Binary file not shown.
BIN
src/shapes/hexsphere_r1_d6.bin
Normal file
BIN
src/shapes/hexsphere_r1_d6.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d0.bin
Normal file
BIN
src/shapes/icosahedron_r1_d0.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d1.bin
Normal file
BIN
src/shapes/icosahedron_r1_d1.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d2.bin
Normal file
BIN
src/shapes/icosahedron_r1_d2.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d3.bin
Normal file
BIN
src/shapes/icosahedron_r1_d3.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d4.bin
Normal file
BIN
src/shapes/icosahedron_r1_d4.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d5.bin
Normal file
BIN
src/shapes/icosahedron_r1_d5.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d6.bin
Normal file
BIN
src/shapes/icosahedron_r1_d6.bin
Normal file
Binary file not shown.
BIN
src/shapes/icosahedron_r1_d7.bin
Normal file
BIN
src/shapes/icosahedron_r1_d7.bin
Normal file
Binary file not shown.
186
src/three_index.js
Normal file
186
src/three_index.js
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
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,15 +2,25 @@ const path = require("path");
|
|||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: "./src/index.js",
|
entry: "./src/regl_index.js",
|
||||||
output: {
|
output: {
|
||||||
filename: "main.js",
|
filename: "main.js",
|
||||||
path: path.resolve(__dirname, "dist")
|
path: path.resolve(__dirname, "docs")
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.(png|jpg|gif)$/,
|
test: /\.(png|jpg|gif|bin)$/,
|
||||||
|
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