|
// BASICS |
|
// Autodesk.Viewing.Document |
|
// Autodesk.Viewing.BubbleNode |
|
// Autodesk.Viewing.Model |
|
|
|
// Autodesk.Viewing.InstanceTree is an object for query nodes. |
|
const tree = model.getInstanceTree(); |
|
tree.enumNodeChildren(tree.getRootId(), (nodeId) => { |
|
tree.enumNodeFragments(nodeId, (fragId) => { |
|
const fragProxy = viewer.impl.getRenderProxy(model, fragId); |
|
}, true); // recursive: true |
|
}, true); // recursive: true |
|
|
|
viewer.impl.scene.add(mesh); |
|
viewer.impl.sceneUpdated(true); // update things that have been changed |
|
viewer.impl.invalidate(true); // reprocess the entire scene |
|
// In case of materials, using invalidated() is preferable because |
|
// the material list is outside the scene. |
|
viewer.impl.getMaterials().addMaterial('superMaterial', material, true); |
|
viewer.impl.matman().addMaterial('superMaterial', material, true); |
|
viewer.impl.getFragmentProxy(model, fragId); |
|
|
|
viewer.setThemingColor(dbId, new THREE.Vector4(1, 0, 0, 1)); |
|
function setMaterial(viewer, dbIds, material) { |
|
const model = viewer.model; |
|
model.unconsolidate(); |
|
const tree = model.getInstanceTree(); |
|
const frags = model.getFragmentList(); |
|
} |
|
|
|
|
|
// Autodesk.Viewing.Model model; |
|
const model = NOP_VIEWER.model; |
|
model.getInstanceTree(); |
|
model.getFragmentList(); |
|
model.getGeometryList(); |
|
model.getGeomScenes(); |
|
model.getData(); // geometry data |
|
model.getDocumentNode(); |
|
model.getRoot(); |
|
model.getRootId(); |
|
model.getMetadata(itemName, subitemName, defaultValue); |
|
model.getPropertyDb(); |
|
model.getProperties(dbId, onSuccessCallback, onErrorCallback); |
|
model.getProperties2(dbId, onSuccessCallback, onErrorCallback, { |
|
needsExternalId: false |
|
}); |
|
model.getBulkProperties(dbIds, options, onSuccessCallback, onErrorCallback); |
|
model.getBulkProperties2(dbIds, options, onSuccessCallback, onErrorCallback); |
|
model.getPropertySetAsync(dbIds, options) |
|
.then(function(propertySet) { |
|
propertySet.forEach(function(key, properties) { |
|
/* ,,, */ |
|
}); |
|
}); |
|
|
|
// PROPERTY OBJECT |
|
{ |
|
attributeName: 'Category', |
|
dbId: 42, |
|
displayCategory: '__document__', |
|
displayName: 'Category', |
|
displayValue: 'Revit Document', |
|
hidden: 1, |
|
parentName: 'Model', |
|
precision: 0, |
|
type: 20, |
|
unit: null |
|
} |
|
|
|
|
|
// HOW TO OPEN A DOCUMENT |
|
Autodesk.Viewing.Viewer3D.loadModel(urn, options, |
|
onSuccessCallback, onFailureCallback); |
|
Autodesk.Viewing.Viewer3D.loadDocumentNode( |
|
Autodesk.Viewing.Document doc, Autodesk.Viewing.BubbleNode manifestNode, |
|
options); |
|
// METHOD A |
|
Autodesk.Viewing.Document.load( |
|
modelUrn, onDocumentLoadedSuccess, onDocumentLoadedFailure); |
|
function onDocumentLoadedSuccess(doc) { |
|
const defaultModel = doc.getRoot().getDefaultModel(); |
|
viewer.loadDocumentNode(doc, defaultModel); // wraps loadModel() |
|
// SVF2 models |
|
const url = doc.getViewablePath(defaultModel); |
|
viewer.loadModel(url, { acmSessionId: doc.getAcmSessionId(url) }); |
|
} |
|
function onDocumentLoadedFailure() {} |
|
// METHOD B |
|
|
|
|
|
// METHOD C |
|
let doc = new Autodesk.Viewing.Document(dataJSON, path, acmSession); |
|
// acmSession is required to load a SVF2 modeil |
|
fetch('http://localhost:3000/api/forge/modelderivate/<urn>/manifest') |
|
.then((res) => { |
|
res.json().then((body) => { |
|
doc = new Autodesk.Viewing.Document(body, 'urn:' + urn); |
|
let defaultModel = doc.getRoot().search({ |
|
type: 'geometry', role: '3d', isMasterView: true |
|
}); |
|
// getDefaultGeometry(searchMasterView, loadLargestView); |
|
defaultModel = doc.getRoot().getDefaultGeometry(true); |
|
if (manifestNodes.length > 0) { |
|
viewer.loadDocumentNode(doc, manifestNodes[0]); |
|
} |
|
}); |
|
}) |
|
|
|
|
|
Autodesk.Viewing.Document.load( |
|
modelUrn, onSuccessCallback, onFailureCallback, options); // a static method |
|
|
|
function onSuccessCallback(doc) { |
|
// Autodesk.Viewing.BubbleNode |
|
const bubbleNodeRoot = doc.getRoot(); |
|
const lmvDoc = bubbleNodeRoot.lmvDocument; |
|
} |
|
|
|
|
|
|
|
|
|
// HOW TO REGISTER AN EXTENSION |
|
(function() { |
|
'use strict' |
|
function MyExtension(viewer, options) { |
|
Autodesk.Viewing.Extension.call(this, viewer, options); |
|
} |
|
MyExtension.prototype = Object.create(Autodesk.Viewing.Extension.prototype); |
|
MyExtension.prototype.constructor = MyExtension; |
|
let proto = MyExtension.prototype; |
|
proto.load = function() { |
|
console.log("My extension loaded!"); |
|
return true; |
|
} |
|
proto.unload = function() { |
|
console.log("My extension unloaded"); |
|
return true; |
|
} |
|
Autodesk.Viewing.theExtensionManager.registerExtension( |
|
'MyExtension', MyExtension); |
|
})(); |
|
|
|
viewer.loadExtension('MyExtension') |
|
.then((ext) => { |
|
console.log("success"); |
|
}) |
|
.catch((err) => { |
|
console.error(err); |
|
}); |
|
|
|
NOP_VIEWER.isExtensionLoaded('MyExtension'); |
|
NOP_VIEWER.loadExtension('MyExtension'); |
|
NOP_VIEWER.loadExtension('Autodesk.DocumentBrowser'); // 2D & 3D viewables |
|
NOP_VIEWER.unloadExtension('MyExtension'); |
|
|
|
// HOW TO ADD A BUTTON |
|
viewer.loadDocumentNode(doc, items[0]) |
|
.then(function(model) { |
|
let group = viewer.toolbar.getControl('randomName'); |
|
if (!group) { |
|
group = new Autodesk.Viewing.UI.ControlGroup('randomName'); |
|
viewer.toolbar.addControl(group); |
|
} |
|
button = new Autodesk.Viewing.UI.Button('printButton'); |
|
button.setIcon('adsk-icon-layers'); |
|
button.onClick = () => { |
|
foo(viewer); |
|
}; |
|
button.setToolTip('Print Sheet'); |
|
group.addControl(button); |
|
}); |
|
|
|
|
|
// added AEC data to models translated from Revit |
|
function onDocumentLoadSuccess(doc) { |
|
let defaultModel = doc.getRoot().getDefaultGeometry(); |
|
doc.downloadAecModelData(); |
|
viewer.loadDocumentNode(doc, defaultModel); |
|
} |
|
const aecData = viewer.model.getDocumentNode().getAecModelData(); |
|
|
|
|
|
// HOW TO ADD A CUSTOM GEOMETRY |
|
// 1. Create a custom geometry |
|
let geometry = new THREE.SphereGeometry(10, 8, 8); |
|
let material = new THREE.MeshBasicMaterial({ color: 0x0000ff }); |
|
let mesh = new THREE.Mesh(sphereGeom, meshMaterial); |
|
|
|
// 2. Create an overlay scene |
|
const sceneName = 'customScene'; |
|
if (!viewer.overlays.hasScene(sceneName)) { |
|
viewer.overlays.addScene(sceneName); |
|
} |
|
|
|
// 3. Add the custom geometry to the scene |
|
viewer.overlays.addMesh(mesh, sceneName); |
|
|
|
// 4. Do the clean-up |
|
viewer.overlays.removeMesh(mesh, sceneName); |
|
viewer.overlays.removeScene(sceneName); |
|
meshMaterial.dispose(); |
|
sphereGeom.dispose(); |
|
|
|
|
|
// HOW TO QUERY THE PROPERTY DATABASE (Autodesk.Globals.PropertyDatabase) |
|
// the function must be named userFunction |
|
function userFunction(pdb) { |
|
pdb.enumAttribtes(function(i, attrDef, attrRaw) { |
|
}); |
|
pdb.enumObjects(function(dbId) { |
|
pdb.enumObjectProperties(dbId, function(attrId, valId) { |
|
const attrDef = pdb.getAttributeDef(attrId); |
|
const attrVal = pdb.getAttrValue(attrId, valId); |
|
|
|
}); |
|
}); |
|
return 42; |
|
}); |
|
|
|
viewer.model |
|
.getPropertyDb() |
|
.executeUserFunction(userFunction) |
|
.then((result) => { }) |
|
.catch((err) => console.error(err)); |
|
|
|
// Since version 7.0.0 |
|
function userFunction(pdb, userData) { |
|
|
|
} |
|
viewer.model |
|
.getPropertyDb() |
|
.executeUserFunction(userFunction, userData) |
|
.then((result) => { }) |
|
.catch((error) => { }) |
|
|
|
// SELECTION |
|
viewer.getSelection(); // [928, 42, 23] |
|
viewer.select([42, 191]); |
|
|
|
|
|
function onSelectionChanged(event) { |
|
const dbId = event.dbIdArray[0]; |
|
if (dbId) { |
|
NOP_VIEWER.model.getProperties(dbId, (result) => { |
|
_externalId = result.externalId; |
|
}); |
|
} |
|
handleSelectionChangeed(event.fragIdsArray); |
|
} |
|
|
|
|
|
// ACCESSING METADATA WITHOUT THE VIEWER |
|
// 1. GET :urn/metadata/:guid/properties |
|
// 2. Sqlite database |
|
// GET :urn/manifest |
|
// sqlite> .tables |
|
// sqlite> PRAGMA table_info(_objects_attr); |
|
// sqlite> .schema _objects_eav |
|
// sqlite> .headers on |
|
// sqlite> .mode column |
|
/* |
|
** _objects_attr |
|
** id | INTEGER |
|
** name | TEXT |
|
** category | TEXT |
|
** data_type | INTEGER |
|
** data_type_context | TEXT |
|
** description | TEXT |
|
** display_name | TEXT |
|
** flags | INTEGER |
|
** display_precision | INTEGER |
|
** forge_parameter | TEXT |
|
*/ |
|
/* |
|
** _objects_eav |
|
** id | INTEGER |
|
** entity_id | INTEGER |
|
** attribute_id | INTEGER |
|
** value_id | INTEGER |
|
*/ |
|
|
|
/* |
|
** _objects_id |
|
** id | INTEGER |
|
** external_id | BLOB |
|
** viewable_id | BLOB |
|
*/ |
|
|
|
/* |
|
** _objects_val |
|
** id | INTEGER |
|
** value | BLOB |
|
*/ |
|
|
|
/* 3. Viewer-optimised database |
|
** objects_attr.json.gz |
|
** objects_avs.json.gz |
|
** objects_ids.json.gz |
|
** objects_vals.json.gz |
|
*/ |
|
|
|
SELECT id.external_id, id.viewable_id, attr.name, attr.category, val.value |
|
FROM (((_objects_eav AS eav JOIN _objects_attr AS attr ON eav.attribute_id = attr.id) |
|
JOIN _objects_val AS val ON eav.value_id = val.id) |
|
JOIN _objects_id as id ON eav.entity_id = id.id) |
|
|
|
|
|
/* |
|
** HOW TO FIND ALL FAMILY TYPE INSTANCES BASED ON THE TYPE'S UNIQUE ID |
|
*/ |
|
SELECT val.value |
|
FROM (((_objects_eav AS eav JOIN _objects_attr AS attr |
|
ON eav.attribute_id = attr.id) |
|
JOIN _objects_val AS val ON eav.value_id = val.id) |
|
JOIN _objects_id as id ON eav.entity_id = id.id) |
|
WHERE id.external_id LIKE '705%1bef' |
|
AND attr.category LIKE '__child__'; |
|
|
|
//SELECT id.external_id, id.viewable_id, attr.name, attr.category, val.value |
|
SELECT * |
|
FROM (((_objects_eav AS eav JOIN _objects_attr AS attr ON eav.attribute_id = attr.id) |
|
JOIN _objects_val AS val ON eav.value_id = val.id) |
|
JOIN _objects_id as id ON eav.entity_id = id.id) |
|
WHERE attr.category LIKE '__parent__' |
|
LIMIT 5; |
|
|
|
|
|
// SELECT ALL INFO ABOUT |
|
SELECT * FROM (((_objects_id AS id JOIN _objects_eav AS eav ON id.id = eav.entity_id) JOIN _objects_val AS val ON val.id = eav.value_id) JOIN _objects_attr AS attr ON attr.id = eav.attribute_id) WHERE val.value = 'Furniture'; |
|
|
|
|
|
// CODE SNIPPETS |
|
var viewer; |
|
var objectIds = []; |
|
|
|
function launchViewer(urn, object_id) { |
|
objectIds = []; |
|
objectIds.push( object_id); |
|
|
|
var options = { |
|
env: 'AutodeskProduction2', |
|
api: 'streamingV2', |
|
getAccessToken |
|
}; |
|
|
|
Autodesk.Viewing.Initializer(options, function onInitialized() { |
|
viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer')); |
|
viewer.start(); |
|
var documentId = 'urn:' + urn; |
|
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure); |
|
}); |
|
} |
|
|
|
|
|
function onDocumentLoadSuccess(doc) { |
|
var viewables = doc.getRoot().getDefaultGeometry(); |
|
viewer.loadDocumentNode(doc, viewables).then( async (model) => { |
|
// Highlight the takeoff element after geometry is loaded |
|
await Autodesk.Viewing.EventUtils.waitUntilGeometryLoaded(viewer); |
|
viewer.isolate(objectIds); |
|
viewer.fitToView(objectIds); |
|
}); |
|
} |
|
|
|
|
|
function onDocumentLoadFailure(viewerErrorCode) { |
|
console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode); |
|
} |
|
|
|
async function getAccessToken(callback) { |
|
const resp = await fetch('/api/forge/oauth/token'); |
|
if (resp.ok) { |
|
const { access_token, expires_in } = await resp.json(); |
|
callback(access_token, expires_in); |
|
} else { |
|
alert('Could not obtain access token. See the console for more details.'); |
|
console.error(await resp.text()); |
|
} |
|
} |
|
|
|
/* |
|
** VIEWER EXTENSIONS: TIPS AND TRICKS |
|
*/ |
|
|
|
// EXTENSION LOADING |
|
Autodesk.Viewing.theExtensionManager |
|
.registerExtension('FooExtensionId', FooExtension); |
|
|
|
// Method A |
|
const viewer = new Autodesk.Viewing.GuiViewer3D( |
|
container, { extension: ['FooExtensionId'] }); |
|
// Method B |
|
const viewer = new Autodesk.Viewing.GuiViewer3D(container); |
|
viewer.loadExtension('FooExtensionId'); |
|
// Method C |
|
Autodesk.Viewing.theExtensionManager.registerExternalExtension( |
|
'FooExtensionId', 'https://foo.fohlio.com/public/FooExtension.js'); |
|
const viewer = new Autodesk.Viewing.GuiViewer3D( |
|
container, { extensions: ['FooExtensionId'] }); |
|
|
|
// PASSING OPTIONS TO EXTENSIONS |
|
viewer.loadExtension('FooExtensionId', { passcode: 'Fido' }); |
|
// ... |
|
constructor(viewer, options) { |
|
super(viewer, options); |
|
console.log(options.passcode); // 'Fido' |
|
} |
|
// ... |
|
const viewer = new Autodesk.Viewing.GuiViewer3D(container, { |
|
extensions: ['FooExtensionId'], |
|
fooExtOptions: { passcode: 'Fido' } |
|
}); |
|
// ... |
|
constructor(viewer, options) { |
|
super(viewer, options); |
|
console.log(options.fooExtOptions); // { passcode: 'Fido' } |
|
} |
|
// ... |
|
|
|
// ASYNC LOADING AND UNLOADING |
|
async load() { |
|
const loadScript = (src) => new Promise(function(resolve, reject) { |
|
const el = document.createElement('script'); |
|
el.src = src; |
|
el.onload = resolve; |
|
el.onerror = reject; |
|
document.head.appendChild(el); |
|
}); |
|
const loadCSS = (href) => new Promise(function(resolve, reject) { |
|
const el = document.createElement('link'); |
|
el.rel = 'stylesheet'; |
|
el.href = href; |
|
el.onload = resolve; |
|
el.onerror = reject; |
|
document.head.appendChild(el); |
|
}); |
|
await Promise.all([ |
|
this.viewer.loadExtension('SomeOtherExtension'), |
|
loadScript('https://foo.fohlio.com/public/js/foo.js'), |
|
loadCSS('https://foo.fohlio.com/public/css/foo.css') |
|
]); |
|
return true; |
|
} |
|
|
|
// EXTENSION STATE |
|
class FooExtension extends Autodesk.Viewing.Extension { |
|
// ... |
|
getState(state) { |
|
state['fooExtState'] = state['fooExtState'] || {}; |
|
state['fooExtState'].passcode = 'Fido'; |
|
} |
|
|
|
restoreState(state) { |
|
const fooExtState = state['fooExtState'] || {}; |
|
this.passcode = fooExtState.passcode || ''; |
|
} |
|
// ... |
|
} |
|
|
|
// PROXYING THE FORGE VIEWER |
|
const options = { |
|
shouldInitializeAuth: false, |
|
endpoint: 'http://localhost:3000/forge/api/viewer-proxy', |
|
}; |
|
|
|
const FORGE_HOST = 'https://developer.api.autodesk.com'; |
|
router.use('/viewer-proxy/*', function(req, res) { |
|
try { |
|
if (userAllowedToAccessResource(req)) { |
|
const headers = { |
|
'Authorization': 'Bearer ' + actualForgeToken |
|
}; |
|
fetch(FORGE_HOST + req.path, { headers }) |
|
.then((res) => { return res.buffer }) |
|
.then((buffer) => { return res.send(buffer); }) |
|
.catch((err) => { res.status(400).send(err);}); |
|
} else { |
|
res.status(401).end(); |
|
} |
|
} catch (err) { |
|
console.error(err); |
|
res.status(500).send(err.message); |
|
} |
|
}); |
|
|
|
|
|
/* |
|
** LABELING |
|
*/ |
|
// HTML ELEMENTS on top of the model (SVG, DIV) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// AEC DATA |
|
doc.downloadAecModelData(); |
|
|
|
// viewports |
|
// let cameraPos = viewports[0].cameraOrienataion; |
|
// cameraPos[0] - cameraPos[2] => the camera's forward direction |
|
// cameraPos[3] - cameraPos[5] => the camera's up vector |
|
// cameraPos[6] - cameraPos[8] => the camera's origin (eye point) |
|
// let viewportPos = viewports[0].viewportPosition; |
|
// viewportPos[0] - viewportPos[2] => the viewport's low-left corner |
|
// viewportPos[3] - viewportPos[5] => the viewport's upper-right corner |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// DATA VISUALIZATION API |
|
const dataVizExt = await viewer.loadExtension('Autodesk.DataVisualization'); |
|
// modelInfo.getRoomList().then((rooms) => {}); |
|
// modelInfo.getLevel(room); // returns string |
|
// modelInfo.getLevelRoomsMap().then((levelRooms) => {}); |
|
function createHeatmapForRooms(dataVizExt, model) { |
|
const modelInfo = new Autodesk.DataVisualization |
|
.Core.ModelStructureInfo(model); |
|
let promise = modelInfo.getRoomList(); |
|
promise = promise |
|
.then((rooms) => { |
|
const devices = []; |
|
rooms.forEach((room) => { |
|
const centroid = room.bounds.getCenter(); |
|
devices.push({ |
|
id: room.name, |
|
position: { x: centroid.x, y: centroid.y, z: room.bounds.min.z }, |
|
sensorType: ['temperature', 'humidity'] |
|
}); |
|
}); |
|
return Promise.resolve(devices); |
|
}); |
|
promise.then((devices) => { |
|
modelInfo.generateSurfaceShadingData(devices) |
|
.then((shadingData) => { |
|
dataVizExt.setupSurfaceShading(model, shadingData) |
|
.then(() => { |
|
const sensorColors = [ 0x0000ff, 0x00ff00, 0xff0000 ]; |
|
const sensorType = 'temperature'; |
|
dataVizExt.registerSurfaceShadingColors(sensorType, sensorColors); |
|
function getSensorValue(surfaceShadingPoint, sensorType) { |
|
const deviceId = surfaceShadingPoint.id; |
|
let sensorValue = readSensorValue(deviceId, sensorType); |
|
const maxSensorValue = getMaxSensorValue(sensorType); |
|
const minSensorValue = getMinSensorValue(sensorType); |
|
sensorValue = (sensorValue - minSensorValue) / |
|
(maxSensorValue - sensorValue); |
|
return clamp(sensorValue, 0.0, 1.0); |
|
} |
|
modelInfo.getLevelRoomsMap() |
|
.then((levelRooms) => { |
|
Object.keys(levelRooms).forEach((levelName) => { |
|
dataVizExt.renderSurfaceShading( |
|
levelName, sensorType, getSensorValue); |
|
}); |
|
}); |
|
}); |
|
}); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
// THREE.js |
|
// mesh => geometry + material |
|
// scene => meshes + lights |
|
// renderScene => scene + camera |
|
// Prefer THREE.BufferGeometry to THREE.Geometry; |
|
function essentialSetups() { |
|
const scene = new THREE.Scene(); |
|
|
|
const axes = new THREE.AxisHelper(20); |
|
scene.add(axes); |
|
let geometry = new THREE.PlaneGeometry(60, 20, 1, 1); |
|
geometry = new THREE.CubeGeometry(42, 42, 42); |
|
geometry = new THREE.SphereGeometry(4, 20, 20); |
|
|
|
let material = new THREE.MeshBasicMaterial({ |
|
color: 0xff0000, wireframe: true |
|
}); |
|
material = new THREE.MeshLambertMaterial({ |
|
color: 0xff0000 |
|
}); |
|
|
|
let mesh = new THREE.Mesh(geometry, material); |
|
mesh.castShadow = true; // only for MeshLambertMaterials |
|
mesh.position.set(10, 10, 0); |
|
scene.add(mesh); |
|
|
|
const spotLight = new THREE.SpotLight(0xffffff); |
|
spotLight.position.set(10, 10, 20); |
|
scene.add(spotLight); |
|
|
|
const camera = new THREE.PerspectiveCamera( |
|
45, window.innderWidth / window.innerHeight, 0.1, 1000); |
|
camera.position.set(-30, 40, 30); |
|
camera.lookAt(scene.position); |
|
|
|
const renderer = new THREE.WebGLRenderer(); |
|
renderer.setClearColor(new THREE.Color(0xeeeeee)); |
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
renderer.shadowMapEnabled = true; // for calculating shadows |
|
function renderScene() { |
|
requestAnimationFramer(renderScene); |
|
renderer.render(scene, camera); |
|
} |
|
$('#viewer').append(renderer.domElement); |
|
renderScene(); |
|
} |
|
|
|
|
|
// THREE.Scene |
|
const scene = new THREE.Scene(); |
|
scene.add(mesh); |
|
scene.children; |
|
scene.getChildByName(name); |
|
scene.remove(mesh); |
|
scene.traverse((child) => { |
|
if (child instanceof THREE.Mesh) ; |
|
}); |
|
scene.fog = new THREE.Fog(0xffffff, 0.015, 100); |
|
scene.overrideMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); |
|
|
|
// THREE.Geometry |
|
// A geometry is a collection of points (vertices) and a number of faces |
|
// connecting all those points |
|
// THREE.SphereGeometry |
|
// THREE.CubeGeometry |
|
const vertices = [ |
|
new THREE.Vector3(1, 3, 1), |
|
new THREE.Vector3(-1, 3, 1), |
|
new THREE.Vector3(0, 0, 0), |
|
]; |
|
const faces = [ |
|
new THREE.Face3(0, 1, 2); // creates a face by joining vertice 0, 1, and 2 |
|
]; |
|
|
|
|
|
/* THREE.Geometry IS OBSOLETE; USE THREE.BufferGeometry */ |
|
let geometry = THREE.Geometry(); |
|
geometry.vertices = vertices; |
|
geometry.faces = faces; |
|
geometry.computeCentroids(); |
|
geometry.mergeVertices(); |
|
function renderScene() { |
|
mesh.geometry.vertices = vertices; |
|
mesh.geometry.verticesNeedUpdate = true; |
|
mesh.geometry.computeFaceNormals(); |
|
} |
|
|
|
|
|
// THREE.Mesh (Only THREE.mesh can be rendered) |
|
const mesh = new THREE.Mesh(geometry, material); |
|
const meshes = THREE.SceneUtils.createMultiMaterialObject(geometry, materials); |
|
const line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ |
|
color: 0xff0000, linewidth: 2 |
|
})); |
|
// Method A |
|
mesh.position.x = 42; |
|
mesh.position.y = 42; |
|
mesh.position.z = 42; |
|
mesh.rotation.x = 0.5 * Math.PI; |
|
mesh.scale.x = 1.2; |
|
mesh.translateX(10); // move the mesh relative to its current positon |
|
mesh.translateY(10); |
|
mesh.translateZ(10); |
|
// Method B |
|
mesh.position.set(42, 42, 42); |
|
mesh.rotation.set(0.5 * Math.PI, 0, 0); |
|
mesh.scale.set(1.2, 0, 0); |
|
// Method 3 |
|
mesh.position = new THREE.Vector3(42, 42, 42); |
|
mesh.rotation = new THREE.Vector3(0.5 * Math.PI, 0, 0); |
|
mesh.scale = new THREE.Vector3(1.2, 0, 0); |
|
|
|
// THREE.Camera |
|
let camera = new THREE.PerspectiveCamera(fov, aspect, near, far); |
|
camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far); |
|
camera.lookAt(new THREE.Vector(x, y, z)); |
|
|
|
|
|
// THREE.JS LIGHT SOURCES |
|
let ambientLight = new THREE.AmbientLight( // does not case shadows |
|
new THREE.Color('#0c0c0c')); |
|
scene.add(ambientLight); |
|
|
|
let pointLight = new THREE.PointLight( |
|
new THREE.Color('#ccffcc')); |
|
pointLight.distance = 100; |
|
pointLigth.intensity = 1; |
|
pointLight.position.set(0, 1, 3); |
|
scene.add(pointLight); |
|
|
|
// THREE.JS MATERIALS |
|
LineBasicMaterial |
|
LineDashedMaterial |
|
new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true }); |
|
new THREE.MeshNormalMaterial({ side: THREE.DoubleSide }); |
|
let meshes = THREE.SceneUtils.createMultiMaterialObject( |
|
geometry, [meshMaterial, wireframeMaterial] |
|
); |
|
|
|
// THREE.JS GEOMETRIES |
|
// 2D |
|
const geometry = new THREE.Geometry(); |
|
geometry.vertices.push(new THREE.Vector3(-10, 0, 0)); |
|
geometry.vertices.push(new THREE.Vector3(0, 10, 0)); |
|
geometry.vertices.push(new THREE.Vector3(10, 0, 0)); |
|
const line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0xff0000 })); |
|
const plane = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments); |
|
const circle = new THREE.CircleGeometry(radius, segments, thetaStart, thetaLength); |
|
function drawShape() { |
|
const shape = new THREE.Shape(); |
|
shape.moveTo(x, y); |
|
shape.lineTo(x, y); |
|
shape.quadraticCurveTo(aCPx, aCPy, x, y); |
|
shape.bezierCurveTo(aCPx1, aCPy1, aCPx2, aCPy2, x, y); |
|
shape.splineThru([ |
|
new THREE.Vector2(32, 30), |
|
new THREE.Vector2(28, 20), |
|
new THREE.Vector2(30, 10) |
|
]); |
|
shape.arc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise); |
|
shape.absArc(aX, aY, aRadius, sStartAngle, aEndAngle, aClockwise); |
|
shape.ellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise); |
|
shape.absellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise); |
|
return shape; |
|
} |
|
const shapeGeometry = new THREE.ShapeGeometry(drawShape()); |
|
|
|
// 3D |
|
const cube = new THREE.CubeGeometry(widthX, heightY, depthZ, |
|
widthSegments = 1, heightSegments = 1, |
|
depthSegments = 1); |
|
const sphere = new THREE.SphereGeometry(radius = 5, |
|
widthSegment = 8, heightSegments = 6, |
|
phiStart = 0, phiLength = 2 * Math.PI, |
|
thetaStart = 0, thetaLength = Math.PI); |
|
const cylinder = new THREE.CylinderGeometry(radiusTop = 20, radiusBottom = 20, |
|
height = 100, segmentsX = 8, |
|
segmentsY = 1, openEnded = false); |
|
const torus = new THREE.TorusGeometry(radius = 100, tube = 40, radialSegments = 8, |
|
tubularSegments = 6, arc = 2 * Math.PI); |
|
const torusKnot = new THREE.TorusKnotGeometry(radius = 100, tube = 40, |
|
radialSegments = 64, |
|
tubularSegments = 8, |
|
p = 2, q = 3, heightScale = 1); |
|
const polyhedron = new THREE.PolyhedronGeometry(vertices, faces, radius = 1, |
|
details = 1); |
|
const octahedron = new THREE.OctahedronGeometry(); |
|
const tetrahedron = new THREE.TetrahedronGeometry(); |
|
const convex = new THREE.ConvexGeometry(); |
|
const lathe = new THREE.LatheGeometry(); |
|
const extrude = new THREE.ExtrudeGeometry(); |
|
const tube = new THREE.TubeGeometry(); |
|
const parametric = new THREE.ParametricGeometry(); |
|
const text = new THREE.TextGeometry(); |
|
// Convert a ttf font into typeface.js |
|
// gero3.github.io/facetype.js/ c:\windows\fonts |
|
// self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; |
|
// <script src="js/arialRegular.facetype.js"></script> |
|
let geometry = new THREE.TextGeometry('Foo', { |
|
font: 'arial', |
|
weight: 'normal', |
|
style: 'normal', |
|
size: 25, |
|
height: 5, |
|
curveSegments: 3 |
|
}); |
|
|
|
// LOADING GEOMETERIES FROM EXTERNAL RESOURCES |
|
// JSON |
|
// <script src="GeometryExporter.js"></script> |
|
function saveGeometryLocally(key, geometry) { |
|
const exporter = new THREE.GeometryExporter(); |
|
const parsedGeometry = exporter.parse(geometry); |
|
localStorage.setItem(key, JSON.stringify(parsedGeometry)); |
|
} |
|
|
|
function loadGeometryBack(key) { |
|
const result = localStorage.getItem(key); |
|
if (!result) { return null; } |
|
const geomJson = JSON.parse(result); |
|
const loader = new THREE.JSONLoader(); |
|
return loader.parse(geomJson); |
|
} |
|
|
|
// <script src="SceneExporter.js"></script> |
|
function saveSceneLocally(key, scene) { |
|
const exporter = new THREE.SceneExporter(); |
|
const parsedGeometry = exporter.parse(scene); |
|
const sceneJson = JSON.stringify(parsedGeometry); |
|
localStorage.setItem(key, sceneJson); |
|
} |
|
|
|
function localSceneBack(key) { |
|
const sceneJson = localStorage.getItem(key); |
|
if (!sceneJson) { return null; } |
|
const loader = new THREE.SceneLoader(); |
|
sceneLoader.parse(JSON.parse(sceneJson), function (e) { |
|
scene = e.scene; |
|
}, '.'); // '.' defines the relative URL for other assets such as images |
|
} |
|
|