1
0
mirror of https://github.com/taigrr/skyline synced 2025-01-18 04:33:13 -08:00

WIP export changes

This commit is contained in:
Jason Long 2020-12-11 16:45:14 -05:00
parent c71a3c2b23
commit af1f5f610a
5 changed files with 1393 additions and 738 deletions

View File

@ -9,10 +9,10 @@ gulp.task('browser-sync', function() {
})
})
gulp.task('watch', ['browser-sync'], function () {
gulp.task('watch', gulp.series('browser-sync', function() {
gulp.watch("css/*.css").on('change', bs.reload)
gulp.watch("js/*.js").on('change', bs.reload)
gulp.watch("*.html").on('change', bs.reload)
})
}))
gulp.task('auto', ['browser-sync', 'watch']);
gulp.task('auto', gulp.series('browser-sync', 'watch'));

342
js/OBJExporter.js Normal file
View File

@ -0,0 +1,342 @@
import {
BufferGeometry,
Color,
Geometry,
Line,
Matrix3,
Mesh,
Points,
Vector2,
Vector3
} from "./three.module.js";
var OBJExporter = function () {};
OBJExporter.prototype = {
constructor: OBJExporter,
parse: function ( object ) {
var output = '';
var indexVertex = 0;
var indexVertexUvs = 0;
var indexNormals = 0;
var vertex = new Vector3();
var color = new Color();
var normal = new Vector3();
var uv = new Vector2();
var i, j, k, l, m, face = [];
var parseMesh = function ( mesh ) {
var nbVertex = 0;
var nbNormals = 0;
var nbVertexUvs = 0;
var geometry = mesh.geometry;
var normalMatrixWorld = new Matrix3();
if ( geometry instanceof Geometry ) {
geometry = new BufferGeometry().setFromObject( mesh );
}
if ( geometry instanceof BufferGeometry ) {
// shortcuts
var vertices = geometry.getAttribute( 'position' );
var normals = geometry.getAttribute( 'normal' );
var uvs = geometry.getAttribute( 'uv' );
var indices = geometry.getIndex();
// name of the mesh object
output += 'o ' + mesh.name + '\n';
// name of the mesh material
if ( mesh.material && mesh.material.name ) {
output += 'usemtl ' + mesh.material.name + '\n';
}
// vertices
if ( vertices !== undefined ) {
for ( i = 0, l = vertices.count; i < l; i ++, nbVertex ++ ) {
vertex.x = vertices.getX( i );
vertex.y = vertices.getY( i );
vertex.z = vertices.getZ( i );
// transform the vertex to world space
vertex.applyMatrix4( mesh.matrixWorld );
// transform the vertex to export format
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
}
}
// uvs
if ( uvs !== undefined ) {
for ( i = 0, l = uvs.count; i < l; i ++, nbVertexUvs ++ ) {
uv.x = uvs.getX( i );
uv.y = uvs.getY( i );
// transform the uv to export format
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
}
}
// normals
if ( normals !== undefined ) {
normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
for ( i = 0, l = normals.count; i < l; i ++, nbNormals ++ ) {
normal.x = normals.getX( i );
normal.y = normals.getY( i );
normal.z = normals.getZ( i );
// transform the normal to world space
normal.applyMatrix3( normalMatrixWorld ).normalize();
// transform the normal to export format
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
}
}
// faces
if ( indices !== null ) {
for ( i = 0, l = indices.count; i < l; i += 3 ) {
for ( m = 0; m < 3; m ++ ) {
j = indices.getX( i + m ) + 1;
face[ m ] = ( indexVertex + j ) + ( normals || uvs ? '/' + ( uvs ? ( indexVertexUvs + j ) : '' ) + ( normals ? '/' + ( indexNormals + j ) : '' ) : '' );
}
// transform the face to export format
output += 'f ' + face.join( ' ' ) + "\n";
}
} else {
for ( i = 0, l = vertices.count; i < l; i += 3 ) {
for ( m = 0; m < 3; m ++ ) {
j = i + m + 1;
face[ m ] = ( indexVertex + j ) + ( normals || uvs ? '/' + ( uvs ? ( indexVertexUvs + j ) : '' ) + ( normals ? '/' + ( indexNormals + j ) : '' ) : '' );
}
// transform the face to export format
output += 'f ' + face.join( ' ' ) + "\n";
}
}
} else {
console.warn( 'THREE.OBJExporter.parseMesh(): geometry type unsupported', geometry );
}
// update index
indexVertex += nbVertex;
indexVertexUvs += nbVertexUvs;
indexNormals += nbNormals;
};
var parseLine = function ( line ) {
var nbVertex = 0;
var geometry = line.geometry;
var type = line.type;
if ( geometry instanceof Geometry ) {
geometry = new BufferGeometry().setFromObject( line );
}
if ( geometry instanceof BufferGeometry ) {
// shortcuts
var vertices = geometry.getAttribute( 'position' );
// name of the line object
output += 'o ' + line.name + '\n';
if ( vertices !== undefined ) {
for ( i = 0, l = vertices.count; i < l; i ++, nbVertex ++ ) {
vertex.x = vertices.getX( i );
vertex.y = vertices.getY( i );
vertex.z = vertices.getZ( i );
// transform the vertex to world space
vertex.applyMatrix4( line.matrixWorld );
// transform the vertex to export format
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
}
}
if ( type === 'Line' ) {
output += 'l ';
for ( j = 1, l = vertices.count; j <= l; j ++ ) {
output += ( indexVertex + j ) + ' ';
}
output += '\n';
}
if ( type === 'LineSegments' ) {
for ( j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1 ) {
output += 'l ' + ( indexVertex + j ) + ' ' + ( indexVertex + k ) + '\n';
}
}
} else {
console.warn( 'THREE.OBJExporter.parseLine(): geometry type unsupported', geometry );
}
// update index
indexVertex += nbVertex;
};
var parsePoints = function ( points ) {
var nbVertex = 0;
var geometry = points.geometry;
if ( geometry instanceof Geometry ) {
geometry = new BufferGeometry().setFromObject( points );
}
if ( geometry instanceof BufferGeometry ) {
var vertices = geometry.getAttribute( 'position' );
var colors = geometry.getAttribute( 'color' );
output += 'o ' + points.name + '\n';
if ( vertices !== undefined ) {
for ( i = 0, l = vertices.count; i < l; i ++, nbVertex ++ ) {
vertex.fromBufferAttribute( vertices, i );
vertex.applyMatrix4( points.matrixWorld );
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z;
if ( colors !== undefined ) {
color.fromBufferAttribute( colors, i );
output += ' ' + color.r + ' ' + color.g + ' ' + color.b;
}
output += '\n';
}
}
output += 'p ';
for ( j = 1, l = vertices.count; j <= l; j ++ ) {
output += ( indexVertex + j ) + ' ';
}
output += '\n';
} else {
console.warn( 'THREE.OBJExporter.parsePoints(): geometry type unsupported', geometry );
}
// update index
indexVertex += nbVertex;
};
object.traverse( function ( child ) {
if ( child instanceof Mesh ) {
parseMesh( child );
}
if ( child instanceof Line ) {
parseLine( child );
}
if ( child instanceof Points ) {
parsePoints( child );
}
} );
return output;
}
};
export { OBJExporter };

