public static Bounds GenerateSpriteMesh(Light2D light, Sprite sprite) { var mesh = light.lightMesh; if (sprite == null) { mesh.Clear(); return(new Bounds(Vector3.zero, Vector3.zero)); } // this needs to be called before getting UV at the line below. // Venky fixed it, enroute to trunk var uvs = sprite.uv; var srcVertices = sprite.GetVertexAttribute <Vector3>(VertexAttribute.Position); var srcUVs = sprite.GetVertexAttribute <Vector2>(VertexAttribute.TexCoord0); var srcIndices = sprite.GetIndices(); var center = 0.5f * (sprite.bounds.min + sprite.bounds.max); var vertices = new NativeArray <LightMeshVertex>(srcIndices.Length, Allocator.Temp); var color = new Color(0, 0, 0, 1); for (var i = 0; i < srcVertices.Length; i++) { vertices[i] = new LightMeshVertex { position = new Vector3(srcVertices[i].x, srcVertices[i].y, 0) - center, color = color, uv = srcUVs[i] }; } mesh.SetVertexBufferParams(vertices.Length, LightMeshVertex.VertexLayout); mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length); mesh.SetIndices(srcIndices, MeshTopology.Triangles, 0, true); light.vertices = new LightMeshVertex[vertices.Length]; NativeArray <LightMeshVertex> .Copy(vertices, light.vertices, vertices.Length); light.indices = new ushort[srcIndices.Length]; NativeArray <ushort> .Copy(srcIndices, light.indices, srcIndices.Length); return(mesh.GetSubMesh(0).bounds); }
public static Bounds GenerateParametricMesh(Light2D light, float radius, float falloffDistance, float angle, int sides) { var angleOffset = Mathf.PI / 2.0f + Mathf.Deg2Rad * angle; if (sides < 3) { radius = 0.70710678118654752440084436210485f * radius; sides = 4; } if (sides == 4) { angleOffset = Mathf.PI / 4.0f + Mathf.Deg2Rad * angle; } var vertexCount = 1 + 2 * sides; var indexCount = 3 * 3 * sides; var vertices = new NativeArray <LightMeshVertex>(vertexCount, Allocator.Temp); var triangles = new NativeArray <ushort>(indexCount, Allocator.Temp); var centerIndex = (ushort)(2 * sides); var mesh = light.lightMesh; // Only Alpha value in Color channel is ever used. May remove it or keep it for batching params in the future. var color = new Color(0, 0, 0, 1); vertices[centerIndex] = new LightMeshVertex { position = float3.zero, color = color }; var radiansPerSide = 2 * Mathf.PI / sides; var min = new float3(float.MaxValue, float.MaxValue, 0); var max = new float3(float.MinValue, float.MinValue, 0); for (var i = 0; i < sides; i++) { var endAngle = (i + 1) * radiansPerSide; var extrudeDir = new float3(math.cos(endAngle + angleOffset), math.sin(endAngle + angleOffset), 0); var endPoint = radius * extrudeDir; var vertexIndex = (2 * i + 2) % (2 * sides); vertices[vertexIndex] = new LightMeshVertex { position = endPoint, color = new Color(extrudeDir.x, extrudeDir.y, 0, 0) }; vertices[vertexIndex + 1] = new LightMeshVertex { position = endPoint, color = color }; // Triangle 1 (Tip) var triangleIndex = 9 * i; triangles[triangleIndex] = (ushort)(vertexIndex + 1); triangles[triangleIndex + 1] = (ushort)(2 * i + 1); triangles[triangleIndex + 2] = centerIndex; // Triangle 2 (Upper Top Left) triangles[triangleIndex + 3] = (ushort)(vertexIndex); triangles[triangleIndex + 4] = (ushort)(2 * i); triangles[triangleIndex + 5] = (ushort)(2 * i + 1); // Triangle 2 (Bottom Top Left) triangles[triangleIndex + 6] = (ushort)(vertexIndex + 1); triangles[triangleIndex + 7] = (ushort)(vertexIndex); triangles[triangleIndex + 8] = (ushort)(2 * i + 1); min = math.min(min, endPoint + extrudeDir * falloffDistance); max = math.max(max, endPoint + extrudeDir * falloffDistance); } mesh.SetVertexBufferParams(vertexCount, LightMeshVertex.VertexLayout); mesh.SetVertexBufferData(vertices, 0, 0, vertexCount); mesh.SetIndices(triangles, MeshTopology.Triangles, 0, false); light.vertices = new LightMeshVertex[vertexCount]; NativeArray <LightMeshVertex> .Copy(vertices, light.vertices, vertexCount); light.indices = new ushort[indexCount]; NativeArray <ushort> .Copy(triangles, light.indices, indexCount); return(new Bounds { min = min, max = max }); }
public static Bounds GenerateShapeMesh(Light2D light, Vector3[] shapePath, float falloffDistance) { var ix = 0; var vcount = 0; var icount = 0; const float kClipperScale = 10000.0f; var mesh = light.lightMesh; // todo Revisit this while we do Batching. var meshInteriorColor = new Color(0.0f, 0, 0, 1.0f); var meshExteriorColor = new Color(0.0f, 0, 0, 0.0f); var vertices = new NativeArray <LightMeshVertex>(shapePath.Length * 256, Allocator.Temp); var indices = new NativeArray <ushort>(shapePath.Length * 256, Allocator.Temp); // Create shape geometry var inputPointCount = shapePath.Length; var inner = new ContourVertex[inputPointCount + 1]; for (var i = 0; i < inputPointCount; ++i) { inner[ix++] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y, Z = 0 } } } ; inner[ix++] = inner[0]; var tess = new Tess(); tess.AddContour(inner, ContourOrientation.CounterClockwise); Tessellate(tess, ElementType.Polygons, indices, vertices, meshInteriorColor, ref vcount, ref icount); // Create falloff geometry List <IntPoint> path = new List <IntPoint>(); for (var i = 0; i < inputPointCount; ++i) { var newPoint = new Vector2(inner[i].Position.X, inner[i].Position.Y) * kClipperScale; var addPoint = new IntPoint((System.Int64)(newPoint.x), (System.Int64)(newPoint.y)); addPoint.N = i; addPoint.D = -1; path.Add(addPoint); } var lastPointIndex = inputPointCount - 1; // Generate Bevels. List <List <IntPoint> > solution = new List <List <IntPoint> >(); ClipperOffset clipOffset = new ClipperOffset(24.0f); clipOffset.AddPath(path, JoinType.jtRound, EndType.etClosedPolygon); clipOffset.Execute(ref solution, kClipperScale * falloffDistance, path.Count); if (solution.Count > 0) { // Fix path for Pivots. var outPath = solution[0]; var minPath = (long)inputPointCount; for (int i = 0; i < outPath.Count; ++i) { minPath = (outPath[i].N != -1) ? Math.Min(minPath, outPath[i].N) : minPath; } var containsStart = minPath == 0; outPath = FixPivots(outPath, path); // Tessellate. var innerIndices = new ushort[inputPointCount]; // Inner Vertices. (These may or may not be part of the created path. Beware!!) for (int i = 0; i < inputPointCount; ++i) { vertices[vcount++] = new LightMeshVertex() { position = new float3(inner[i].Position.X, inner[i].Position.Y, 0), color = meshInteriorColor }; innerIndices[i] = (ushort)(vcount - 1); } var saveIndex = (ushort)vcount; var pathStart = saveIndex; var prevIndex = outPath[0].N == -1 ? 0 : outPath[0].N; for (int i = 0; i < outPath.Count; ++i) { var curr = outPath[i]; var currPoint = new float2(curr.X / kClipperScale, curr.Y / kClipperScale); var currIndex = curr.N == -1 ? 0 : curr.N; vertices[vcount++] = new LightMeshVertex() { position = new float3(currPoint.x, currPoint.y, 0), color = meshExteriorColor }; if (prevIndex != currIndex) { indices[icount++] = innerIndices[prevIndex]; indices[icount++] = innerIndices[currIndex]; indices[icount++] = (ushort)(vcount - 1); } indices[icount++] = innerIndices[prevIndex]; indices[icount++] = saveIndex; indices[icount++] = saveIndex = (ushort)(vcount - 1); prevIndex = currIndex; } // Close the Loop. { indices[icount++] = pathStart; indices[icount++] = innerIndices[minPath]; indices[icount++] = containsStart ? innerIndices[lastPointIndex] : saveIndex; indices[icount++] = containsStart ? pathStart : saveIndex; indices[icount++] = containsStart ? saveIndex : innerIndices[minPath]; indices[icount++] = containsStart ? innerIndices[lastPointIndex] : innerIndices[minPath - 1]; } } mesh.SetVertexBufferParams(vcount, LightMeshVertex.VertexLayout); mesh.SetVertexBufferData(vertices, 0, 0, vcount); mesh.SetIndices(indices, 0, icount, MeshTopology.Triangles, 0, true); light.vertices = new LightMeshVertex[vcount]; NativeArray <LightMeshVertex> .Copy(vertices, light.vertices, vcount); light.indices = new ushort[icount]; NativeArray <ushort> .Copy(indices, light.indices, icount); return(mesh.GetSubMesh(0).bounds); }