123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- import * as THREE from 'three';
- import {threejsLessonUtils} from './threejs-lesson-utils.js';
- {
- function makeSphere(widthDivisions, heightDivisions) {
- const radius = 7;
- return new THREE.SphereGeometry(radius, widthDivisions, heightDivisions);
- }
- const highPolySphereGeometry = function() {
- const widthDivisions = 100;
- const heightDivisions = 50;
- return makeSphere(widthDivisions, heightDivisions);
- }();
- const lowPolySphereGeometry = function() {
- const widthDivisions = 12;
- const heightDivisions = 9;
- return makeSphere(widthDivisions, heightDivisions);
- }();
- function smoothOrFlat(flatShading, radius = 7) {
- const widthDivisions = 12;
- const heightDivisions = 9;
- const geometry = new THREE.SphereGeometry(radius, widthDivisions, heightDivisions);
- const material = new THREE.MeshPhongMaterial({
- flatShading,
- color: 'hsl(300,50%,50%)',
- });
- return new THREE.Mesh(geometry, material);
- }
- function basicLambertPhongExample(MaterialCtor, lowPoly, params = {}) {
- const geometry = lowPoly ? lowPolySphereGeometry : highPolySphereGeometry;
- const material = new MaterialCtor({
- color: 'hsl(210,50%,50%)',
- ...params,
- });
- return {
- obj3D: new THREE.Mesh(geometry, material),
- trackball: lowPoly,
- };
- }
- function sideExample(side) {
- const base = new THREE.Object3D();
- const size = 6;
- const geometry = new THREE.PlaneGeometry(size, size);
- [
- { position: [ -1, 0, 0], up: [0, 1, 0], },
- { position: [ 1, 0, 0], up: [0, -1, 0], },
- { position: [ 0, -1, 0], up: [0, 0, -1], },
- { position: [ 0, 1, 0], up: [0, 0, 1], },
- { position: [ 0, 0, -1], up: [ 1, 0, 0], },
- { position: [ 0, 0, 1], up: [-1, 0, 0], },
- ].forEach((settings, ndx) => {
- const material = new THREE.MeshBasicMaterial({side});
- material.color.setHSL(ndx / 6, .5, .5);
- const mesh = new THREE.Mesh(geometry, material);
- mesh.up.set(...settings.up);
- mesh.lookAt(...settings.position);
- mesh.position.set(...settings.position).multiplyScalar(size * .75);
- base.add(mesh);
- });
- return base;
- }
- function makeStandardPhysicalMaterialGrid(elem, physical, update) {
- const numMetal = 5;
- const numRough = 7;
- const meshes = [];
- const MatCtor = physical ? THREE.MeshPhysicalMaterial : THREE.MeshStandardMaterial;
- const color = physical ? 'hsl(160,50%,50%)' : 'hsl(140,50%,50%)';
- for (let m = 0; m < numMetal; ++m) {
- const row = [];
- for (let r = 0; r < numRough; ++r) {
- const material = new MatCtor({
- color,
- roughness: r / (numRough - 1),
- metalness: 1 - m / (numMetal - 1),
- });
- const mesh = new THREE.Mesh(highPolySphereGeometry, material);
- row.push(mesh);
- }
- meshes.push(row);
- }
- return {
- obj3D: null,
- trackball: false,
- render(renderInfo) {
- const {camera, scene, renderer} = renderInfo;
- const rect = elem.getBoundingClientRect();
- const width = (rect.right - rect.left) * renderInfo.pixelRatio;
- const height = (rect.bottom - rect.top) * renderInfo.pixelRatio;
- const left = rect.left * renderInfo.pixelRatio;
- const bottom = (renderer.domElement.clientHeight - rect.bottom) * renderInfo.pixelRatio;
- const cellSize = Math.min(width / numRough, height / numMetal) | 0;
- const xOff = (width - cellSize * numRough) / 2;
- const yOff = (height - cellSize * numMetal) / 2;
- camera.aspect = 1;
- camera.updateProjectionMatrix();
- if (update) {
- update(meshes);
- }
- for (let m = 0; m < numMetal; ++m) {
- for (let r = 0; r < numRough; ++r) {
- const x = left + xOff + r * cellSize;
- const y = bottom + yOff + m * cellSize;
- renderer.setViewport(x, y, cellSize, cellSize);
- renderer.setScissor(x, y, cellSize, cellSize);
- const mesh = meshes[m][r];
- scene.add(mesh);
- renderer.render(scene, camera);
- scene.remove(mesh);
- }
- }
- },
- };
- }
- threejsLessonUtils.addDiagrams({
- smoothShading: {
- create() {
- return smoothOrFlat(false);
- },
- },
- flatShading: {
- create() {
- return smoothOrFlat(true);
- },
- },
- MeshBasicMaterial: {
- create() {
- return basicLambertPhongExample(THREE.MeshBasicMaterial);
- },
- },
- MeshLambertMaterial: {
- create() {
- return basicLambertPhongExample(THREE.MeshLambertMaterial);
- },
- },
- MeshPhongMaterial: {
- create() {
- return basicLambertPhongExample(THREE.MeshPhongMaterial);
- },
- },
- MeshBasicMaterialLowPoly: {
- create() {
- return basicLambertPhongExample(THREE.MeshBasicMaterial, true);
- },
- },
- MeshLambertMaterialLowPoly: {
- create() {
- return basicLambertPhongExample(THREE.MeshLambertMaterial, true);
- },
- },
- MeshPhongMaterialLowPoly: {
- create() {
- return basicLambertPhongExample(THREE.MeshPhongMaterial, true);
- },
- },
- MeshPhongMaterialShininess0: {
- create() {
- return basicLambertPhongExample(THREE.MeshPhongMaterial, false, {
- color: 'red',
- shininess: 0,
- });
- },
- },
- MeshPhongMaterialShininess30: {
- create() {
- return basicLambertPhongExample(THREE.MeshPhongMaterial, false, {
- color: 'red',
- shininess: 30,
- });
- },
- },
- MeshPhongMaterialShininess150: {
- create() {
- return basicLambertPhongExample(THREE.MeshPhongMaterial, false, {
- color: 'red',
- shininess: 150,
- });
- },
- },
- MeshBasicMaterialCompare: {
- create() {
- return basicLambertPhongExample(THREE.MeshBasicMaterial, false, {
- color: 'purple',
- });
- },
- },
- MeshLambertMaterialCompare: {
- create() {
- return basicLambertPhongExample(THREE.MeshLambertMaterial, false, {
- color: 'black',
- emissive: 'purple',
- });
- },
- },
- MeshPhongMaterialCompare: {
- create() {
- return basicLambertPhongExample(THREE.MeshPhongMaterial, false, {
- color: 'black',
- emissive: 'purple',
- shininess: 0,
- });
- },
- },
- MeshToonMaterial: {
- create() {
- return basicLambertPhongExample(THREE.MeshToonMaterial);
- },
- },
- MeshStandardMaterial: {
- create(props) {
- return makeStandardPhysicalMaterialGrid(props.renderInfo.elem, false);
- },
- },
- MeshPhysicalMaterial: {
- create(props) {
- const settings = {
- clearcoat: .5,
- clearcoatRoughness: 0,
- };
- function addElem(parent, type, style = {}) {
- const elem = document.createElement(type);
- Object.assign(elem.style, style);
- parent.appendChild(elem);
- return elem;
- }
- function addRange(elem, obj, prop, min, max) {
- const outer = addElem(elem, 'div', {
- width: '100%',
- textAlign: 'center',
- 'font-family': 'monospace',
- });
- const div = addElem(outer, 'div', {
- textAlign: 'left',
- display: 'inline-block',
- });
- const label = addElem(div, 'label', {
- display: 'inline-block',
- width: '12em',
- });
- label.textContent = prop;
- const num = addElem(div, 'div', {
- display: 'inline-block',
- width: '3em',
- });
- function updateNum() {
- num.textContent = obj[prop].toFixed(2);
- }
- updateNum();
- const input = addElem(div, 'input', {
- });
- Object.assign(input, {
- type: 'range',
- min: 0,
- max: 100,
- value: (obj[prop] - min) / (max - min) * 100,
- });
- input.addEventListener('input', () => {
- obj[prop] = min + (max - min) * input.value / 100;
- updateNum();
- });
- }
- const {elem} = props.renderInfo;
- addRange(elem, settings, 'clearcoat', 0, 1);
- addRange(elem, settings, 'clearcoatRoughness', 0, 1);
- const area = addElem(elem, 'div', {
- width: '100%',
- height: '400px',
- });
- return makeStandardPhysicalMaterialGrid(area, true, (meshes) => {
- meshes.forEach(row => row.forEach(mesh => {
- mesh.material.clearcoat = settings.clearcoat;
- mesh.material.clearcoatRoughness = settings.clearcoatRoughness;
- }));
- });
- },
- },
- MeshDepthMaterial: {
- create(props) {
- const {camera} = props;
- const radius = 4;
- const tube = 1.5;
- const radialSegments = 8;
- const tubularSegments = 64;
- const p = 2;
- const q = 3;
- const geometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q);
- const material = new THREE.MeshDepthMaterial();
- camera.near = 7;
- camera.far = 20;
- return new THREE.Mesh(geometry, material);
- },
- },
- MeshNormalMaterial: {
- create() {
- const radius = 4;
- const tube = 1.5;
- const radialSegments = 8;
- const tubularSegments = 64;
- const p = 2;
- const q = 3;
- const geometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q);
- const material = new THREE.MeshNormalMaterial();
- return new THREE.Mesh(geometry, material);
- },
- },
- sideDefault: {
- create() {
- return sideExample(THREE.FrontSide);
- },
- },
- sideDouble: {
- create() {
- return sideExample(THREE.DoubleSide);
- },
- },
- });
- }
|