View File

@ -1,7 +1,8 @@
import * as THREE from "./three.module.js";
import { GLTFLoader } from './GLTFLoader.js';
import { OrbitControls } from './OrbitControls.js';
import { GUI } from './dat.gui.module.js';
import * as THREE from "./three.module.js"
import { GLTFLoader } from './GLTFLoader.js'
import { OrbitControls } from './OrbitControls.js'
import { OBJExporter } from './OBJExporter.js'
import { GUI } from './dat.gui.module.js'
const BASE_LENGTH = 0.834
const BASE_WIDTH = 0.167
@ -10,25 +11,25 @@ const CUBE_SIZE = 0.0143
const MAX_HEIGHT = 0.14
const FACE_ANGLE = 104.79
let username = "jasonlong"
let year = "2018"
let json = {}
let font = undefined
let fontSize = 0.025
let fontHeight = 0.00658 // Extrusion thickness
let nameMesh
let yearMesh
let camera, scene, renderer
let camera, scene, renderer, barGroup
let bronzeMaterial
var urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('username')) {
username = urlParams.get('username')
const gui = new GUI()
const params = {
username: 'jasonlong',
year: '2019'
}
if (urlParams.has('year')) {
year = urlParams.get('year')
}
let usernameController
let yearController
let exporter = new OBJExporter()
// Import JSON data
async function loadJSON(username, year) {
@ -36,20 +37,33 @@ async function loadJSON(username, year) {
let response = await fetch(url)
if (response.ok) {
json = await response.json()
init()
addBars()
addText()
render()
} else {
alert("HTTP-Error: " + response.status)
}
}
loadJSON(username, year)
usernameController = gui.add(params, 'username').name('Username')
usernameController.onChange(() => {
removeBars()
removeText()
loadJSON(params.username, params.year)
})
yearController = gui.add(params, 'year').name('Year')
yearController.onChange(() => {
removeBars()
removeText()
loadJSON(params.username, params.year)
})
const fixSideNormals = (geometry) => {
let triangle = new THREE.Triangle()
// "fix" side normals by removing z-component of normals for side faces
var triangleAreaHeuristics = 0.1 * ( fontHeight * fontSize );
var triangleAreaHeuristics = 0.1 * (fontHeight * fontSize)
for (var i = 0; i < geometry.faces.length; i++) {
let face = geometry.faces[i]
@ -75,7 +89,7 @@ const fixSideNormals = (geometry) => {
}
const createText = () => {
let nameGeo = new THREE.TextGeometry(username, {
let nameGeo = new THREE.TextGeometry(params.username, {
font: font,
size: fontSize,
height: fontHeight
@ -84,7 +98,7 @@ const createText = () => {
nameGeo.computeBoundingBox()
nameGeo.computeVertexNormals()
let yearGeo = new THREE.TextGeometry(year, {
let yearGeo = new THREE.TextGeometry(params.year, {
font: font,
size: fontSize,
height: fontHeight
@ -97,7 +111,7 @@ const createText = () => {
fixSideNormals(yearGeo)
nameGeo = new THREE.BufferGeometry().fromGeometry(nameGeo)
let nameMesh = new THREE.Mesh(nameGeo, bronzeMaterial)
nameMesh = new THREE.Mesh(nameGeo, bronzeMaterial)
nameMesh.position.x = -0.295
nameMesh.position.y = -0.075
@ -105,10 +119,11 @@ const createText = () => {
nameMesh.geometry.rotateX(FACE_ANGLE * Math.PI / 2)
nameMesh.geometry.rotateY(Math.PI * 2)
nameMesh.name = "name_mesh"
scene.add(nameMesh)
yearGeo = new THREE.BufferGeometry().fromGeometry(yearGeo)
let yearMesh = new THREE.Mesh(yearGeo, bronzeMaterial)
yearMesh = new THREE.Mesh(yearGeo, bronzeMaterial)
yearMesh.position.x = 0.280
yearMesh.position.y = -0.075
@ -116,9 +131,14 @@ const createText = () => {
yearMesh.geometry.rotateX(FACE_ANGLE * Math.PI / 2)
yearMesh.geometry.rotateY(Math.PI * 2)
yearMesh.name = "year_mesh"
scene.add(yearMesh)
}
const render = () => {
renderer.render(scene, camera)
}
const init = () => {
// SCENE
scene = new THREE.Scene()
@ -182,15 +202,21 @@ const init = () => {
scene.add(base.scene)
})
// USERNAME + YEAR
let fontLoader = new THREE.FontLoader()
fontLoader.load('../fonts/helvetiker_regular.typeface.json', function (response) {
font = response
createText()
})
const box = new THREE.Box3().setFromObject(scene)
const center = box.getCenter(new THREE.Vector3())
camera.lookAt(center)
camera.position.y = -0.4
camera.position.z = 0.3
let controls = new OrbitControls(camera, renderer.domElement)
controls.autoRotate = false
controls.screenSpacePanning = true
controls.addEventListener('change', render)
}
const addBars = () => {
// CONTRIBUTION BARS
let barGroup = new THREE.Group()
barGroup = new THREE.Group()
let maxCount = json.max
let x = 0
let y = 0
@ -213,33 +239,63 @@ const init = () => {
barGroup.position.x -= groupCenter.x
barGroup.position.y -= groupCenter.y
scene.add(barGroup)
const box = new THREE.Box3().setFromObject(scene)
const center = box.getCenter(new THREE.Vector3())
camera.lookAt(center)
camera.position.y = -0.4
camera.position.z = 0.3
let controls = new OrbitControls(camera, renderer.domElement)
controls.autoRotate = false
controls.screenSpacePanning = true
controls.addEventListener('change', render);
render()
}
const render = () => {
renderer.render(scene, camera)
const removeBars = () => {
scene.remove(barGroup)
barGroup = null
render()
}
const addText = () => {
let fontLoader = new THREE.FontLoader()
fontLoader.load('../fonts/helvetiker_regular.typeface.json', function (response) {
font = response
createText()
render()
})
}
const removeText = () => {
scene.remove(nameMesh)
scene.remove(yearMesh)
nameMesh = null
yearMesh = null
render()
}
//
// Event listeners
//
const onExport = () => {
const result = exporter.parse(mesh)
save(new Blob([ text ], { type: 'text/plain' }), filename)
}
const save = (blob, filename) => {
downloadLink.href = URL.createObjectURL(blob)
downloadLink.download = filename
downloadLink.click()
}
const onWindowResize = () => {
let canvasWidth = window.innerWidth;
let canvasHeight = window.innerHeight;
renderer.setSize( canvasWidth, canvasHeight );
camera.aspect = canvasWidth / canvasHeight;
camera.updateProjectionMatrix();
let canvasWidth = window.innerWidth
let canvasHeight = window.innerHeight
renderer.setSize(canvasWidth, canvasHeight)
camera.aspect = canvasWidth / canvasHeight
camera.updateProjectionMatrix()
render()
}
window.addEventListener('resize', onWindowResize, false)
///////////////////////////////////////////////////////////////////////
//
// ENTRY POINT
//
///////////////////////////////////////////////////////////////////////
init()
loadJSON(params.username, params.year)

1597
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,10 @@
},
"devDependencies": {
"browser-sync": "^2.18.2",
"gulp": "^3.9.1",
"gulp-watch": "^4.3.11"
"gulp": "^4.0.2",
"gulp-watch": "^5.0.1"
},
"dependencies": {
"three": "^0.118.1"
"three": "^0.123.0"
}
}