Last active
September 22, 2019 20:26
-
-
Save erikparr/a0bef15944534d6fe11451e7cf27fa5b to your computer and use it in GitHub Desktop.
This file contains hidden or 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 NurbsRibbon(strokeTexture) { | |
this.loadedCurvePts = []; | |
this.nurbsKnots = []; | |
this.nurbsDegree = 3; | |
this.nurbsControlPoints = []; | |
this.resolution = 100; | |
this.drawSpeed = 50; | |
this.spline; | |
this.segmentPoints; | |
this.numCtrlPts = 5; | |
this.drawIndex = 0; | |
this.drawLoadedCurve = false; | |
this.linePts = []; | |
this.curveLength = 200; | |
this.isInited = false; | |
this.drawSpeedScalar = 0.17; | |
this.lineGroup; | |
this.nurbsGeometry; | |
this.nurbsLine; | |
this.interpolate = false; | |
this.numInterplPts = 5; | |
this.boundaryAreaSize = 0.5; | |
} | |
var colors = [ | |
new THREE.Color(0xff66a8), | |
new THREE.Color(0xdf2dff), | |
new THREE.Color(0x6d1eff), | |
new THREE.Color(0xa72dff), | |
new THREE.Color(0xf0b5b3), | |
new THREE.Color(0x00ff00), | |
new THREE.Color(0x000000), | |
new THREE.Color(0xffffff) | |
]; | |
NurbsRibbon.prototype.init = function(texture) { | |
this.material = new MeshLineMaterial({ | |
map: texture, | |
useMap: true, | |
lineWidth: 0.075, | |
near: 1, | |
far: 100000, | |
depthTest: false, | |
opacity: 1, | |
blending: THREE.NormalBlending, | |
transparent: true, | |
side: THREE.DoubleSide, | |
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight), | |
color: colors[Math.floor(Math.random()*colors.length)] | |
}); | |
this.nurbsGeometry = new THREE.Geometry(); | |
this.nurbsGeometry.setFromPoints(this.linePts); | |
var position = new THREE.Vector3(); | |
for (var i = 0; i < this.curveLength; i++) { | |
// must initialize it to the number of positions it will keep or it will throw an error | |
this.nurbsGeometry.vertices.push(position.clone()); | |
} | |
this.nurbsLine = new MeshLine(); | |
this.nurbsLine.setGeometry(this.nurbsGeometry, function(p) { | |
return p; | |
}); | |
//put the ribbon line in a group | |
this.lineGroup = new THREE.Group(); | |
this.lineMesh = new THREE.Mesh(this.nurbsLine.geometry, this.material); // this syntax could definitely be improved! | |
this.lineMesh.frustumCulled = false; | |
this.lineGroup.add(this.lineMesh); | |
// init the nurbs array with some points | |
for (var i = 0; i < this.numCtrlPts; i++) { | |
var ranPt = new THREE.Vector4( | |
this.boundaryAreaSize * (Math.random() * 2 - 1), | |
this.boundaryAreaSize * (Math.random() * 2 - 1), | |
this.boundaryAreaSize * (Math.random() * 2 - 1), | |
1 | |
); | |
this.nurbsControlPoints.push(ranPt); | |
} | |
// scene.add(this.lineGroup); | |
this.AddNewCurve(); | |
}; | |
NurbsRibbon.prototype.update = function() { | |
// linePts stores the windowed segments points for drawing the curve | |
var point = this.segmentPoints[this.drawIndex]; | |
this.nurbsLine.advance(point); | |
this.linePts.push(point); | |
this.drawIndex++; | |
// new curve when finished drawing current curve | |
if (this.drawIndex >= this.resolution) { | |
this.drawIndex = 0; | |
if (this.drawLoadedCurve) { | |
console.log("draw curve from data"); | |
this.addInterpolationPts(); | |
this.AddNewCurve(this.loadedCurvePts); | |
} else { | |
this.AddNewCurve(); | |
} | |
} | |
}; | |
NurbsRibbon.prototype.AddNewCurve = function(curvePts) { | |
console.log("add new curve"); | |
console.log("line group size: " + this.lineGroup.children.length); | |
var drawPoints = []; | |
//last two points used to calculate transition to new curve | |
var curPt = this.nurbsControlPoints[this.nurbsControlPoints.length - 1]; | |
var lastPt = this.nurbsControlPoints[this.nurbsControlPoints.length - 2]; | |
var lastMidPt = new THREE.Vector4( | |
(curPt.x + lastPt.x) / 2, | |
(curPt.y + lastPt.y) / 2, | |
(curPt.z + lastPt.z) / 2, | |
1 // strength of curve | |
); | |
//add first two points of new curve based on previous curve | |
this.nurbsControlPoints.length = 0; //reset | |
this.nurbsControlPoints.push(lastMidPt); | |
this.nurbsControlPoints.push(curPt); | |
//fill the control point list with curve data points or if none exist, random points | |
if (curvePts != null) { | |
// this.drawLoadedCurve = false; | |
for (var i = 0; i <= curvePts.length - 2; i++) { | |
this.nurbsControlPoints.push(curvePts[i]); | |
} | |
//calculate resolution (draw speed) of curve | |
this.resolution = | |
this.drawSpeed * this.drawSpeedScalar * this.nurbsControlPoints.length; | |
//remove any interpolation points added to our nurbs curve data | |
if (this.interpolate) this.removeInterpolationPts(); | |
} else { | |
for ( | |
var i = 0; | |
i <= this.numCtrlPts - this.nurbsControlPoints.length; | |
i++ | |
) { | |
var ranCtrlPt = new THREE.Vector4( | |
this.boundaryAreaSize * (Math.random() * 2 - 1), | |
this.boundaryAreaSize * (Math.random() * 2 - 1), | |
this.boundaryAreaSize * (Math.random() * 2 - 1), | |
1 | |
); | |
this.nurbsControlPoints.push(ranCtrlPt); | |
} | |
//calculate resolution (draw speed) of curve | |
this.resolution = this.drawSpeed * this.nurbsControlPoints.length; | |
} | |
// update knots if number of control points change | |
if (this.nurbsControlPoints.length != this.nurbsKnots.length - 4) { | |
this.generateKnots(); | |
} | |
var nextEndPt = this.nurbsControlPoints[this.nurbsControlPoints.length - 1]; | |
var nextLastPt = this.nurbsControlPoints[this.nurbsControlPoints.length - 2]; | |
var midPt = new THREE.Vector4( | |
(nextEndPt.x + nextLastPt.x) / 2, | |
(nextEndPt.y + nextLastPt.y) / 2, | |
(nextEndPt.z + nextLastPt.z) / 2, | |
1 | |
); | |
// fill array except for last element in curve, which is replaced with midPt | |
for (var i = 0; i < this.nurbsControlPoints.length - 1; i++) { | |
drawPoints.push(this.nurbsControlPoints[i]); | |
} | |
drawPoints.push(midPt); | |
this.spline = new THREE.NURBSCurve( | |
this.nurbsDegree, | |
this.nurbsKnots, | |
drawPoints | |
); | |
this.segmentPoints = this.spline.getPoints(this.resolution); | |
// drawCtrlPts(lastPt, lastMidPt, midPt, nextEndPt); | |
}; | |
NurbsRibbon.prototype.generateKnots = function() { | |
this.nurbsKnots.length = 0; // reset array | |
//here we generate the knot array, should increment 0-1 with and array always begins with 0,0,0 and ends with 1,1,1 | |
for (var i = 0; i <= this.nurbsDegree; i++) { | |
this.nurbsKnots.push(0); //0,0,0 | |
} | |
for (var i = 0; i < this.nurbsControlPoints.length; i++) { | |
var knot = (i + 1) / (this.nurbsControlPoints.length - this.nurbsDegree); | |
this.nurbsKnots.push(THREE.Math.clamp(knot, 0, 1)); | |
} | |
}; | |
NurbsRibbon.prototype.addInterpolationPts = function() { | |
let lastPt = this.nurbsControlPoints[ | |
this.nurbsControlPoints.length - 1 | |
].clone(); | |
let nextPt = this.loadedCurvePts[0]; | |
//if the distance between last curve and new curve is greater than threshold amount, add extra points to smooth the transition | |
let dist = new THREE.Vector3(lastPt.x, lastPt.y, lastPt.z).distanceTo( | |
this.loadedCurvePts[0] | |
); | |
let smoothDistance = 2.0; | |
if (dist > smoothDistance) { | |
this.interpolate = true; | |
for (var i = 0; i < this.numInterplPts; i++) { | |
var interplPt = new THREE.Vector3().lerp( | |
lastPt, | |
nextPt, | |
i / this.numInterplPts | |
); | |
this.loadedCurvePts.unshift(interplPt); | |
} | |
} | |
}; | |
NurbsRibbon.prototype.removeInterpolationPts = function() { | |
//remove the interpolation points from the loaded curve point array | |
for (var i = 0; i < this.numInterplPts; i++) { | |
this.loadedCurvePts.shift(); | |
} | |
this.interpolate = false; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment