memoscan
← all memos

Memo 0xa821e88c…38575e on Ethereum

const{cellsWide:i,cellsHigh:l}=this;this.segmentMetaDataTexture={texture:new e.DataTexture(new Float32Array(i*l*2),i,l,e.RGFormat,e.FloatType),width:i,height:l},this.segmentMetaDataTexture.texture.needsUpdate=!0,this.segmentIndexTexture={texture:new Bt(n,n,e.RedFormat,e.FloatType,new Float32Array(n*n)),width:n,height:n},this.segmentIndexTexture.texture.setRenderer(X)}updatePolylines(e,t=!1){this.isClosed=t,this.polyLines=e,this.texturesInitialised||(this.initializeTextures(),this.texturesInitialised=!0),this.buildSegmentRecords(),this.buildSegmentCellIndex(),this.buildSegmentDataTextures()}buildSegmentRecords(){const e=this.polyLines.reduce(((e,t)=>{const n=this.isClosed?t.length:t.length-1;return n>0?e+n:e}),0);this._segmentRecords=new Float32Array(8*e);let t=0;this.polyLines.forEach(((e,n)=>{let i=0;for(let t=0;t<e.length-1;t++)i+=Qt(e[t],e[t+1]);this.isClosed&&e.length>1&&(i+=Qt(e[e.length-1],e[0]));let l=0;const a=this.isClosed?e.length:e.length-1;for(let s=0;s<a;s++){const a=e[s],o=e[(s+1)%e.length],r=Qt(a,o);this._segmentRecords[t++]=a[0],this._segmentRecords[t++]=a[1],this._segmentRecords[t++]=o[0],this._segmentRecords[t++]=o[1],this._segmentRecords[t++]=n,this._segmentRecords[t++]=l,this._segmentRecords[t++]=l+r,this._segmentRecords[t++]=i,l+=r}}))}buildSegmentCellIndex(){const e=this.cellsWide*this.cellsHigh;this._cellCounts=new Float32Array(e),this._cellOffsets=new Float32Array(e);const n=this._segmentRecords.length/8;let i=0;for(let e=0;e<n;e++){const e=this._segmentRecords[i+0],n=this._segmentRecords[i+1],l=this._segmentRecords[i+2],a=this._segmentRecords[i+3];i+=8;const o=t(e/this.cellSize),r=t(n/this.cellSize),c=t(l/this.cellSize),d=t(a/this.cellSize);let u=s(c-o),h=s(d-r),m=o,p=r,g=1+u+h;const b=c>o?1:-1,f=d>r?1:-1;let x=u-h;for(u*=2,h*=2;g--;){if(m>=0&&m<this.cellsWide&&p>=0&&p<this.cellsHigh){const e=p*this.cellsWide+m;this._cellCounts[e]++}if(x>0)m+=b,x-=h;else if(x<0)p+=f,x+=u;else{if(m+=b,p+=f,x+=u-h,g--,g<0)break;if(m>=0&&m<this.cellsWide&&p>=0&&p<this.cellsHigh){const e=p*this.cellsWide+m;this._cellCounts[e]++}}}}let l=0;for(let t=0;t<e;t++){const e=this._cellCounts[t];this._cellOffsets[t]=l,l+=e}this._indexData=new Float32Array(l),i=0;for(let e=0;e<n;e++){const n=this._segmentRecords[i+0],l=this._segmentRecords[i+1],a=this._segmentRecords[i+2],o=this._segmentRecords[i+3];i+=8;const r=t(n/this.cellSize),c=t(l/this.cellSize),d=t(a/this.cellSize),u=t(o/this.cellSize);let h=s(d-r),m=s(u-c),p=r,g=c,b=1+h+m;const f=d>r?1:-1,x=u>c?1:-1;let Z=h-m;for(h*=2,m*=2;b--;){if(p>=0&&p<this.cellsWide&&g>=0&&g<this.cellsHigh){const t=g*this.cellsWide+p,n=this._cellOffsets[t];this._indexData[n]=e,this._cellOffsets[t]=n+1}if(Z>0)p+=f,Z-=m;else if(Z<0)g+=x,Z+=h;else{if(p+=f,g+=x,Z+=h-m,b--,b<0)break;if(p>=0&&p<this.cellsWide&&g>=0&&g<this.cellsHigh){const t=g*this.cellsWide+p,n=this._cellOffsets[t];this._indexData[n]=e,this._cellOffsets[t]=n+1}}}}}buildSegmentDataTextures(){const e=this.segmentDataTexture.texture.texture.image.data,t=this.segmentDataTexture.width,n=this.segmentDataTexture.height,i=this._segmentRecords.length/8,l=o(2*i,t*n);let a=0,s=0;for(let t=0;t<i&&!(2*t+1>=l);t++){const n=2*t*4,i=4*(2*t+1),l=this._segmentRecords[a+0],o=this._segmentRecords[a+1],r=this._segmentRecords[a+2],c=this._segmentRecords[a+3],d=this._segmentRecords[a+4],u=this._segmentRecords[a+5],h=this._segmentRecords[a+6],m=this._segmentRecords[a+7];e[n+0]=l,e[n+1]=o,e[n+2]=r,e[n+3]=c,e[i+0]=d,e[i+1]=u,e[i+2]=h,e[i+3]=m,a+=8,s+=8}this.segmentDataTexture.texture.uploadSubData(s);const r=this.segmentMetaDataTexture.texture.image.data,c=this.segmentMetaDataTexture.width*this.segmentMetaDataTexture.height;for(let e=0;e<c;e++){const t=this._cellCounts[e],n=this._cellOffsets[e]-t,i=2*e;r[i+0]=n,r[i+1]=t}this.segmentMetaDataTexture.texture.needsUpdate=!0;const d=this.segmentIndexTexture.texture.texture.image.data,u=d.length,h=Math.min(this._indexData.length,u);d.set(this._indexData.subarray(0,h)),this.segmentIndexTexture.texture.uploadSubData(this._indexData.length)}getTextures(){return{segmentMetaDataTexture:this.segmentMetaDataTexture.texture,segmentDataTexture:this.segmentDataTexture.texture.texture,segmentIndexTexture:this.segmentIndexTexture.texture.texture}}reset(){this._segmentRecords=new Float32Array(0),this._cellCounts=new Float32Array(0),this._cellOffsets=new Float32Array(0),this._indexData=new Float32Array(0)}dispose(){this.segmentDataTexture.texture.texture.dispose(),this.segmentMetaDataTexture.texture.dispose(),this.segmentIndexTexture.texture.texture.dispose()}}let jt,At=new Jt(4),Et=new Jt(20),_t=0,qt=!1,$t=null;function en(t){if(0===t.lines.length)return;jt=jt||new e.ShaderMaterial({uniforms:{resolution:{value:new e.Vector2(B,Q)},uInternalResolution:{value:new e.Vector2(Y,P)},uFaceIndex:{value:0},tPaperTexture:{value:Ct.paperTexture.target.texture},uSegmentDataTex:{value:null},uSegmentIndexTex:{value:null},uSegmentMetaDataTex:{value:null},uBrightness:{value:1},...ce(),uAccumulationStrength:{value:1},uEdgeSharpness:{value:1},uTaperingFadeIn:{value:0},uTaperingFadeOut:{value:0},uTaperingScaleIn:{value:0},uTaperingScaleOut:{value:0},uFadeAtLineSegmentVertices:{value:new Float32Array([0,0,0,0])},uFadeAtLineSegmentDistance:{value:0},uFadeAtLineSegmentStrength:{value:1},uEnableFadeAtLineSegment:{value:!1},uIsShading:{value:!0},uDisableSaturationShift:{value:!1},uIsClosedPoly:{value:!1},tScreenBuffer:{value:Xt.getReadBuffer().texture},tPolyEdgeDistance:{value:Ct.polyEdgeDistance.target.texture},uNoiseOffset:{value:new le(0,0)},tWarpTex:{value:Ct.displacementMap.target.texture},uLineColor:{value:new e.Vector3(1,0,0)},uLineHardness:{value:1},uLineWeight:{value:1},uMaterialHardness:{value:1},uLighting:{value:{center:Ke.default,min:wt(Ke.default,Ke.min,Ke.influencesBrightnessMult),max:wt(Ke.default,Ke.max,Ke.influencesBrightnessMult)}},tPolyLineGrid:{value:{width:0,height:0,cellSize:0}}},vertexShader:ie,glslVersion:e.GLSL3,fragmentShader:`\n precision highp float;\n precision highp int;\n\n uniform highp sampler2D tWarpTex;\n uniform highp sampler2D tScreenBuffer;\n uniform highp sampler2D tPaperTexture;\n uniform highp sampler2D tPolyEdgeDistance;\n\n uniform highp sampler2D uSegmentDataTex;\n uniform highp sampler2D uSegmentMetaDataTex;\n uniform highp sampler2D uSegmentIndexTex;\n\n struct TPolyLineGrid {\n float width;\n float height;\n float cellSize;\n };\n\n uniform TPolyLineGrid tPolyLineGrid;\n\n\n struct Lighting {\n float center;\n float min;\n float max;\n };\n\n uniform Lighting uLighting;\n \n // uniform int uPositionsCount;\n uniform bool uIsClosedPoly;\n \n uniform vec2 resolution;\n uniform vec2 uTileOffset;\n uniform vec2 uTileSize;\n\n uniform vec2 uInternalResolution;\n uniform vec2 uNoiseOffset;\n uniform bool uIsShading;\n // uniform bool uBulge;\n\n uniform float uTaperingFadeIn;\n uniform float uTaperingFadeOut;\n uniform float uTaperingScaleIn;\n uniform float uTaperingScaleOut;\n\n uniform bool uEnableFadeAtLineSegment;\n uniform vec2 uFadeAtLineSegmentVertices[2];\n uniform float uFadeAtLineSegmentDistance;\n uniform float uFadeAtLineSegmentStrength;\n\n uniform float uBrightness;\n uniform float uEdgeSharpness;\n uniform float uAccumulationStrength;\n uniform float uMaterialHardness;\n uniform vec3 uLineColor;\n uniform float uLineHardness;\n uniform float uLineWeight;\n uniform float uFaceIndex;\n uniform bool uDisableSaturationShift;\n\n // Max number of lines to consider for this fragment\n const int MAX_LINE_COUNT = 64;\n\n in vec2 vUv;\n out vec4 outColor;\n\n ${Dt}\n ${te}\n ${bt}\n ${gt}\n ${ee}\n ${ne}\n ${Ut}\n\n //-----------------------------------------\n \n\n vec2 pointLineSDFInfinite(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n float t = dot(pa, ba) / dot(ba, ba);\n float dist = length(pa - ba * t);\n return vec2(dist, t);\n }\n\n // 1) Helper to fetch offset+count from segmentMetaDataTexture\n vec2 getSegmentMeta(ivec2 cellCoords) {\n // each pixel stores (offset, count)\n return texelFetch(uSegmentMetaDataTex, cellCoords, 0).rg;\n }\n \n ivec2 getCellCounts() {\n return ivec2(\n int(tPolyLineGrid.width / tPolyLineGrid.cellSize),\n int(tPolyLineGrid.height / tPolyLineGrid.cellSize)\n );\n }\n\n ivec2 getGridCoords(vec2 uv) {\n ivec2 cellCount = getCellCounts();\n \n // Flip Y so top-left is (0,0)\n float flippedY = 1.0 - uv.y;\n \n int x = int(floor(uv.x * float(cellCount.x)));\n int y = int(floor(flippedY * float(cellCount.y)));\n \n return ivec2(x, y);\n }\n\n\n // 2) Helper to read the segment ID from segmentIndexTexture\n int getSegmentID(int globalIndex) {\n ivec2 size = textureSize(uSegmentIndexTex, 0);\n // clamp the fetch\n globalIndex = clamp(globalIndex, 0, size.x*size.y - 1);\n int x = globalIndex % size.x;\n int y = globalIndex / size.x;\n return int(texelFetch(uSegmentIndexTex, ivec2(x,y), 0).r);\n }\n\n // 3) Helper to read the 2 texels for the given segment\n struct SegmentData {\n vec2 a; // x1,y1\n vec2 b; // x2,y2\n float lineIndex; \n float segStart;\n float segEnd;\n float totalLen;\n };\n\n SegmentData getSegmentData(int segmentID) {\n SegmentData seg;\n // float scaleFactor = (1. / uInternalResolution.x);\n\n // each segment uses 2 RGBA texels = 8 floats\n // texel1 => (x1, y1, x2, y2)\n // texel2 => (lineIndex, segStartLen, segEndLen, totalLineLen)\n int texelIndex1 = segmentID * 2;\n int texelIndex2 = segmentID * 2 + 1;\n\n ivec2 size = textureSize(uSegmentDataTex, 0);\n\n // clamp fetch\n int maxTexels = size.x * size.y;\n texelIndex1 = clamp(texelIndex1, 0, maxTexels-1);\n texelIndex2 = clamp(texelIndex2, 0, maxTexels-1);\n\n // decode coordinates\n int x1 = texelIndex1 % size.x;\n int y1 = texelIndex1 / size.x;\n int x2 = texelIndex2 % size.x;\n int y2 = texelIndex2 / size.x;\n\n vec4 d1 = texelFetch(uSegmentDataTex, ivec2(x1,y1), 0);\n vec4 d2 = texelFetch(uSegmentDataTex, ivec2(x2,y2), 0);\n\n seg.a = d1.xy / uInternalResolution;\n seg.b = d1.zw / uInternalResolution;\n\n seg.a = vec2(seg.a.x, 1.0 - seg.a.y);\n seg.b = vec2(seg.b.x, 1.0 - seg.b.y);\n\n seg.lineIndex = d2.x;\n seg.segEnd = d2.z / uInternalResolution.x;\n seg.segStart = d2.y / uInternalResolution.x;\n seg.totalLen = d2.w / uInternalResolution.x; // scale to pixel space\n\n return seg;\n }\n\n vec2 pointLineSegSDF(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n float t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n float dist = length(pa - ba * t);\n return vec2(dist, t);\n }\n\n\n // This struct can store the final line-based result\n struct LineDistanceResult {\n float dist; // nearest distance for this line\n float lineT; // fraction along the entire line\n float lineIndex; // which line\n };\n \n const ivec2 offsets[9] = ivec2[](\n ivec2(-1,-1), ivec2(0,-1), ivec2(1,-1),\n ivec2(-1, 0), ivec2(0, 0), ivec2(1, 0),\n ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1)\n );\n\n // This function will find the closest lines to the given uv coordinate\n void lineDistanceSDFSegments(\n vec2 uv,\n float distanceThreshold,\n out LineDistanceResult linesWithin[MAX_LINE_COUNT],\n out int linesCount\n ){\n linesCount = 0;\n \n // We'll keep track of each line's nearest distance in arrays,\n float lineDistances[MAX_LINE_COUNT];\n float lineTvalues[MAX_LINE_COUNT];\n int lineIDs[MAX_LINE_COUNT];\n \n // Initialize with defaults\n for (int i = 0; i < MAX_LINE_COUNT; i++) {\n lineDistances[i] = 1e20;\n lineTvalues[i] = 0.0;\n lineIDs[i] = -1;\n }\n \n // Figure out the base cell coords from uv\n ivec2 baseCellCoords = getGridCoords(uv);\n ivec2 cellCount = getCellCounts();\n \n // For each of the 9 offsets, gather segments from neighboring cells.\n for (int c = 0; c < 9; c++) {\n ivec2 cellCoords = baseCellCoords + offsets[c];\n \n // clamp cellCoords to grid boundaries\n if(cellCoords.x < 0 || cellCoords.x >= cellCount.x) continue;\n if(cellCoords.y < 0 || cellCoords.y >= cellCount.y) continue;\n \n // 1) fetch offset+count from the segmentMetaDataTexture\n vec2 meta = getSegmentMeta(cellCoords);\n int segOffset = int(meta.r);\n int segCount = int(meta.g);\n \n // 2) read each segment\n // same logic as before, but unify them into lineDistances\n for (int i = 0; i < 1024; i++) {\n if (i >= segCount) break;\n \n int segID = getSegmentID(segOffset + i);\n SegmentData seg = getSegmentData(segID);\n \n // compute distance to this segment\n vec2 dt = pointLineSegSDF(uv, seg.a, seg.b);\n float dist = dt.x;\n float localT = dt.y;\n \n float segLen = seg.segEnd - seg.segStart;\n float absoluteDistanceAlongLine = seg.segStart + localT * segLen;\n float fraction = (seg.totalLen > 0.0) ? (absoluteDistanceAlongLine / seg.totalLen) : 0.0;\n \n // if within threshold\n if (dist <= distanceThreshold) {\n int lineID = int(seg.lineIndex);\n \n // check if we already have that line\n int foundIndex = -1;\n for (int j = 0; j < MAX_LINE_COUNT; j++) {\n if (lineIDs[j] == lineID) {\n foundIndex = j;\n break;\n }\n }\n \n if (foundIndex == -1) {\n // new line\n for (int j = 0; j < MAX_LINE_COUNT; j++) {\n if (lineIDs[j] < 0) {\n lineIDs[j] = lineID;\n lineDistances[j] = dist;\n lineTvalues[j] = fraction;\n break;\n }\n }\n } else {\n // line already exists => keep closer distance\n if (dist < lineDistances[foundIndex]) {\n lineDistances[foundIndex] = dist;\n lineTvalues[foundIndex] = fraction;\n }\n }\n }\n }\n }\n \n // Final pass: gather valid lines into linesWithin\n int validCount = 0;\n for (int i = 0; i < MAX_LINE_COUNT; i++) {\n if (lineIDs[i] >= 0) {\n linesWithin[validCount].dist = lineDistances[i];\n linesWithin[validCount].lineT = lineTvalues[i];\n linesWithin[validCount].lineIndex = float(lineIDs[i]);\n validCount++;\n if (validCount >= MAX_LINE_COUNT) break;\n }\n }\n\n // Now 'validCount' lines are in linesWithin[0..validCount-1].\n // Sort them by dist ascending.\n for (int i = 0; i < MAX_LINE_COUNT - 1; i++) {\n // If 'i' >= validCount - 1, break\n if (i >= validCount - 1) break;\n\n for (int j = i + 1; j < MAX_LINE_COUNT; j++) {\n // If 'j' >= validCount, break\n if (j >= validCount) break;\n\n if (linesWithin[j].dist < linesWithin[i].dist) {\n // Swap\n LineDistanceResult tmp = linesWithin[i];\n linesWithin[i] = linesWithin[j];\n linesWithin[j] = tmp;\n }\n }\n }\n \n linesCount = validCount;\n }\n\n\n float easeOut(float t, float strength) {\n return 1.0 - pow(1.0 - t, strength);\n }\n\n // UV - Scene UV\n // screenSpaceUV - screen space UV\n // MSAA Offset - offset for the current sample\n vec4 render(vec2 uv, vec2 screenSpaceUV, vec2 msaaOffset, vec3 frameBuffer) {\n\n float scaleFactor = (1. / uInternalResolution.x);\n vec2 tileScaleFactor = resolution / uTileSize;\n \n \n vec2 uvWarp = lookupWarpSample(screenSpaceUV + msaaOffset).xy;\n vec2 ssLookupWarp = uvWarp * tileScaleFactor;\n\n uv += uvWarp;\n\n float sdf = (texture(tPolyEdgeDistance, screenSpaceUV + ssLookupWarp + msaaOffset).r - 0.5) * 2.0;\n\n // float flippedY = 1.0 - uv.y;\n vec3 color = uLineColor;\n\n // float shift = 0.02;\n // color.x += shift;\n // color.y -= shift * 0.4;\n\n float rampStart = 0.7; // Where ramping begins\n float rampEnd = 1.0; // Where ramping hits its max\n float lowValue = 0.015; // AccumulationIncrement below threshold\n float highValue = 0.06; // AccumulationIncrement if color.x approaches rampEnd\n\n // ‘t’ goes from 0.0 to 1.0 as color.x moves from rampStart to rampEnd\n float t = clamp((color.x - rampStart) / (rampEnd - rampStart), 0.0, 1.0);\n // float accumulationIncrement = mix(lowValue, highValue, t);\n \n float accumulationClampMax = 0.15;\n float accumulationIncrement = mix(lowValue, highValue, smoothstep(rampStart, rampEnd, color.x));\n vec2 accumulationClamp = vec2(accumulationClampMax, accumulationClampMax * 0.4);\n float chromaIncrement = (accumulationIncrement * 0.4) * uAccumulationStrength; // adjust for subtlety\n float lightnessIncrement = (-accumulationIncrement) * uAccumulationStrength; // adjust for subtlety\n float alphaIncrement = uIsShading ? .95 : 1.5; // adjust for subtlety\n \n // float brightnessRemap = remap(uBrightness, 0., 1., 0., 0.95);\n if(uIsShading) {\n float colorShift = uBrightness - uLighting.center;\n // Only scale down if colorShift is above 0\n float shiftFactor = (colorShift > 0. && color.x > 0.6) ? (1.0 - clamp(color.x / 0.82, 0., 1.)) : 1.0;\n float newMult = ((colorShift * 1.5 * shiftFactor) + 1.0);\n \n color.x *= newMult;\n \n // color.y = remap(\n // clamp(colorShift, 0., 1.),\n // 0.,\n // uLighting.max - uLighting.center,\n // color.y,\n // color.y - .02\n // );\n \n \n color.x -= 0.0;\n color.y -= 0.025;\n \n color.x = clamp(color.x, 0., 0.82);\n }\n // float satRemap = remap(uBrightness, 0.8, 1.2, 0.04, -0.02);\n // color.y -= (colorShift * 0.4);\n // }\n\n\n\n color.x = clamp(color.x, 0., .81);\n color.y = clamp(color.y, 0., .4);\n \n \n // float satShift = 1.0 - remap(uBrightness, 0.9, 1., 1.005, 1.);\n // color.y = clamp(color.y - satShift, 0., 1.);\n \n vec3 originalColor = color;\n // color.y = clamp(color.y - colourShift * 0.1, 0., 1.);\n // color.x *= uBrightness;\n // float satRemapAtHighBrightness = clamp(remap(uBrightness, 1., 1.2, 1., 0.8), 0.8, 1.);\n // color.y *= satRemapAtHighBrightness;\n\n \n\n\n \n\n // SHAPE SDF\n \n float alpha = 0.0;\n \n float segmentDistanceAlphaMult = 1.;\n\n if(uEnableFadeAtLineSegment) {\n vec2 fadeStartVert = uFadeAtLineSegmentVertices[0] / resolution.xy;\n vec2 fadeEndVert = uFadeAtLineSegmentVertices[1] / resolution.xy;\n float fadeDistance = uFadeAtLineSegmentDistance * scaleFactor;\n float fadeAlpha = pointLineSDFInfinite(uv, fadeStartVert, fadeEndVert).x;\n float fadeLerp = smoothstep(0., fadeDistance, fadeAlpha);\n fadeLerp = clamp(remap(fadeLerp, 0., 1., 1. - uFadeAtLineSegmentStrength, 1.), 0., 1.);\n segmentDistanceAlphaMult = fadeLerp;\n }\n\n float edgeSharpness = remap(uEdgeSharpness, 0., 1., -0.1, -0.0015);\n\n segmentDistanceAlphaMult *= smoothstep(edgeSharpness, -0.0, sdf);\n\n if(segmentDistanceAlphaMult <= 0.) {\n return vec4(frameBuffer, 1.);\n }\n\n\n float accumulationValue = 0.0;\n\n // Loop Setup\n // int linesInRangeCount;\n // vec3 linesInRange[MAX_LINE_COUNT];\n float lineSampleDistanceMax = scaleFactor * (uLineWeight * 2.);\n // lineDistanceSDF(uv + uvOffset, lineSampleDistanceMax, linesInRange, linesInRangeCount);\n\n LineDistanceResult linesWithin[MAX_LINE_COUNT];\n int linesCount;\n lineDistanceSDFSegments(uv, lineSampleDistanceMax, linesWithin, linesCount);\n\n // for(int i = MAX_LINE_COUNT; i >= 0; i--) {\n for(int i = 0; i < linesCount; i++) {\n vec3 localColor = color;\n // if(i >= linesInRangeCount) continue;\n // vec3 lineDistanceProps = linesInRange[i];\n\n float lineSDF = linesWithin[i].dist;\n float lineT = linesWithin[i].lineT;\n float lineIndex = linesWithin[i].lineIndex;\n\n float currentLineNoiseOffset = float(lineIndex) * 10.;\n\n // Line Tapering and Fade\n float fadeLineCap = 1.;\n float scaleLineCap = 1.;\n \n if(uTaperingFadeIn > 0. || uTaperingFadeOut > 0.) {\n float fadeWarp = abs(fbm(uv + uNoiseOffset + currentLineNoiseOffset, 1, 10., 0.9)) * 0.05;\n \n if(uTaperingFadeIn > 0.) {\n fadeLineCap = easeOut(smoothstep(0.0, (uTaperingFadeIn / 2.) - fadeWarp, lineT), 10.);\n }\n\n if(uTaperingFadeOut > 0.) {\n fadeLineCap *= easeOut(smoothstep(1., 1. - (uTaperingFadeOut / 2.) - fadeWarp, lineT), 10.);\n }\n }\n\n if(uTaperingScaleIn > 0. || uTaperingScaleOut > 0.) {\n float scaleWarp = abs(fbm(uv + uNoiseOffset + currentLineNoiseOffset, 1, 10., 0.9)) * 0.05;\n if(uTaperingScaleIn > 0.) {\n scaleLineCap = easeOut(smoothstep(0.0, (uTaperingScaleIn / 2.), lineT + scaleWarp), 1.);\n }\n\n if(uTaperingScaleOut > 0.) {\n scaleLineCap *= easeOut(smoothstep(1., 1. - (uTaperingScaleOut / 2.), lineT + scaleWarp), 1.);\n }\n }\n\n float lineHardness = uLineHardness * fadeLineCap;\n // float lineHardness = uLineHardness;\n\n // float lineWeight = uLineWeight + (fbm(uNoiseOffset + (lineIndex / 2.), 1, 10., 0.9) / 4.);\n float lineWeight = uLineWeight;\n \n float lineDistanceMax = (scaleFactor * lineWeight) * scaleLineCap;\n float lineWeightWobble = fbm(uv + currentLineNoiseOffset,