Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

37 Commits

Repository files navigation

SVGMeshUnity

typo

Generates mesh from SVG path in realtime for Unity.

This is a port of https://github.com/mattdesl/svg-mesh-3d

Install

Copy Assets/SVGMeshUnity directory to your Assets directory.

Add a SVGMesh component to a GameObject that has MeshFilter and MeshRenderer.

inspector

Usage

Create mesh from SVG path

twittertwtitter-wire

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.

Create mesh from code

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.

Options

The following options are provided in SVGMesh component.

  • Delaunay (default false)
    • whether to use Delaunay triangulation
    • Delaunay triangulation is slower, but looks better
  • Scale (default 1)
    • a positive number, the scale at which to approximate the curves from the SVG paths
    • higher number leads to smoother corners, but slower triangulation
  • Interior if set, only return interior faces. See note. (Default true)
  • Exterior if set, only return exterior faces. See note. (Default false)
  • Infinity if set, then the triangulation is augmented with a point at infinity represented by the index -1. (Default false)

License

MIT

About

Generates mesh from SVG path in realtime for Unity.

Topics

Resources

Stars

183 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages