Created
August 15, 2016 15:56
-
-
Save killroy42/79d7db820a354a97d6674e7e061adcb7 to your computer and use it in GitHub Desktop.
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
function extrudeProfileOnPath(profileVs, outlineVs, sharedUVs) { | |
/* | |
TODO: | |
- if sharedUVs == false, create multiple UV layers | |
- Smooth according to edge angles | |
- Accept Shapes/CurvePaths directly | |
- Don't scale UVs along profile. Reuse reference profile | |
*/ | |
var upVector = new THREE.Vector3(0, 1, 0); | |
var backVector = new THREE.Vector3(0, 0, -1); | |
var outlineCount = outlineVs.length; | |
var profileCount = profileVs.length; | |
var profileVertices, verticeIndices, outlineLengths, profileLengths, uvs; | |
var geo = new THREE.Geometry(); | |
var uvLayer = 0; | |
function capFront() { | |
var i, a, b, c = geo.vertices.length; | |
// Calculate bounds | |
var bounds = new THREE.Box3(); | |
for(i = 0; i < outlineCount; i++) { | |
a = (i + 1) * profileCount - 1; | |
bounds.expandByPoint(geo.vertices[a]); | |
} | |
geo.vertices.push(bounds.center()); | |
// Faces and UVs | |
var size = bounds.size(); | |
var center = bounds.center(); | |
var uvOffset = new THREE.Vector2(0.5, 0.5); | |
var centerOffset = new THREE.Vector2(center.x, - center.y); | |
var uvScale = new THREE.Vector2(1 / size.x, 1 / size.y); | |
if(sharedUVs) { | |
uvScale.multiplyScalar(0.5); | |
uvOffset.add(new THREE.Vector2(-0.25, 0.25)); | |
} | |
for(i = 0; i < outlineCount; i++) { | |
a = (i + 1) * profileCount - 1; | |
b = (((i + 1) % outlineCount) + 1) * profileCount - 1; | |
geo.faces.push(new THREE.Face3(a, c, b)); | |
geo.faceVertexUvs[uvLayer][geo.faces.length - 1] = [ | |
geo.vertices[a].clone().add(centerOffset).multiply(uvScale).add(uvOffset), | |
geo.vertices[c].clone().add(centerOffset).multiply(uvScale).add(uvOffset), | |
geo.vertices[b].clone().add(centerOffset).multiply(uvScale).add(uvOffset) | |
]; | |
} | |
} | |
function capBack() { | |
var i, a, b, c = geo.vertices.length; | |
// Calculate bounds | |
var bounds = new THREE.Box3(); | |
for(i = 0; i < outlineCount; i++) { | |
a = i * profileCount; | |
bounds.expandByPoint(geo.vertices[a]); | |
} | |
geo.vertices.push(bounds.center()); | |
// Faces and UVs | |
var size = bounds.size(); | |
var center = bounds.center(); | |
var uvOffset = new THREE.Vector2(0.5, 0.5); | |
var centerOffset = new THREE.Vector2(center.x, - center.y); | |
var uvScale = new THREE.Vector2(-1 / size.x, 1 / size.y); | |
if(sharedUVs) { | |
uvScale.multiplyScalar(0.5); | |
uvOffset.add(new THREE.Vector2(0.25, 0.25)); | |
} | |
for(i = 0; i < outlineCount; i++) { | |
a = i * profileCount; | |
b = ((i + 1) % outlineCount) * profileCount; | |
geo.faces.push(new THREE.Face3(a, b, c)); | |
geo.faceVertexUvs[uvLayer][geo.faces.length - 1] = [ | |
geo.vertices[a].clone().add(centerOffset).multiply(uvScale).add(uvOffset), | |
geo.vertices[b].clone().add(centerOffset).multiply(uvScale).add(uvOffset), | |
geo.vertices[c].clone().add(centerOffset).multiply(uvScale).add(uvOffset) | |
]; | |
} | |
} | |
function computeOutlineLengths() { | |
outlineLengths = []; | |
for(var pIdx = 0; pIdx < profileCount; pIdx++) { | |
outlineLengths[pIdx] = 0; | |
for(var oIdx = 0; oIdx < outlineCount; oIdx++) { | |
var dist = profileVertices[oIdx][pIdx] | |
.distanceTo(profileVertices[(oIdx+1) % outlineCount][pIdx]); | |
outlineLengths[pIdx] += dist; | |
} | |
} | |
} | |
function computeProfileLengths() { | |
profileLengths = []; | |
for(var oIdx = 0; oIdx < outlineCount; oIdx++) { | |
profileLengths[oIdx] = 0; | |
for(var pIdx = 0; pIdx < profileCount-1; pIdx++) { | |
var dist = profileVertices[oIdx][pIdx] | |
.distanceTo(profileVertices[oIdx][pIdx+1]); | |
profileLengths[oIdx] += dist; | |
} | |
} | |
} | |
function createProfileVertices() { | |
var oIdx, pIdx, vertex, v0, v1, v2, va, vb, vab, scaleV, ang, a, b, c; | |
profileVertices = []; | |
verticeIndices = []; | |
for(oIdx = 0; oIdx < outlineCount; oIdx++) { | |
a = (oIdx + outlineCount - 1) % outlineCount; | |
b = oIdx; | |
c = (oIdx + 1) % outlineCount; | |
v0 = outlineVs[a].clone(); v0.z = 0; | |
v1 = outlineVs[b].clone(); v1.z = 0; | |
v2 = outlineVs[c].clone(); v2.z = 0; | |
va = v1.clone().sub(v0).normalize(); | |
vb = v2.clone().sub(v1).normalize(); | |
vab = va.clone().add(vb).normalize(); | |
vab.set(-vab.y, vab.x, vab.z); // Rotate by 90 degrees clockwise | |
ang = upVector.angleTo(vab); if(vab.x < 0) ang = -ang; | |
scaleV = new THREE.Vector3(1, 1 / Math.sin(vab.angleTo(va)), 1); | |
profileVertices[oIdx] = []; | |
verticeIndices[oIdx] = []; | |
for(pIdx = 0; pIdx < profileCount; pIdx++) { | |
vertex = profileVs[profileCount - pIdx - 1].clone() | |
.multiply(scaleV) | |
.applyAxisAngle(backVector, ang) | |
.add(outlineVs[oIdx]); | |
profileVertices[oIdx][pIdx] = vertex; | |
verticeIndices[oIdx][pIdx] = geo.vertices.push(vertex) - 1; | |
} | |
} | |
} | |
function computeUVs() { | |
var oIdx, pIdx, uvA, uvB, uvC, uvD, a, b, c, d; | |
uvs = []; | |
for(oIdx = 0; oIdx <= outlineCount; oIdx++) { | |
uvs[oIdx] = []; | |
for(pIdx = 0; pIdx < profileCount; pIdx++) { | |
uvs[oIdx][pIdx] = new THREE.Vector2(0, 0); | |
} | |
} | |
for(oIdx = 0; oIdx < outlineCount; oIdx++) { | |
for(pIdx = 0; pIdx < profileCount-1; pIdx++) { | |
uvA = uvs[(oIdx + 0)][(pIdx + 0)]; | |
uvB = uvs[(oIdx + 1)][(pIdx + 0)]; | |
uvC = uvs[(oIdx + 1)][(pIdx + 1)]; | |
uvD = uvs[(oIdx + 0)][(pIdx + 1)]; | |
a = verticeIndices[(oIdx + 0) % outlineCount][(pIdx + 0) % profileCount]; | |
b = verticeIndices[(oIdx + 1) % outlineCount][(pIdx + 0) % profileCount]; | |
c = verticeIndices[(oIdx + 1) % outlineCount][(pIdx + 1) % profileCount]; | |
d = verticeIndices[(oIdx + 0) % outlineCount][(pIdx + 1) % profileCount]; | |
var ab = geo.vertices[a].distanceTo(geo.vertices[b]); | |
uvB.x = uvA.x + ab; | |
var ad = geo.vertices[a].distanceTo(geo.vertices[d]); | |
uvD.y = uvA.y + ad; | |
var dc = geo.vertices[d].distanceTo(geo.vertices[c]); | |
var bc = geo.vertices[b].distanceTo(geo.vertices[c]); | |
uvC.x = uvD.x + dc; | |
uvC.y = uvB.y + bc; | |
} | |
} | |
for(oIdx = 0; oIdx <= outlineCount; oIdx++) { | |
for(pIdx = 0; pIdx < profileCount; pIdx++) { | |
uvs[oIdx][pIdx].multiply(new THREE.Vector2( | |
1 / outlineLengths[pIdx % profileCount], | |
1 / profileLengths[oIdx % outlineCount] | |
)); | |
uvs[oIdx][pIdx].y = 1 - uvs[oIdx][pIdx].y; | |
if(sharedUVs) { | |
uvs[oIdx][pIdx].multiply(new THREE.Vector2(1, 0.5)); | |
} | |
} | |
} | |
} | |
function createProfileFaces() { | |
var oIdx, pIdx, segA, segB, a, b, c, d; | |
var faceA, faceB, fIdxA, fIdxB; | |
var uvA, uvB, uvC, uvD; | |
for(oIdx = 0; oIdx < outlineCount; oIdx++) { | |
for(pIdx = 0; pIdx < profileCount - 1; pIdx++) { | |
a = verticeIndices[(oIdx + 0) % outlineCount][(pIdx + 0) % profileCount]; | |
b = verticeIndices[(oIdx + 1) % outlineCount][(pIdx + 0) % profileCount]; | |
c = verticeIndices[(oIdx + 1) % outlineCount][(pIdx + 1) % profileCount]; | |
d = verticeIndices[(oIdx + 0) % outlineCount][(pIdx + 1) % profileCount]; | |
faceA = new THREE.Face3(a, c, b); | |
fIdxA = geo.faces.push(faceA) - 1; | |
faceB = new THREE.Face3(a, d, c); | |
fIdxB = geo.faces.push(faceB) - 1; | |
// UVs | |
uvA = uvs[(oIdx + 0)][(pIdx + 0)]; | |
uvB = uvs[(oIdx + 1)][(pIdx + 0)]; | |
uvC = uvs[(oIdx + 1)][(pIdx + 1)]; | |
uvD = uvs[(oIdx + 0)][(pIdx + 1)]; | |
geo.faceVertexUvs[uvLayer][fIdxA] = [uvA, uvC, uvB]; | |
geo.faceVertexUvs[uvLayer][fIdxB] = [uvA, uvD, uvC]; | |
} | |
} | |
} | |
if(sharedUVs === undefined) sharedUVs = true; | |
geo.faceVertexUvs[uvLayer] = []; | |
createProfileVertices(); | |
computeOutlineLengths(); | |
computeProfileLengths(); | |
computeUVs(); | |
createProfileFaces(); | |
capFront(profileVs, outlineVs, geo); | |
capBack(profileVs, outlineVs, geo); | |
geo.uvsNeedUpdate = true; | |
geo.computeFaceNormals(); | |
return geo; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment