public static void SetSlicedSpriteGeom(Vector3[] pos, Vector2[] uv, int offset, out Vector3 boundsCenter, out Vector3 boundsExtents, tk2dSpriteDefinition spriteDef, Vector3 scale, Vector2 dimensions, Vector2 borderBottomLeft, Vector2 borderTopRight, tk2dBaseSprite.Anchor anchor, float colliderOffsetZ, float colliderExtentZ) { boundsCenter = Vector3.zero; boundsExtents = Vector3.zero; if (spriteDef.positions.Length == 4) { float sx = spriteDef.texelSize.x; float sy = spriteDef.texelSize.y; Vector3[] srcVert = spriteDef.positions; float dx = (srcVert[1].x - srcVert[0].x) - 2 * spriteDef.innerPadding; float dy = (srcVert[2].y - srcVert[0].y) - 2 * spriteDef.innerPadding; float borderTopPixels = borderTopRight.y * dy + spriteDef.innerPadding; float borderBottomPixels = borderBottomLeft.y * dy + spriteDef.innerPadding; float borderRightPixels = borderTopRight.x * dx + spriteDef.innerPadding; float borderLeftPixels = borderBottomLeft.x * dx + spriteDef.innerPadding; float dimXPixels = dimensions.x * sx; float dimYPixels = dimensions.y * sy; float anchorOffsetX = 0.0f; float anchorOffsetY = 0.0f; switch (anchor) { case tk2dBaseSprite.Anchor.LowerLeft: case tk2dBaseSprite.Anchor.MiddleLeft: case tk2dBaseSprite.Anchor.UpperLeft: break; case tk2dBaseSprite.Anchor.LowerCenter: case tk2dBaseSprite.Anchor.MiddleCenter: case tk2dBaseSprite.Anchor.UpperCenter: anchorOffsetX = -(int)(dimensions.x / 2.0f); break; case tk2dBaseSprite.Anchor.LowerRight: case tk2dBaseSprite.Anchor.MiddleRight: case tk2dBaseSprite.Anchor.UpperRight: anchorOffsetX = -(int)(dimensions.x); break; } switch (anchor) { case tk2dBaseSprite.Anchor.LowerLeft: case tk2dBaseSprite.Anchor.LowerCenter: case tk2dBaseSprite.Anchor.LowerRight: break; case tk2dBaseSprite.Anchor.MiddleLeft: case tk2dBaseSprite.Anchor.MiddleCenter: case tk2dBaseSprite.Anchor.MiddleRight: anchorOffsetY = -(int)(dimensions.y / 2.0f); break; case tk2dBaseSprite.Anchor.UpperLeft: case tk2dBaseSprite.Anchor.UpperCenter: case tk2dBaseSprite.Anchor.UpperRight: anchorOffsetY = -(int)dimensions.y; break; } anchorOffsetX -= spriteDef.innerPadding; anchorOffsetY -= spriteDef.innerPadding; // scale back to sprite coordinates // do it after the cast above, as we're trying to align to pixel anchorOffsetX *= sx; anchorOffsetY *= sy; boundsCenter.Set(Mathf.Floor(scale.x * ((dimXPixels) * 0.5f + anchorOffsetX)), Mathf.Floor(scale.y * ((dimYPixels) * 0.5f + anchorOffsetY)), colliderOffsetZ); boundsExtents.Set(scale.x * ((dimXPixels) * 0.5f), scale.y * ((dimYPixels) * 0.5f), colliderExtentZ); Vector2[] srcUv = spriteDef.uvs; Vector2 duvx = srcUv[1] - srcUv[0]; Vector2 duvy = srcUv[2] - srcUv[0]; Vector3 origin = new Vector3(anchorOffsetX, anchorOffsetY, 0); tempOriginPoints = ArrayExtention.EnsureLength(tempOriginPoints, 4); tempOriginPoints[0] = origin + new Vector3(0, 0, 0); tempOriginPoints[1] = origin + new Vector3(0, borderBottomPixels, 0); tempOriginPoints[2] = origin + new Vector3(0, dimYPixels - borderTopPixels + 2 * spriteDef.innerPadding, 0); tempOriginPoints[3] = origin + new Vector3(0, dimYPixels + 2 * spriteDef.innerPadding, 0); tempOriginUVs = ArrayExtention.EnsureLength(tempOriginUVs, 4); tempOriginUVs[0] = srcUv[0]; tempOriginUVs[1] = srcUv[0] + duvy * (borderBottomPixels / (srcVert[2].y - srcVert[0].y)); tempOriginUVs[2] = srcUv[0] + duvy * (1 - borderTopPixels / (srcVert[2].y - srcVert[0].y)); tempOriginUVs[3] = srcUv[0] + duvy; for (int i = 0; i < 4; ++i) { pos[offset + i * 4 + 0] = tempOriginPoints[i] + new Vector3(0, 0, 0); pos[offset + i * 4 + 1] = tempOriginPoints[i] + new Vector3(borderLeftPixels, 0, 0); pos[offset + i * 4 + 2] = tempOriginPoints[i] + new Vector3(dimXPixels - borderRightPixels + 2 * spriteDef.innerPadding, 0, 0); pos[offset + i * 4 + 3] = tempOriginPoints[i] + new Vector3(dimXPixels + 2 * spriteDef.innerPadding, 0, 0); for (int j = 0; j < 4; ++j) { pos[offset + i * 4 + j] = Vector3.Scale(pos[offset + i * 4 + j], scale); } uv[offset + i * 4 + 0] = tempOriginUVs[i]; uv[offset + i * 4 + 1] = tempOriginUVs[i] + duvx * (borderLeftPixels / (srcVert[1].x - srcVert[0].x)); uv[offset + i * 4 + 2] = tempOriginUVs[i] + duvx * (1 - borderRightPixels / (srcVert[1].x - srcVert[0].x)); uv[offset + i * 4 + 3] = tempOriginUVs[i] + duvx; } } }
protected override void PostRecombine(CombineInstance[] combos) { int bones = 0; for (int i = 0, combosLength = combos.Length; i < combosLength; i++) { var mci = combos[i]; int meshHash = mci.mesh.GetInstanceID(); int meshBones; if (!bonesPerMesh.TryGetValue(meshHash, out meshBones)) { var bindposes = mci.mesh.bindposes;// here leak ~1kb per frame bool bonesExist = (bindposes != null) && bindposes.Length > 0; meshBones += bonesExist ? bindposes.Length : 1; bonesPerMesh.Add(meshHash, meshBones); } bones += meshBones; } tempBones = ArrayExtention.EnsureLength(tempBones, bones); tempBindPoses = ArrayExtention.EnsureLength(tempBindPoses, bones); tempBoneWeights = ArrayExtention.EnsureLength(tempBoneWeights, Mesh.vertexCount); int boneIndex = 0; int vertexIndexBase = 0; for (int partIndex = 0, partsCount = BatchedParts.Count; partIndex < partsCount; partIndex++) { tmBatchObject part = BatchedParts[partIndex]; SkinnedMeshRenderer partSMR = part.SkinnedMeshRender; if (partSMR) { Transform[] partBones = partSMR.bones; BoneWeight[] partWeights = part.Mesh.boneWeights; Matrix4x4[] partBindPoses = part.Mesh.bindposes; Matrix4x4 partToBatchMatrix = part.CachedTransform.worldToLocalMatrix * CachedTransform.localToWorldMatrix; int meshBonesCount = partBones.Length; for (int i = 0; i < meshBonesCount; i++) { tempBones[boneIndex + i] = partBones[i]; tempBindPoses[boneIndex + i] = partBindPoses[i] * partToBatchMatrix; } int partWeightsLength = partWeights.Length; for (int i = 0; i < partWeightsLength; i++) { BoneWeight bw = partWeights[i]; bw.boneIndex0 += boneIndex; bw.boneIndex1 += boneIndex; bw.boneIndex2 += boneIndex; bw.boneIndex3 += boneIndex; tempBoneWeights[vertexIndexBase] = bw; vertexIndexBase++; } boneIndex += meshBonesCount; } else { Transform bone = part.CachedTransform; tempBones[boneIndex] = bone; tempBindPoses[boneIndex] = bone.worldToLocalMatrix * CachedTransform.localToWorldMatrix; int curVertCount = part.Mesh.vertexCount; for (int vertexIndex = 0; vertexIndex < curVertCount; ++vertexIndex) { tempBoneWeights[vertexIndexBase].boneIndex0 = boneIndex; tempBoneWeights[vertexIndexBase].weight0 = 1; vertexIndexBase++; } boneIndex++; } } Mesh.boneWeights = tempBoneWeights; Mesh.bindposes = tempBindPoses; CachedSkinnedRender.quality = SkinQuality.Auto; CachedSkinnedRender.bones = tempBones; CachedSkinnedRender.sharedMesh = Mesh; CachedSkinnedRender.localBounds = Mesh.bounds; CachedSkinnedRender.enabled = (Mesh.vertexCount > 0); }
void BuildMesh() { MeshClear(); if (meshColliderMesh != null) { meshColliderMesh.Clear(); } tk2dSpriteDefinition sprite = CurrentSprite; Bounds bounds = sprite.GetBounds(); Vector3 actualSpriteSize = new Vector3(bounds.size.x, bounds.size.y, bounds.size.z); // round fill amount - so vertices and uv become rounded float curFillAmount = mFillAmount; bool fillWasRounded = false; if (!isRoundShiftDisabled && (mFillDirection == FillDirection.Horizontal || mFillDirection == FillDirection.Vertical)) { float curSize = (mFillDirection == FillDirection.Horizontal) ? actualSpriteSize.x : actualSpriteSize.y; curFillAmount *= curSize; curFillAmount = (mInvert) ? Mathf.Ceil(curFillAmount) : Mathf.Floor(curFillAmount); curFillAmount /= curSize; fillWasRounded = true; } OnFill(ref tempVertices, ref tempUvs, ref tempColors, curFillAmount); Vector3 centerCorrection = new Vector3(-bounds.size.x * 0.5f * scale.x, bounds.size.y * 0.5f * scale.y) + bounds.center; Vector3 totalScale = actualSpriteSize; totalScale.Scale(scale); for (int i = 0; i < tempVertices.Length; i++) { tempVertices[i] = Vector3.Scale(tempVertices[i], totalScale) + centerCorrection; if (!isRoundShiftDisabled) { if (fillWasRounded) { tempVertices[i] = RoundVertex(tempVertices[i]); } else { tempVertices[i] = FloorVertex(tempVertices[i]); } } } if (rotated ^ (sprite.flipped == tk2dSpriteDefinition.FlipMode.TPackerCW)) { float u0 = 1; float v0 = 1; float u1 = 0; float v1 = 0; foreach (Vector2 v in sprite.uvs) { u0 = u0 > v.x ? v.x : u0; v0 = v0 > v.y ? v.y : v0; u1 = u1 < v.x ? v.x : u1; v1 = v1 < v.y ? v.y : v1; } float du = (u1 - u0); float dv = (v1 - v0); Vector2 zero = new Vector2(u0, v0); Vector2 zero1 = new Vector2(u1, v0); for (int i = 0; i < tempUvs.Length; i++) { Vector2 uvpos = (tempUvs[i] - zero); tempUvs[i] = zero1 + new Vector2(-du * uvpos.y / dv, dv * uvpos.x / du); } } else if (rotated ^ (sprite.flipped == tk2dSpriteDefinition.FlipMode.Tk2d)) { float u0 = 1; float v0 = 1; float u1 = 0; float v1 = 0; foreach (Vector2 v in sprite.uvs) { u0 = u0 > v.x ? v.x : u0; v0 = v0 > v.y ? v.y : v0; u1 = u1 < v.x ? v.x : u1; v1 = v1 < v.y ? v.y : v1; } float du = (u1 - u0); float dv = (v1 - v0); Vector2 zero = new Vector2(u0, v0); Vector2 zero1 = new Vector2(u0, v0); for (int i = 0; i < tempUvs.Length; i++) { Vector2 uvpos = (tempUvs[i] - zero); tempUvs[i] = zero1 + new Vector2(du * uvpos.y / dv, dv * uvpos.x / du); } } int quads = tempVertices.Length / 4; tempIndexes = ArrayExtention.EnsureLength(tempIndexes, quads * 6); for (int i = 0; i < quads; i++) { tempIndexes[6 * i + 0] = 4 * i + 0; tempIndexes[6 * i + 1] = 4 * i + 1; tempIndexes[6 * i + 2] = 4 * i + 2; tempIndexes[6 * i + 3] = 4 * i + 2; tempIndexes[6 * i + 4] = 4 * i + 3; tempIndexes[6 * i + 5] = 4 * i + 0; } MeshVertices = tempVertices; MeshUV = tempUvs; MeshColors = tempColors; MeshTriangles = tempIndexes; if (meshColliderMesh != null) { meshColliderMesh.vertices = tempVertices; meshColliderMesh.uv = tempUvs; meshColliderMesh.colors = tempColors; meshColliderMesh.triangles = tempIndexes; } changed = false; }
public void Recombine() { // update order if (OrderDirty && parts.Count > 0) { parts.Sort((a, b) => b.CachedTransform.position.z.CompareTo(a.CachedTransform.position.z)); } OrderDirty = false; // update mesh // recalc non empty meshes batchedParts.Clear(); foreach (var curObject in parts) { if (curObject.Mesh != null && curObject.Mesh.vertexCount > 0) { batchedParts.Add(curObject); } } if (batchedParts.Count > 0) { CachedTransform.position = Vector3.zero; tempCombos = ArrayExtention.EnsureLength(tempCombos, batchedParts.Count); for (int index = 0, partsCount = batchedParts.Count; index < partsCount; index++) { tmBatchObject part = batchedParts[index]; part.Batched = true; #if UNITY_EDITOR if (part.Mesh != null && !part.Mesh.isReadable) //this work only for batches without tmTextureRender { CustomDebug.Log(part.Mesh); string path = UnityEditor.AssetDatabase.GetAssetPath(part.Mesh); UnityEditor.ModelImporter mImporter = UnityEditor.AssetImporter.GetAtPath(path) as UnityEditor.ModelImporter; if (mImporter != null) { mImporter.isReadable = true; UnityEditor.AssetDatabase.ImportAsset(path, UnityEditor.ImportAssetOptions.ForceUpdate); } } #endif tempCombos[index].mesh = part.Mesh; tempCombos[index].subMeshIndex = 0; tempCombos[index].transform = CachedTransform.worldToLocalMatrix * part.CachedTransform.localToWorldMatrix; } Mesh.CombineMeshes(tempCombos, true); PostRecombine(tempCombos); } else { Mesh.Clear(); ClearMesh(); } Modified = false; }
/// <summary> /// Virtual function called by the UIScreen that fills the buffers. /// </summary> public void OnFill(ref Vector3[] verts_array, ref Vector2[] uvs_array, ref Color[] cols_array, float curFillAmount) { tk2dSpriteDefinition sprite = CurrentSprite; float x0 = 0f; float y0 = 0f; float x1 = 1; float y1 = -1; float u0 = 1; float v0 = 1; float u1 = 0; float v1 = 0; foreach (Vector2 v in sprite.uvs) { u0 = u0 > v.x ? v.x : u0; v0 = v0 > v.y ? v.y : v0; u1 = u1 < v.x ? v.x : u1; v1 = v1 < v.y ? v.y : v1; } // Horizontal and vertical filled sprites are simple -- just end the sprite prematurely if (mFillDirection == FillDirection.Horizontal || mFillDirection == FillDirection.Vertical) { float du = (u1 - u0) * curFillAmount; float dv = (v1 - v0) * curFillAmount; if (fillDirection == FillDirection.Horizontal) { if (mInvert) { x0 = (1f - curFillAmount); u0 = u1 - du; } else { x1 *= curFillAmount; u1 = u0 + du; } } else if (fillDirection == FillDirection.Vertical) { if (mInvert) { y1 *= curFillAmount; v0 = v1 - dv; } else { y0 = -(1f - curFillAmount); v1 = v0 + dv; } } } bool is4VertexType = (fillDirection == FillDirection.Radial90 || fillDirection == FillDirection.Horizontal || fillDirection == FillDirection.Vertical); // Starting quad for the sprite verts_array = ArrayExtention.EnsureLength(verts_array, 4, !is4VertexType); uvs_array = ArrayExtention.EnsureLength(uvs_array, 4, !is4VertexType); verts_array[0] = new Vector2(x1, y0); verts_array[1] = new Vector2(x1, y1); verts_array[2] = new Vector2(x0, y1); verts_array[3] = new Vector2(x0, y0); uvs_array[0] = new Vector2(u1, v1); uvs_array[1] = new Vector2(u1, v0); uvs_array[2] = new Vector2(u0, v0); uvs_array[3] = new Vector2(u0, v1); if (is4VertexType) { if (fillDirection == FillDirection.Radial90) { // Adjust the quad radially, and if 'false' is returned (it's not visible), just exit AdjustRadial(verts_array, uvs_array, curFillAmount, mInvert); } } else { tempVertexList.Clear(); tempUVList.Clear(); tempOXY = ArrayExtention.EnsureLength(tempOXY, 4); tempOUV = ArrayExtention.EnsureLength(tempOUV, 4); if (fillDirection == FillDirection.Radial180) { for (int i = 0; i < 2; ++i) { tempOXY[0] = new Vector2(0f, 0f); tempOXY[1] = new Vector2(0f, 1f); tempOXY[2] = new Vector2(1f, 1f); tempOXY[3] = new Vector2(1f, 0f); tempOUV[0] = new Vector2(0f, 0f); tempOUV[1] = new Vector2(0f, 1f); tempOUV[2] = new Vector2(1f, 1f); tempOUV[3] = new Vector2(1f, 0f); // Each half must be rotated 90 degrees clockwise in order for it to fill properly if (mInvert) { if (i > 0) { Rotate(tempOXY, i); Rotate(tempOUV, i); } } else if (i < 1) { Rotate(tempOXY, 1 - i); Rotate(tempOUV, 1 - i); } // Each half must fill in only a part of the space float x, y; if (i == 1) { x = mInvert ? 0.5f : 1f; y = mInvert ? 1f : 0.5f; } else { x = mInvert ? 1f : 0.5f; y = mInvert ? 0.5f : 1f; } tempOXY[1].y = Mathf.Lerp(x, y, tempOXY[1].y); tempOXY[2].y = Mathf.Lerp(x, y, tempOXY[2].y); tempOUV[1].y = Mathf.Lerp(x, y, tempOUV[1].y); tempOUV[2].y = Mathf.Lerp(x, y, tempOUV[2].y); float amount = (curFillAmount) * 2 - i; bool odd = (i % 2) == 1; if (AdjustRadial(tempOXY, tempOUV, amount, !odd)) { if (mInvert) { odd = !odd; } // Add every other side in reverse order so they don't come out backface-culled due to rotation if (odd) { for (int b = 0; b < 4; ++b) { x = Mathf.Lerp(verts_array[0].x, verts_array[2].x, tempOXY[b].x); y = Mathf.Lerp(verts_array[0].y, verts_array[2].y, tempOXY[b].y); float u = Mathf.Lerp(uvs_array[0].x, uvs_array[2].x, tempOUV[b].x); float v = Mathf.Lerp(uvs_array[0].y, uvs_array[2].y, tempOUV[b].y); tempVertexList.Add(new Vector3(x, y, 0f)); tempUVList.Add(new Vector2(u, v)); } } else { for (int b = 3; b > -1; --b) { x = Mathf.Lerp(verts_array[0].x, verts_array[2].x, tempOXY[b].x); y = Mathf.Lerp(verts_array[0].y, verts_array[2].y, tempOXY[b].y); float u = Mathf.Lerp(uvs_array[0].x, uvs_array[2].x, tempOUV[b].x); float v = Mathf.Lerp(uvs_array[0].y, uvs_array[2].y, tempOUV[b].y); tempVertexList.Add(new Vector3(x, y, 0f)); tempUVList.Add(new Vector2(u, v)); } } } } } else if (fillDirection == FillDirection.Radial360) { for (int i = 0; i < 4; ++i) { tempOXY[0] = new Vector2(0f, 0f); tempOXY[1] = new Vector2(0f, 1f); tempOXY[2] = new Vector2(1f, 1f); tempOXY[3] = new Vector2(1f, 0f); tempOUV[0] = new Vector2(0f, 0f); tempOUV[1] = new Vector2(0f, 1f); tempOUV[2] = new Vector2(1f, 1f); tempOUV[3] = new Vector2(1f, 0f); // Each quadrant must be rotated 90 degrees clockwise in order for it to fill properly if (mInvert) { if (i > 0) { Rotate(tempOXY, i); Rotate(tempOUV, i); } } else if (i < 3) { Rotate(tempOXY, 3 - i); Rotate(tempOUV, 3 - i); } // Each quadrant must fill in only a quarter of the space for (int b = 0; b < 4; ++b) { int index = (mInvert) ? (3 - i) * 4 : i * 4; float fx0 = constRadial360Matrix[index]; float fy0 = constRadial360Matrix[index + 1]; float fx1 = constRadial360Matrix[index + 2]; float fy1 = constRadial360Matrix[index + 3]; tempOXY[b].x = Mathf.Lerp(fx0, fy0, tempOXY[b].x); tempOXY[b].y = Mathf.Lerp(fx1, fy1, tempOXY[b].y); tempOUV[b].x = Mathf.Lerp(fx0, fy0, tempOUV[b].x); tempOUV[b].y = Mathf.Lerp(fx1, fy1, tempOUV[b].y); } float amount = (curFillAmount) * 4 - i; bool odd = (i % 2) == 1; if (AdjustRadial(tempOXY, tempOUV, amount, !odd)) { if (mInvert) { odd = !odd; } // Add every other side in reverse order so they don't come out backface-culled due to rotation if (odd) { for (int b = 0; b < 4; ++b) { float x = Mathf.Lerp(verts_array[0].x, verts_array[2].x, tempOXY[b].x); float y = Mathf.Lerp(verts_array[0].y, verts_array[2].y, tempOXY[b].y); float u = Mathf.Lerp(uvs_array[0].x, uvs_array[2].x, tempOUV[b].x); float v = Mathf.Lerp(uvs_array[0].y, uvs_array[2].y, tempOUV[b].y); tempVertexList.Add(new Vector3(x, y, 0f)); tempUVList.Add(new Vector2(u, v)); } } else { for (int b = 3; b > -1; --b) { float x = Mathf.Lerp(verts_array[0].x, verts_array[2].x, tempOXY[b].x); float y = Mathf.Lerp(verts_array[0].y, verts_array[2].y, tempOXY[b].y); float u = Mathf.Lerp(uvs_array[0].x, uvs_array[2].x, tempOUV[b].x); float v = Mathf.Lerp(uvs_array[0].y, uvs_array[2].y, tempOUV[b].y); tempVertexList.Add(new Vector3(x, y, 0f)); tempUVList.Add(new Vector2(u, v)); } } } } } verts_array = ArrayExtention.EnsureLength(verts_array, tempVertexList.Count); uvs_array = ArrayExtention.EnsureLength(uvs_array, tempUVList.Count); for (int i = 0; i < tempVertexList.Count; i++) { verts_array[i] = tempVertexList[i]; } for (int i = 0; i < tempUVList.Count; i++) { uvs_array[i] = tempUVList[i]; } } // Fill the buffer with the quad for the sprite cols_array = ArrayExtention.EnsureLength(cols_array, verts_array.Length); for (int i = 0; i < cols_array.Length; ++i) { cols_array[i] = color; } }