Generates mesh from SVG path in realtime for Unity.
This is a port of https://github.com/mattdesl/svg-mesh-3d
Copy Assets/SVGMeshUnity directory to your Assets directory.
Add a SVGMesh component to a GameObject that has MeshFilter and MeshRenderer.
varmesh=GetComponent<SVGMesh>();varsvg=newSVGData();svg.Path("M17.316,6.246c0.008,0.162,0.011,... and so on");mesh.Fill(svg);Simply create an instance of SVGData and set SVG path data string by calling SVGData.Path().
Then call Mesh.Fill(), a mesh will be generated.
Instead of use SVG path data, you can directly make path data in your code.
voidUpdate(){SVG.Clear();varresolution=5;varradius=3f;SVG.Move(NoisedR(radius,0),0f);for(vari=0;i<resolution;++i){vari0=i;vari1=(i+1)%resolution;varangle0=Mathf.PI*2f*((float)i0/resolution);varangle1=Mathf.PI*2f*((float)i1/resolution);varr0=NoisedR(radius,i0);varr1=NoisedR(radius,i1);varx0=Mathf.Cos(angle0)*r0;vary0=Mathf.Sin(angle0)*r0;varx1=Mathf.Cos(angle1)*r1;vary1=Mathf.Sin(angle1)*r1;varcx=x0+(x1-x0)*0.5f;varcy=y0+(y1-y0)*0.5f;varca=Mathf.Atan2(cy,cx);varcr=0.3f+(Mathf.PerlinNoise(Time.time,i*-100f)-0.5f)*1.15f;cx+=Mathf.Cos(ca)*cr;cy+=Mathf.Sin(ca)*cr;SVG.Curve(cx,cy,cx,cy,x1,y1);}Mesh.Fill(SVG);}privatefloatNoisedR(floatr,floatrandomize){returnr+(Mathf.PerlinNoise(Time.time,randomize*10f)-0.5f)*0.5f;}publicclassMove:MonoBehaviour{[SerializeField]privatefloatR=0.5f;[SerializeField]privatefloatIntervalRate=1f;[SerializeField]privateSVGMeshHeadMesh;[SerializeField]privateSVGMeshTailMesh;[SerializeField]privateSVGMeshBodyMesh;privateSVGDataHeadSVG;privateSVGDataTailSVG;privateSVGDataBodySVG;privateVector2Head;privateVector2Tail;privateVector2To;privatefloatHeadR;privatefloatTailR;privatefloatInterval;privatefloatFollowTime;voidStart(){HeadSVG=newSVGData();TailSVG=newSVGData();BodySVG=newSVGData();Head=RandomField();Tail=Head;}voidUpdate(){HeadSVG.Clear();TailSVG.Clear();BodySVG.Clear();Update(Time.deltaTime);varv=Mathf.Max(0.7f,1.3f-Mathf.Clamp01((Head-Tail).magnitude/3f));Circle(HeadSVG,Head,HeadR);Circle(TailSVG,Tail,TailR);Metaball(BodySVG,Head,HeadR,Tail,TailR,v);HeadMesh.Fill(HeadSVG);TailMesh.Fill(TailSVG);BodyMesh.Fill(BodySVG);}privatevoidUpdate(floatdt){Interval-=dt;FollowTime-=dt;if(Interval<=0f){To=RandomField();To=Head+Vector2.ClampMagnitude(To-Head,2f);HeadR=R*0.15f;TailR=R;Interval=Random.Range(1.5f,2.6f)*IntervalRate;FollowTime=Random.Range(0.15f,0.25f);}Head=Vector2.Lerp(To,Head,Mathf.Exp(-5f*dt));if(FollowTime<=0f){Tail=Vector2.Lerp(Head,Tail,Mathf.Exp(-5f*dt));if(FollowTime<=-0.4f){TailR=Mathf.Lerp(R,TailR,Mathf.Exp(-4f*dt));}else{TailR=Mathf.Lerp(R*0.05f,TailR,Mathf.Exp(-6f*dt));}HeadR=Mathf.Lerp(R,HeadR,Mathf.Exp(-3f*dt));}}privateVector2RandomField(){returnnewVector2(Random.Range(-4f,4f),Random.Range(-4f,4f));}privatevoidCircle(SVGDatasvg,Vector2c,floatr){for(vari=0;i<4;++i){varangle0=Mathf.PI*0.5f*(i+0);varangle1=Mathf.PI*0.5f*(i+1);varx0=c.x+Mathf.Cos(angle0)*r;vary0=c.y-Mathf.Sin(angle0)*r;varx1=c.x+Mathf.Cos(angle1)*r;vary1=c.y-Mathf.Sin(angle1)*r;vara=r*(4f/3f)*Mathf.Tan((angle1-angle0)/4f);varinAngle=angle0+Mathf.PI*0.5f;varinX=x0+Mathf.Cos(inAngle)*a;varinY=y0-Mathf.Sin(inAngle)*a;varoutAngle=angle1-Mathf.PI*0.5f;varoutX=x1+Mathf.Cos(outAngle)*a;varoutY=y1-Mathf.Sin(outAngle)*a;if(i==0){svg.Move(x0,y0);}svg.Curve(inX,inY,outX,outY,x1,y1);}}// http://shspage.com/aijs/privatevoidMetaball(SVGDatasvg,Vector2c1,floatr1,Vector2c2,floatr2,floatv){if(r1==0f||r2==0f){return;}varpi2=Mathf.PI/2f;vard=(c2-c1).magnitude;varu1=0f;varu2=0f;if(d<=Mathf.Abs(r1-r2)){return;}elseif(d<r1+r2){// case circles are overlappingu1=Mathf.Acos((r1*r1+d*d-r2*r2)/(2*r1*d));u2=Mathf.Acos((r2*r2+d*d-r1*r1)/(2*r2*d));}vart1=Mathf.Atan2(c2.y-c1.y,c2.x-c1.x);vart2=Mathf.Acos((r1-r2)/d);vart1a=t1+u1+(t2-u1)*v;vart1b=t1-u1-(t2-u1)*v;vart2a=t1+Mathf.PI-u2-(Mathf.PI-u2-t2)*v;vart2b=t1-Mathf.PI+u2+(Mathf.PI-u2-t2)*v;varp1a=PointOnCircle(c1,t1a,r1);varp1b=PointOnCircle(c1,t1b,r1);varp2a=PointOnCircle(c2,t2a,r2);varp2b=PointOnCircle(c2,t2b,r2);// define handle length by the distance between both ends of the curve to drawvarhandle_len_rate=2;vard2=Mathf.Min(v*handle_len_rate,(p2a-p1a).magnitude/(r1+r2));d2*=Mathf.Min(1,d*2/(r1+r2));// case circles are overlappingr1*=d2;r2*=d2;svg.Move(p1a);svg.Curve(PointOnCircle(p1a,t1a-pi2,r1),PointOnCircle(p2a,t2a+pi2,r2),p2a);svg.Line(p2b);svg.Curve(PointOnCircle(p2b,t2b-pi2,r2),PointOnCircle(p1b,t1b+pi2,r1),p1b);svg.Line(p1a);}privateVector2PointOnCircle(Vector2c,floatangle,floatr){returnc+newVector2(Mathf.Cos(angle),Mathf.Sin(angle))*r;}}Use SVGData.Move, SVGData.Line, SVGData.Curve, ... and so on. Create realtime path as you like.
The following options are provided in SVGMesh component.
Delaunay(defaultfalse)- whether to use Delaunay triangulation
- Delaunay triangulation is slower, but looks better
Scale(default1)- a positive number, the scale at which to approximate the curves from the SVG paths
- higher number leads to smoother corners, but slower triangulation
Interiorif set, only return interior faces. See note. (Defaulttrue)Exteriorif set, only return exterior faces. See note. (Defaultfalse)Infinityif set, then the triangulation is augmented with a point at infinity represented by the index-1. (Defaultfalse)
MIT





