From e32c1a20047a244937b58a2fbe4965b1ed8a143e Mon Sep 17 00:00:00 2001 From: Michael Aschauer Date: Sat, 27 Oct 2018 14:33:27 +0200 Subject: [PATCH] make jumplines dashed and experiment with drawing the lines --- stitchcode/objects.js | 131 +++++++++++++++++++++++----- stitchcode/threee/THREE.MeshLine.js | 58 ++++++++---- 2 files changed, 153 insertions(+), 36 deletions(-) diff --git a/stitchcode/objects.js b/stitchcode/objects.js index b14d1a8c..798b0ca8 100644 --- a/stitchcode/objects.js +++ b/stitchcode/objects.js @@ -62,6 +62,34 @@ SpriteMorph.prototype.addStitch = function(x1, y1, x2, y2) { this.cache.addMaterial(material); } + // render as line mesh + if (false) { + var geometry = this.cache.findGeometry('meshline', [x1,y1,x2,y2, color, this.color.a]); + if (!geometry) { + geometry = new THREE.Geometry(); + geometry.vertices = [ + new THREE.Vector3(x1, y1, 0.0), + new THREE.Vector3(x2, y2, 0.0), + ]; + var g = new MeshLine(); + g.setGeometry( geometry ); + + this.cache.addGeometry('meshline', g, [x1,y1,x2,y2, color, this.color.a]); + } + + var material = new MeshLineMaterial( { + useMap: false, + color: new THREE.Color( color ), + opacity: this.color.a * 1, + resolution: new THREE.Vector2( stage.width(), stage.height() ), + sizeAttenuation: true, + lineWidth: stage.penSize/200, + }); + material.transparent = true; + var mesh = new THREE.Mesh( g.geometry, material ); + stage.myStitchLines.add(mesh); + } + // render as plain lines if (false) { @@ -81,8 +109,9 @@ SpriteMorph.prototype.addStitch = function(x1, y1, x2, y2) { // render as quads if (true) { var geometry = new THREE.Geometry(); - var s = stage.penSize / 2; - + var s = 2; + + /* normal = new THREE.Vector3( -(y2-y1), (x2-x1), 0); normal = normal.normalize(); @@ -122,9 +151,14 @@ SpriteMorph.prototype.addStitch = function(x1, y1, x2, y2) { //console.log(bcgeometry); //console.log(bgeometry); + + var w = Math.sqrt((x2-x1) * (x2-x1) +(y2-y1) * (y2-y1)); w = Math.round((w + 0.00001) * 100) / 100; h = stage.penSize * 2; + if (stage.penSize <= 1) + w = w - s * 2; + var geometry = this.cache.findGeometry('plane', [w, h]); if (!geometry) { @@ -134,29 +168,52 @@ SpriteMorph.prototype.addStitch = function(x1, y1, x2, y2) { line = new THREE.Mesh(geometry, material); line.translateX(x1 + (x2 - x1)/2); - line.translateY(y1+ (y2 - y1)/2); + line.translateY(y1 + (y2 - y1)/2); line.rotation.z = (90 - this.heading) * Math.PI / 180; stage.myStitchLines.add(line); + + // add half circles to simulate linecaps:round in svg + if (stage.penSize > 1) { + geometry = this.cache.findGeometry('circle', [stage.penSize/2, 0]); + if (!geometry) { + geometry = new THREE.CircleGeometry( stage.penSize/2, 32, 0, Math.PI ); + this.cache.addGeometry('circle', geometry, [stage.penSize/2, 0]); + } + var circle = new THREE.Mesh( geometry, material ); + circle.translateX(x2); + circle.translateY(y2); + circle.rotation.z = - this.heading * Math.PI / 180; + circle.visible = true; + stage.myStitchLines.add(circle); + + var circle = new THREE.Mesh( geometry, material ); + circle.translateX(x1); + circle.translateY(y1); + circle.rotation.z = - (this.heading + 180) * Math.PI / 180; + circle.visible = true; + stage.myStitchLines.add(circle); + + } + + + /* - // add a circle to simulate linecaps:round in svg + // add half circles to simulate linecaps:round in svg //if (stage.penSize > 1) { geometry = this.cache.findGeometry('circle', [s]); if (!geometry) { - geometry = new THREE.CircleGeometry( s, 32 ); + geometry = new THREE.CircleGeometry( s, 32); this.cache.addGeometry('circle', geometry, [s]); } var circle = new THREE.Mesh( geometry, material ); circle.translateX(x2); circle.translateY(y2); circle.visible = true; - stage.myStitchLines.add(circle); + stage.myStitchLines.add(circle); //} */ - - //console.log(w, x2, y2); - //console.log(this.cache); } this.reRender(); this.lastJumped = false; @@ -170,14 +227,47 @@ SpriteMorph.prototype.addJumpLine = function(x1, y1, x2, y2) { this.jumpLines = new THREE.Group(); } - var material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); - var geometry = new THREE.Geometry(); - geometry.vertices = [ - new THREE.Vector3(x1, y1, 0.0), - new THREE.Vector3(x2, y2, 0.0), - ]; - line = new THREE.Line(geometry, material); - stage.myJumpLines.add(line); + if (false) { + var material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); + var geometry = new THREE.Geometry(); + geometry.vertices = [ + new THREE.Vector3(x1, y1, 0.0), + new THREE.Vector3(x2, y2, 0.0), + ]; + line = new THREE.Line(geometry, material); + stage.myJumpLines.add(line); + } + + if (true) { + color = new THREE.Color("rgb(255,0,0)"); + var geometry = this.cache.findGeometry('meshline', [x1,y1,x2,y2, color, 0.8]); + if (!geometry) { + geometry = new THREE.Geometry(); + geometry.vertices = [ + new THREE.Vector3(x1, y1, 0.0), + new THREE.Vector3(x2, y2, 0.0), + ]; + var g = new MeshLine(); + g.setGeometry( geometry ); + + this.cache.addGeometry('meshline', g, [x1,y1,x2,y2, color, this.color.a]); + } + + var material = new MeshLineMaterial( { + useMap: false, + color: new THREE.Color( color ), + opacity: 0.8, + resolution: new THREE.Vector2( stage.width(), stage.height() ), + sizeAttenuation: true, + lineWidth: .003, + dashArray: 0.06, + dashOffset: 0, + dashRatio: 0.35 + }); + material.transparent = true; + var mesh = new THREE.Mesh( g.geometry, material ); + stage.myJumpLines.add(mesh); + } this.lastJumped = true; this.reRender(); @@ -213,10 +303,11 @@ SpriteMorph.prototype.addStitchPoint = function(x2, y2) { line = new THREE.Mesh(geometry, material); line.rotation.z = (45 - this.heading) * Math.PI / 180; - line.position.set(x2,y2,0); + line.position.set(x2,y2,0.01); line.visible = stage.renderer.showingStitchPoints; - stage.myStitchPoints.add(line); + if (stage.penSize <= 1) + stage.myStitchPoints.add(line); this.reRender(); }; @@ -2230,7 +2321,7 @@ function Cache () { Cache.prototype.init = function () { this.materials = []; - this.geometries = { stitch: [], stitchPoint: [], densityPoint: [], circle: [], plane: [] }; + this.geometries = { stitch: [], stitchPoint: [], densityPoint: [], circle: [], plane: [], meshline: [] }; }; Cache.prototype.clear = function () { diff --git a/stitchcode/threee/THREE.MeshLine.js b/stitchcode/threee/THREE.MeshLine.js index 59280a63..12c36b49 100644 --- a/stitchcode/threee/THREE.MeshLine.js +++ b/stitchcode/threee/THREE.MeshLine.js @@ -8,7 +8,7 @@ var has_require = typeof require !== 'undefined' var THREE = root.THREE || has_require && require('three') if( !THREE ) - throw new Error( 'EquirectangularToCubemap requires three.js' ) + throw new Error( 'MeshLine requires three.js' ) function MeshLine() { @@ -268,7 +268,6 @@ function MeshLineMaterial( parameters ) { '', 'varying vec2 vUV;', 'varying vec4 vColor;', -'varying vec3 vPosition;', 'varying float vCounters;', '', 'vec2 fix( vec4 i, float aspect ) {', @@ -326,7 +325,6 @@ function MeshLineMaterial( parameters ) { ' vec4 offset = vec4( normal * side, 0.0, 1.0 );', ' finalPosition.xy += offset.xy;', '', -' vPosition = ( modelViewMatrix * vec4( position, 1. ) ).xyz;', ' gl_Position = finalPosition;', '', '}' ]; @@ -336,27 +334,32 @@ function MeshLineMaterial( parameters ) { 'precision mediump float;', '', 'uniform sampler2D map;', +'uniform sampler2D alphaMap;', 'uniform float useMap;', +'uniform float useAlphaMap;', 'uniform float useDash;', -'uniform vec2 dashArray;', +'uniform float dashArray;', +'uniform float dashOffset;', +'uniform float dashRatio;', 'uniform float visibility;', 'uniform float alphaTest;', +'uniform vec2 repeat;', '', 'varying vec2 vUV;', 'varying vec4 vColor;', -'varying vec3 vPosition;', 'varying float vCounters;', '', 'void main() {', '', ' vec4 c = vColor;', -' if( c.a < alphaTest ) discard;', -' if( useMap == 1. ) c *= texture2D( map, vUV );', -' if( useDash == 1. ){', -' ', -' }', +' if( useMap == 1. ) c *= texture2D( map, vUV * repeat );', +' if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV * repeat ).a;', +' if( c.a < alphaTest ) discard;', +' if( useDash == 1. ){', +' c.a *= ceil(mod(vCounters + dashOffset, dashArray) - (dashArray * dashRatio));', +' }', ' gl_FragColor = c;', -' gl_FragColor.a *= step(vCounters,visibility);', +' gl_FragColor.a *= step(vCounters, visibility);', '}' ]; function check( v, d ) { @@ -371,32 +374,42 @@ function MeshLineMaterial( parameters ) { this.lineWidth = check( parameters.lineWidth, 1 ); this.map = check( parameters.map, null ); this.useMap = check( parameters.useMap, 0 ); + this.alphaMap = check( parameters.alphaMap, null ); + this.useAlphaMap = check( parameters.useAlphaMap, 0 ); this.color = check( parameters.color, new THREE.Color( 0xffffff ) ); this.opacity = check( parameters.opacity, 1 ); this.resolution = check( parameters.resolution, new THREE.Vector2( 1, 1 ) ); this.sizeAttenuation = check( parameters.sizeAttenuation, 1 ); this.near = check( parameters.near, 1 ); this.far = check( parameters.far, 1 ); - this.dashArray = check( parameters.dashArray, [] ); - this.useDash = ( this.dashArray !== [] ) ? 1 : 0; + this.dashArray = check( parameters.dashArray, 0 ); + this.dashOffset = check( parameters.dashOffset, 0 ); + this.dashRatio = check( parameters.dashRatio, 0.5 ); + this.useDash = ( this.dashArray !== 0 ) ? 1 : 0; this.visibility = check( parameters.visibility, 1 ); this.alphaTest = check( parameters.alphaTest, 0 ); + this.repeat = check( parameters.repeat, new THREE.Vector2( 1, 1 ) ); var material = new THREE.RawShaderMaterial( { uniforms:{ lineWidth: { type: 'f', value: this.lineWidth }, map: { type: 't', value: this.map }, useMap: { type: 'f', value: this.useMap }, + alphaMap: { type: 't', value: this.alphaMap }, + useAlphaMap: { type: 'f', value: this.useAlphaMap }, color: { type: 'c', value: this.color }, opacity: { type: 'f', value: this.opacity }, resolution: { type: 'v2', value: this.resolution }, sizeAttenuation: { type: 'f', value: this.sizeAttenuation }, near: { type: 'f', value: this.near }, far: { type: 'f', value: this.far }, - dashArray: { type: 'v2', value: new THREE.Vector2( this.dashArray[ 0 ], this.dashArray[ 1 ] ) }, + dashArray: { type: 'f', value: this.dashArray }, + dashOffset: { type: 'f', value: this.dashOffset }, + dashRatio: { type: 'f', value: this.dashRatio }, useDash: { type: 'f', value: this.useDash }, visibility: {type: 'f', value: this.visibility}, - alphaTest: {type: 'f', value: this.alphaTest} + alphaTest: {type: 'f', value: this.alphaTest}, + repeat: { type: 'v2', value: this.repeat } }, vertexShader: vertexShaderSource.join( '\r\n' ), fragmentShader: fragmentShaderSource.join( '\r\n' ) @@ -405,6 +418,8 @@ function MeshLineMaterial( parameters ) { delete parameters.lineWidth; delete parameters.map; delete parameters.useMap; + delete parameters.alphaMap; + delete parameters.useAlphaMap; delete parameters.color; delete parameters.opacity; delete parameters.resolution; @@ -412,8 +427,11 @@ function MeshLineMaterial( parameters ) { delete parameters.near; delete parameters.far; delete parameters.dashArray; + delete parameters.dashOffset; + delete parameters.dashRatio; delete parameters.visibility; delete parameters.alphaTest; + delete parameters.repeat; material.type = 'MeshLineMaterial'; @@ -433,12 +451,21 @@ MeshLineMaterial.prototype.copy = function ( source ) { this.lineWidth = source.lineWidth; this.map = source.map; this.useMap = source.useMap; + this.alphaMap = source.alphaMap; + this.useAlphaMap = source.useAlphaMap; this.color.copy( source.color ); this.opacity = source.opacity; this.resolution.copy( source.resolution ); this.sizeAttenuation = source.sizeAttenuation; this.near = source.near; this.far = source.far; + this.dashArray.copy( source.dashArray ); + this.dashOffset.copy( source.dashOffset ); + this.dashRatio.copy( source.dashRatio ); + this.useDash = source.useDash; + this.visibility = source.visibility; + this.alphaTest = source.alphaTest; + this.repeat.copy( source.repeat ); return this; @@ -457,4 +484,3 @@ else { } }).call(this); -