-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #496 from 3DStreet/bevel-option-svg-extrude
add bevel and second material support
- Loading branch information
Showing
1 changed file
with
116 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,164 @@ | ||
/* global AFRAME */ | ||
var { SVGLoader } = require('../lib/SVGLoader.js'); | ||
const { SVGLoader } = require('../lib/SVGLoader.js'); | ||
|
||
AFRAME.registerComponent('svg-extruder', { | ||
schema: { | ||
svgString: { type: 'string' }, | ||
depth: { type: 'number', default: 4 } | ||
depth: { type: 'number', default: 4 }, | ||
bevelEnabled: { type: 'boolean', default: false }, | ||
bevelThickness: { type: 'number', default: 1 }, | ||
bevelSize: { type: 'number', default: 1 }, | ||
bevelOffset: { type: 'number', default: 1 }, | ||
bevelSegments: { type: 'number', default: 1 }, | ||
topElement: { type: 'boolean', default: false }, | ||
color: { type: 'color', default: 'white'}, | ||
src: { type: 'string', default: '#grass-texture'}, | ||
bevelColor: { type: 'color', default: 'grey'}, | ||
bevelSrc: { type: 'string', default: ''}, | ||
lineColor: { type: 'color', default: 'black'} | ||
}, | ||
init: function () { | ||
const data = this.data; | ||
const el = this.el; | ||
const svgString = this.data.svgString; | ||
const svgString = data.svgString; | ||
const lineColor = data.lineColor; | ||
this.loader = new SVGLoader(); | ||
|
||
this.stokeMaterial = new THREE.LineBasicMaterial({ | ||
color: '#00A5E6' | ||
el.removeAttribute('material'); | ||
el.setAttribute('shadow', 'cast: true; receive: true'); | ||
}, | ||
createTopEntity: function (topGeometryArray) { | ||
const data = this.data; | ||
let topElement = this.el.children[0]; | ||
// remove existing topElement. It could be getting from loaded JSON | ||
if (!topElement) { | ||
topElement = document.createElement('a-entity'); | ||
topElement.classList.add('topElement'); | ||
this.el.appendChild(topElement); | ||
} | ||
|
||
// merge shape geometries into one mergedGeometry | ||
const mergedGeometry = this.mergedGeometryFromArray(topGeometryArray); | ||
|
||
mergedGeometry.translate(0, 0.15, 0); | ||
|
||
// create a mesh with the shape geometry | ||
const mergedShapeMesh = new THREE.Mesh(mergedGeometry, | ||
this.materialFromSrc(data.src, data.color)); | ||
|
||
if (topElement.getObject3D('mesh')) { | ||
topElement.removeObject3D('mesh'); | ||
} | ||
topElement.setObject3D('mesh', mergedShapeMesh); | ||
|
||
//topElement.setAttribute('material', `src:${data.src};roughness:1;repeat: 0.01 0.01`); | ||
|
||
}, | ||
materialFromSrc: function (imgSrc, color) { | ||
let texture = null; | ||
// create material with texture from img element with id imgSrc | ||
const textureImg = (imgSrc !== '') ? document.querySelector(imgSrc): null; | ||
if (textureImg) { | ||
// create texture from img element | ||
texture = new THREE.Texture(textureImg); | ||
|
||
texture.encoding = THREE.sRGBEncoding; | ||
|
||
// set repeat property for texture | ||
texture.wrapS = THREE.RepeatWrapping; | ||
texture.wrapT = THREE.RepeatWrapping; | ||
texture.repeat.set(0.01, 0.01); | ||
} | ||
|
||
const material = new THREE.MeshStandardMaterial({ | ||
color: color, map: texture, roughness: 1 | ||
}); | ||
if (material.map) material.map.needsUpdate = true; | ||
return material; | ||
}, | ||
mergedGeometryFromArray: function (geometryArray) { | ||
// Merge array of extruded geometries into the mergedGeometry | ||
const mergedGeometry = | ||
THREE.BufferGeometryUtils.mergeGeometries(geometryArray); | ||
|
||
// set scale for extruded svg | ||
el.setAttribute('shadow', 'cast: true; receive: true'); | ||
mergedGeometry.computeBoundingBox(); | ||
mergedGeometry.computeVertexNormals(); | ||
mergedGeometry.center(); | ||
mergedGeometry.rotateX(Math.PI / 2); | ||
mergedGeometry.scale(0.05, 0.05, 0.05); | ||
|
||
return mergedGeometry; | ||
}, | ||
extrudeFromSVG: function (svgString) { | ||
const depth = this.data.depth; | ||
const data = this.data; | ||
const el = this.el; | ||
const svgData = this.loader.parse(svgString); | ||
const fillMaterial = new THREE.MeshStandardMaterial(); | ||
|
||
const extrudeSettings = { | ||
depth: depth, | ||
bevelEnabled: false | ||
depth: data.depth, | ||
bevelEnabled: data.bevelEnabled, | ||
bevelThickness: data.bevelThickness, | ||
bevelSize: data.bevelSize, | ||
bevelOffset: data.bevelOffset, | ||
bevelSegments: data.bevelSegments | ||
}; | ||
|
||
const shapeGeometryArray = []; | ||
const extrudedGeometryArray = []; | ||
const topGeometryArray = []; | ||
|
||
svgData.paths.forEach((path) => { | ||
const shapes = SVGLoader.createShapes(path); | ||
|
||
shapes.forEach((shape) => { | ||
const topGeometry = new THREE.ExtrudeGeometry(shape, {depth: 1, bevelEnabled: false}); | ||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); | ||
shapeGeometryArray.push(geometry); | ||
topGeometryArray.push(topGeometry); | ||
extrudedGeometryArray.push(geometry); | ||
}); | ||
}); | ||
|
||
// Merge array of extruded geometries into the mergedGeometry | ||
const mergedGeometry = | ||
THREE.BufferGeometryUtils.mergeBufferGeometries(shapeGeometryArray); | ||
const mergedGeometry = this.mergedGeometryFromArray(extrudedGeometryArray); | ||
|
||
mergedGeometry.computeBoundingBox(); | ||
mergedGeometry.computeVertexNormals(); | ||
mergedGeometry.center(); | ||
mergedGeometry.rotateX(Math.PI / 2); | ||
mergedGeometry.scale(0.05, 0.05, 0.05); | ||
const stokeMaterial = new THREE.LineBasicMaterial({ | ||
color: data.lineColor | ||
}); | ||
|
||
// create edges geometries and line segments from mergedGeometry | ||
const linesGeometry = new THREE.EdgesGeometry(mergedGeometry); | ||
const lines = new THREE.LineSegments(linesGeometry, this.stokeMaterial); | ||
const lines = new THREE.LineSegments(linesGeometry, stokeMaterial); | ||
|
||
el.setObject3D('lines', lines); | ||
|
||
// Finally, create a mesh with the merged geometry | ||
const mergedMesh = new THREE.Mesh(mergedGeometry, fillMaterial); | ||
const mergedMesh = new THREE.Mesh(mergedGeometry, | ||
this.materialFromSrc(data.bevelSrc, data.bevelColor) | ||
); | ||
|
||
// remove existing mesh from entity | ||
el.removeObject3D('mesh'); | ||
if (el.getObject3D('mesh')) { | ||
el.removeObject3D('mesh'); | ||
} | ||
el.setObject3D('mesh', mergedMesh); | ||
|
||
//el.setAttribute('material', `src:${data.bevelSrc};roughness:1;repeat: 0.1 0.1`); | ||
|
||
const topElement = this.el.children[0]; | ||
if (data.topElement) { | ||
// create entity from shapes for top level of extruded geometry | ||
this.createTopEntity(topGeometryArray); | ||
} else if (topElement) { | ||
el.removeChild(topElement); | ||
} | ||
|
||
}, | ||
update: function (oldData) { | ||
// If `oldData` is empty, then this means we're in the initialization process. | ||
// No need to update. | ||
// if (Object.keys(oldData).length === 0) { return; } | ||
//if (Object.keys(oldData).length === 0) { return; } | ||
|
||
const el = this.el; | ||
const svgString = this.data.svgString; | ||
|
||
if (svgString) { | ||
this.extrudeFromSVG(svgString); | ||
if (!el.getAttribute('material')) { | ||
// applies the default mixin material grass. If the element's material is not set via setAttribute | ||
el.setAttribute('material', 'src:#grass-texture;roughness:1;repeat: 0.01 0.01'); | ||
} | ||
} | ||
if (svgString) this.extrudeFromSVG(svgString); | ||
} | ||
|
||
}); |