Skip to content

Commit

Permalink
Examples: Add external subdivision demo (#24397)
Browse files Browse the repository at this point in the history
* Added example file

* Added subdivision example

* Added subdivision example

* Added subdivision screenshot

* Fixed subdivision screenshot

* Improved wireframe in example

* Tabs

* Fix version and dispose

* Wrong directory, oops

* Fix version and dispose
  • Loading branch information
stevinz authored Aug 24, 2022
1 parent 87de750 commit 4279f3e
Show file tree
Hide file tree
Showing 4 changed files with 263 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
"webgl_modifier_curve_instanced",
"webgl_modifier_edgesplit",
"webgl_modifier_simplifier",
"webgl_modifier_subdivision",
"webgl_modifier_tessellation",
"webgl_morphtargets",
"webgl_morphtargets_face",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/tags.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"webgl_math_orientation_transform": [ "rotation" ],
"webgl_mirror": [ "reflection" ],
"webgl_portal": [ "frameCorners", "renderTarget" ],
"webgl_modifier_subdivision" : [ "external", "community", "smooth" ],
"webgl_morphtargets_horse": [ "animation" ],
"webgl_multiple_elements": [ "differential equations", "physics" ],
"webgl_multiple_elements_text": [ "font" ],
Expand Down
261 changes: 261 additions & 0 deletions examples/webgl_modifier_subdivision.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - modifier - subdivision</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>

<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - modifier - <a href="https://github.com/stevinz/three-subdivide" target="_blank" rel="noopener">subdivision</a><br/>
See external <a href="https://github.com/stevinz/three-subdivide" target="_blank" rel="noopener">three-subdivide</a> for more information on subdivision surfaces.
</div>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three-subdivide": "https://unpkg.com/[email protected]/build/index.module.js"
}
}
</script>

<script type="module">

import * as THREE from 'three';
import { LoopSubdivision } from 'three-subdivide';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { GUI } from './jsm/libs/lil-gui.module.min.js';

let renderer, scene, camera;
let texture;
let meshMaterial, meshNormal, meshSmooth;
let wireMaterial, wireNormal, wireSmooth;

const params = {
geometry: 'Box',
iterations: 3,
split: true,
uvSmooth: false,
flatOnly: false,
maxTriangles: 25000,
wireframe: false
};

init();

function init() {

renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight );
camera.position.set( 0, 0.7, 2.1 );

const controls = new OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render ); // use if there is no animation loop
controls.rotateSpeed = 0.5;
controls.minZoom = 1;
controls.target.set( 0, 0, 0 );
controls.update();

texture = new THREE.TextureLoader().load( './textures/uv_grid_opengl.jpg', () => {

texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;

render();

} );

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.position.set( - 0.7, 0, 0 );
meshSmooth.position.set( 0.7, 0, 0 );
scene.add( meshNormal, meshSmooth );

wireMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, depthTest: true, wireframe: true } );
wireNormal = new THREE.Mesh( new THREE.BufferGeometry(), wireMaterial );
wireSmooth = new THREE.Mesh( new THREE.BufferGeometry(), wireMaterial );
wireNormal.visible = false;
wireSmooth.visible = false;
wireNormal.position.copy( meshNormal.position );
wireSmooth.position.copy( meshSmooth.position );
scene.add( wireNormal, wireSmooth );

updateMeshes();

window.addEventListener( 'resize', onWindowResize );

const geomTypes = [ 'Box', 'Capsule', 'Circle', 'Cone', 'Cylinder', 'Dodecahedron', 'Icosahedron', 'Lathe', 'Octahedron', 'Plane', 'Ring', 'Sphere', 'Tetrahedron', 'Torus', 'TorusKnot' ];

const gui = new GUI();

const folder1 = gui.addFolder( 'Subdivide Params' );
const geomController = folder1.add( params, 'geometry', geomTypes ).onFinishChange( () => {

const geom = params.geometry.toLowerCase();

params.split = geom === 'box' || geom === 'ring';
params.uvSmooth = geom === 'circle' || geom === 'plane' || geom === 'ring';

refreshDisplay();

} );

folder1.add( params, 'iterations' ).min( 0 ).max( 5 ).step( 1 ).onFinishChange( updateMeshes );
const splitController = folder1.add( params, 'split' ).onFinishChange( updateMeshes );
const smoothController = folder1.add( params, 'uvSmooth' ).onFinishChange( updateMeshes );
folder1.add( params, 'flatOnly' ).onFinishChange ( updateMeshes );
folder1.add( params, 'maxTriangles' ).onFinishChange( updateMeshes );

const folder2 = gui.addFolder( 'View' );
folder2.add( params, 'wireframe' ).onFinishChange( updateMeshes );

function refreshDisplay() {

geomController.updateDisplay();
splitController.updateDisplay();
smoothController.updateDisplay();

updateMeshes();

}

}

function getGeometry() {

switch ( params.geometry.toLowerCase() ) {

case 'box':
return new THREE.BoxGeometry();

case 'capsule':
return new THREE.CapsuleGeometry( 0.5, 0.5, 3, 5 );

case 'circle':
return new THREE.CircleGeometry( 0.6, 10 );

case 'cone':
return new THREE.ConeGeometry( 0.6, 1.5, 5, 3 );

case 'cylinder':
return new THREE.CylinderGeometry( 0.5, 0.5, 1, 5, 5 );

case 'dodecahedron':
return new THREE.DodecahedronGeometry( 0.6 );

case 'icosahedron':
return new THREE.IcosahedronGeometry( 0.6 );

case 'lathe':

// Sine Wave

const points = [];

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;
points.push( new THREE.Vector2( x * 0.0075, y * 0.005 ) );

}

const latheGeometry = new THREE.LatheGeometry( points, 4 );
latheGeometry.center();

return latheGeometry;

case 'octahedron':
return new THREE.OctahedronGeometry( 0.7 );

case 'plane':
return new THREE.PlaneGeometry();

case 'ring':
return new THREE.RingGeometry( 0.3, 0.6, 10 );

case 'sphere':
return new THREE.SphereGeometry( 0.6, 8, 4 );

case 'tetrahedron':
return new THREE.TetrahedronGeometry( 0.8 );

case 'torus':
return new THREE.TorusGeometry( 0.48, 0.24, 4, 6 );

case 'torusknot':
return new THREE.TorusKnotGeometry( 0.38, 0.18, 20, 4 );

}

}

function updateMeshes() {

const normalGeometry = getGeometry();
const smoothGeometry = LoopSubdivision.modify(
normalGeometry,
params.iterations,
params.split,
params.uvSmooth,
params.flatOnly,
params.maxTriangles
);

meshNormal.geometry.dispose();
meshSmooth.geometry.dispose();
meshNormal.geometry = normalGeometry;
meshSmooth.geometry = smoothGeometry;

wireNormal.geometry.dispose();
wireSmooth.geometry.dispose();
wireNormal.geometry = normalGeometry.clone();
wireSmooth.geometry = smoothGeometry.clone();

wireNormal.visible = wireSmooth.visible = params.wireframe;

render();

}

function onWindowResize() {

renderer.setSize( window.innerWidth, window.innerHeight );

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

render();

}

function render() {

renderer.render( scene, camera );

}

</script>

</body>
</html>

0 comments on commit 4279f3e

Please sign in to comment.