|
@@ -22,7 +22,7 @@
|
|
"imports": {
|
|
"imports": {
|
|
"three": "../build/three.module.js",
|
|
"three": "../build/three.module.js",
|
|
"three/addons/": "./jsm/",
|
|
"three/addons/": "./jsm/",
|
|
- "three-subdivide": "https://unpkg.com/three-subdivide@1.0.2/build/index.module.js"
|
|
|
|
|
|
+ "three-subdivide": "https://unpkg.com/three-subdivide@1.1.2/build/index.module.js"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</script>
|
|
@@ -36,16 +36,20 @@
|
|
|
|
|
|
let renderer, scene, camera;
|
|
let renderer, scene, camera;
|
|
let texture;
|
|
let texture;
|
|
- let meshMaterial, meshNormal, meshSmooth;
|
|
|
|
- let wireMaterial, wireNormal, wireSmooth;
|
|
|
|
|
|
+ let meshNormal, meshSmooth;
|
|
|
|
+ let wireNormal, wireSmooth;
|
|
|
|
+ let wireMaterial;
|
|
|
|
|
|
const params = {
|
|
const params = {
|
|
geometry: 'Box',
|
|
geometry: 'Box',
|
|
iterations: 3,
|
|
iterations: 3,
|
|
split: true,
|
|
split: true,
|
|
uvSmooth: false,
|
|
uvSmooth: false,
|
|
|
|
+ preserveEdges: false,
|
|
flatOnly: false,
|
|
flatOnly: false,
|
|
maxTriangles: 25000,
|
|
maxTriangles: 25000,
|
|
|
|
+ flatShading: false,
|
|
|
|
+ textured: true,
|
|
wireframe: false
|
|
wireframe: false
|
|
};
|
|
};
|
|
|
|
|
|
@@ -70,6 +74,14 @@
|
|
controls.target.set( 0, 0, 0 );
|
|
controls.target.set( 0, 0, 0 );
|
|
controls.update();
|
|
controls.update();
|
|
|
|
|
|
|
|
+ scene.add( new THREE.HemisphereLight( 0xffffff, 0x737373, 1 ) );
|
|
|
|
+
|
|
|
|
+ const frontLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
|
|
|
|
+ const backLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
|
|
|
|
+ frontLight.position.set( 0, 1, 1 );
|
|
|
|
+ backLight.position.set( 0, 1, - 1 );
|
|
|
|
+ scene.add( frontLight, backLight );
|
|
|
|
+
|
|
texture = new THREE.TextureLoader().load( './textures/uv_grid_opengl.jpg', () => {
|
|
texture = new THREE.TextureLoader().load( './textures/uv_grid_opengl.jpg', () => {
|
|
|
|
|
|
texture.wrapS = THREE.RepeatWrapping;
|
|
texture.wrapS = THREE.RepeatWrapping;
|
|
@@ -79,15 +91,8 @@
|
|
|
|
|
|
} );
|
|
} );
|
|
|
|
|
|
- meshMaterial = new THREE.MeshBasicMaterial( {
|
|
|
|
- map: texture,
|
|
|
|
- polygonOffset: true,
|
|
|
|
- polygonOffsetFactor: 1, // positive value pushes polygon further away
|
|
|
|
- polygonOffsetUnits: 1,
|
|
|
|
- side: THREE.DoubleSide
|
|
|
|
- } );
|
|
|
|
- meshNormal = new THREE.Mesh( new THREE.BufferGeometry(), meshMaterial );
|
|
|
|
- meshSmooth = new THREE.Mesh( new THREE.BufferGeometry(), meshMaterial );
|
|
|
|
|
|
+ meshNormal = new THREE.Mesh( new THREE.BufferGeometry(), new THREE.MeshBasicMaterial() );
|
|
|
|
+ meshSmooth = new THREE.Mesh( new THREE.BufferGeometry(), new THREE.MeshBasicMaterial() );
|
|
meshNormal.position.set( - 0.7, 0, 0 );
|
|
meshNormal.position.set( - 0.7, 0, 0 );
|
|
meshSmooth.position.set( 0.7, 0, 0 );
|
|
meshSmooth.position.set( 0.7, 0, 0 );
|
|
scene.add( meshNormal, meshSmooth );
|
|
scene.add( meshNormal, meshSmooth );
|
|
@@ -114,7 +119,7 @@
|
|
|
|
|
|
const geom = params.geometry.toLowerCase();
|
|
const geom = params.geometry.toLowerCase();
|
|
|
|
|
|
- params.split = geom === 'box' || geom === 'ring';
|
|
|
|
|
|
+ params.split = geom === 'box' || geom === 'ring' || geom === 'plane';
|
|
params.uvSmooth = geom === 'circle' || geom === 'plane' || geom === 'ring';
|
|
params.uvSmooth = geom === 'circle' || geom === 'plane' || geom === 'ring';
|
|
|
|
|
|
refreshDisplay();
|
|
refreshDisplay();
|
|
@@ -123,18 +128,22 @@
|
|
|
|
|
|
folder1.add( params, 'iterations' ).min( 0 ).max( 5 ).step( 1 ).onFinishChange( updateMeshes );
|
|
folder1.add( params, 'iterations' ).min( 0 ).max( 5 ).step( 1 ).onFinishChange( updateMeshes );
|
|
const splitController = folder1.add( params, 'split' ).onFinishChange( updateMeshes );
|
|
const splitController = folder1.add( params, 'split' ).onFinishChange( updateMeshes );
|
|
- const smoothController = folder1.add( params, 'uvSmooth' ).onFinishChange( updateMeshes );
|
|
|
|
- folder1.add( params, 'flatOnly' ).onFinishChange ( updateMeshes );
|
|
|
|
|
|
+ const uvSmoothController = folder1.add( params, 'uvSmooth' ).onFinishChange( updateMeshes );
|
|
|
|
+ const preserveController = folder1.add( params, 'preserveEdges' ).onFinishChange( updateMeshes );
|
|
|
|
+ folder1.add( params, 'flatOnly' ).onFinishChange( updateMeshes );
|
|
folder1.add( params, 'maxTriangles' ).onFinishChange( updateMeshes );
|
|
folder1.add( params, 'maxTriangles' ).onFinishChange( updateMeshes );
|
|
|
|
|
|
- const folder2 = gui.addFolder( 'View' );
|
|
|
|
- folder2.add( params, 'wireframe' ).onFinishChange( updateMeshes );
|
|
|
|
|
|
+ const folder2 = gui.addFolder( 'Material' );
|
|
|
|
+ folder2.add( params, 'flatShading' ).onFinishChange( updateMaterial );
|
|
|
|
+ folder2.add( params, 'textured' ).onFinishChange( updateMaterial );
|
|
|
|
+ folder2.add( params, 'wireframe' ).onFinishChange( updateWireframe );
|
|
|
|
|
|
function refreshDisplay() {
|
|
function refreshDisplay() {
|
|
|
|
|
|
geomController.updateDisplay();
|
|
geomController.updateDisplay();
|
|
splitController.updateDisplay();
|
|
splitController.updateDisplay();
|
|
- smoothController.updateDisplay();
|
|
|
|
|
|
+ uvSmoothController.updateDisplay();
|
|
|
|
+ preserveController.updateDisplay();
|
|
|
|
|
|
updateMeshes();
|
|
updateMeshes();
|
|
|
|
|
|
@@ -159,7 +168,7 @@
|
|
return new THREE.ConeGeometry( 0.6, 1.5, 5, 3 );
|
|
return new THREE.ConeGeometry( 0.6, 1.5, 5, 3 );
|
|
|
|
|
|
case 'cylinder':
|
|
case 'cylinder':
|
|
- return new THREE.CylinderGeometry( 0.5, 0.5, 1, 5, 5 );
|
|
|
|
|
|
+ return new THREE.CylinderGeometry( 0.5, 0.5, 1, 5, 4 );
|
|
|
|
|
|
case 'dodecahedron':
|
|
case 'dodecahedron':
|
|
return new THREE.DodecahedronGeometry( 0.6 );
|
|
return new THREE.DodecahedronGeometry( 0.6 );
|
|
@@ -175,8 +184,8 @@
|
|
|
|
|
|
for ( let i = 0; i < 65; i += 5 ) {
|
|
for ( let i = 0; i < 65; i += 5 ) {
|
|
|
|
|
|
- let x = ( Math.sin( i * 0.2 ) * Math.sin( i * 0.1 ) * 15 + 50 ) * 1.2;
|
|
|
|
- let y = ( i - 5 ) * 3;
|
|
|
|
|
|
+ const x = ( Math.sin( i * 0.2 ) * Math.sin( i * 0.1 ) * 15 + 50 ) * 1.2;
|
|
|
|
+ const y = ( i - 5 ) * 3;
|
|
points.push( new THREE.Vector2( x * 0.0075, y * 0.005 ) );
|
|
points.push( new THREE.Vector2( x * 0.0075, y * 0.005 ) );
|
|
|
|
|
|
}
|
|
}
|
|
@@ -214,14 +223,8 @@
|
|
function updateMeshes() {
|
|
function updateMeshes() {
|
|
|
|
|
|
const normalGeometry = getGeometry();
|
|
const normalGeometry = getGeometry();
|
|
- const smoothGeometry = LoopSubdivision.modify(
|
|
|
|
- normalGeometry,
|
|
|
|
- params.iterations,
|
|
|
|
- params.split,
|
|
|
|
- params.uvSmooth,
|
|
|
|
- params.flatOnly,
|
|
|
|
- params.maxTriangles
|
|
|
|
- );
|
|
|
|
|
|
+
|
|
|
|
+ const smoothGeometry = LoopSubdivision.modify( normalGeometry, params.iterations, params );
|
|
|
|
|
|
meshNormal.geometry.dispose();
|
|
meshNormal.geometry.dispose();
|
|
meshSmooth.geometry.dispose();
|
|
meshSmooth.geometry.dispose();
|
|
@@ -233,6 +236,71 @@
|
|
wireNormal.geometry = normalGeometry.clone();
|
|
wireNormal.geometry = normalGeometry.clone();
|
|
wireSmooth.geometry = smoothGeometry.clone();
|
|
wireSmooth.geometry = smoothGeometry.clone();
|
|
|
|
|
|
|
|
+ updateMaterial();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function disposeMaterial( material ) {
|
|
|
|
+
|
|
|
|
+ const materials = Array.isArray( material ) ? material : [ material ];
|
|
|
|
+
|
|
|
|
+ for ( let i = 0; i < materials.length; i ++ ) {
|
|
|
|
+
|
|
|
|
+ if ( materials[ i ].dispose ) materials[ i ].dispose();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function updateMaterial() {
|
|
|
|
+
|
|
|
|
+ disposeMaterial( meshNormal.material );
|
|
|
|
+ disposeMaterial( meshSmooth.material );
|
|
|
|
+
|
|
|
|
+ const materialParams = {
|
|
|
|
+ color: ( params.textured ) ? 0xffffff : 0x808080,
|
|
|
|
+ flatShading: params.flatShading,
|
|
|
|
+ map: ( params.textured ) ? texture : null,
|
|
|
|
+ polygonOffset: true,
|
|
|
|
+ polygonOffsetFactor: 1, // positive value pushes polygon further away
|
|
|
|
+ polygonOffsetUnits: 1
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ switch ( params.geometry.toLowerCase() ) {
|
|
|
|
+
|
|
|
|
+ case 'circle':
|
|
|
|
+ case 'lathe':
|
|
|
|
+ case 'plane':
|
|
|
|
+ case 'ring':
|
|
|
|
+
|
|
|
|
+ materialParams.side = THREE.DoubleSide;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 'box':
|
|
|
|
+ case 'capsule':
|
|
|
|
+ case 'cone':
|
|
|
|
+ case 'cylinder':
|
|
|
|
+ case 'dodecahedron':
|
|
|
|
+ case 'icosahedron':
|
|
|
|
+ case 'octahedron':
|
|
|
|
+ case 'sphere':
|
|
|
|
+ case 'tetrahedron':
|
|
|
|
+ case 'torus':
|
|
|
|
+ case 'torusknot':
|
|
|
|
+
|
|
|
|
+ materialParams.side = THREE.FrontSide;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ meshNormal.material = meshSmooth.material = new THREE.MeshStandardMaterial( materialParams );
|
|
|
|
+
|
|
|
|
+ render();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function updateWireframe() {
|
|
|
|
+
|
|
wireNormal.visible = wireSmooth.visible = params.wireframe;
|
|
wireNormal.visible = wireSmooth.visible = params.wireframe;
|
|
|
|
|
|
render();
|
|
render();
|