public static CoRProcessThreadState[] CalculateCenterOfRotation(this RenderChunk chunk, int maxThreadNumber, float similarityKernel, float similarityThreshold)
        {
            if (chunk.clusterArray == null || chunk.clusteredVertexIndexArray == null)
            {
                Debug.LogError("Must need pre-calculated Center Of Clusters");
                return(null);
            }

            CoRProcessThreadState[] processStateArray = new CoRProcessThreadState[maxThreadNumber];

            chunk.centerOfRotationPositionArray = new Vector3[chunk.vertexCount];

            System.Threading.ParameterizedThreadStart CoRProcessStart =
                (threadObj) =>
            {
                Thread thread = threadObj as Thread;
                Match  match  = Regex.Match(thread.Name, threadNameRegexPattern);

                int currentThreadNum = int.Parse(match.Groups[1].Value), maximumThreadNum = int.Parse(match.Groups[2].Value),
                    vertexLegnth = chunk.vertexCount;

                try
                {
                    for (int clusterIndex = currentThreadNum; clusterIndex < chunk.clusterArray.Length; clusterIndex += maximumThreadNum)
                    {
                        ClusterData currentCluster = chunk.clusterArray[clusterIndex];

                        for (int clusterVertexIndex = currentCluster.startIndexOfCluster; clusterVertexIndex < currentCluster.startIndexOfCluster + currentCluster.lengthOfCluster; clusterVertexIndex++)
                        {
                            int vertexIndex = chunk.clusteredVertexIndexArray[clusterVertexIndex];

                            Vector3 calculatedVertex = Vector3.zero;
                            float   sumedSimiliarity = 0f;

                            for (int clusterTriangleIndex = currentCluster.startIndexOfTriangles; clusterTriangleIndex < currentCluster.startIndexOfTriangles + currentCluster.lengthOfTriangles; clusterTriangleIndex++)
                            {
                                int triangleIndex = chunk.clusteredTriangleIndexArray[clusterTriangleIndex];

                                float similarity =
                                    chunk.GetSimliarity(
                                        vertexIndex,
                                        chunk.indices[triangleIndex * 3 + 0],
                                        chunk.indices[triangleIndex * 3 + 1],
                                        chunk.indices[triangleIndex * 3 + 2],
                                        similarityKernel
                                        );

                                if (similarity < similarityThreshold)
                                {
                                    continue;
                                }

                                float area = chunk.GetArea(
                                    chunk.indices[triangleIndex * 3 + 0],
                                    chunk.indices[triangleIndex * 3 + 1],
                                    chunk.indices[triangleIndex * 3 + 2]
                                    );

                                calculatedVertex +=
                                    (Vector3)(
                                        chunk.dataPerVertex[chunk.indices[triangleIndex * 3 + 0]].position +
                                        chunk.dataPerVertex[chunk.indices[triangleIndex * 3 + 1]].position +
                                        chunk.dataPerVertex[chunk.indices[triangleIndex * 3 + 2]].position
                                        ) / 3 *
                                    area * similarity;
                                sumedSimiliarity += area * similarity;
                            }

                            if (sumedSimiliarity > 0)
                            {
                                chunk.centerOfRotationPositionArray[vertexIndex] = calculatedVertex / sumedSimiliarity;
                            }
                            else
                            {
                                chunk.centerOfRotationPositionArray[vertexIndex] = chunk.dataPerVertex[vertexIndex].position;
                                processStateArray[currentThreadNum].emptyCount++;
                            }

                            processStateArray[currentThreadNum].processCount++;
                        }
                    }

                    processStateArray[currentThreadNum].done = true;
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                    Debug.LogError(e.Source);
                    Debug.LogError(e.Message);

                    processStateArray[currentThreadNum].fail = true;
                }
            };

            for (int i = 0; i < maxThreadNumber; i++)
            {
                Thread thread = new Thread(CoRProcessStart);
                thread.Name = String.Format(threadNameFormat, i, maxThreadNumber);
                thread.Start(thread);
            }

            return(processStateArray);
        }
Example #2
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUI.BeginDisabledGroup(true);

            EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject(targetAs), typeof(RenderChunk), false);
            EditorGUILayout.ObjectField("Editor Script", MonoScript.FromScriptableObject(this), typeof(RenderChunkEditor), false);

            EditorGUI.EndDisabledGroup();

            serializedObject.Update();

            EditorGUILayout.Space();

            RenderChunk chunk = targetAs;

            EditorGUILayout.PropertyField(rendererProperty);

            SkinnedMeshRenderer renderer = rendererProperty.objectReferenceValue as SkinnedMeshRenderer;

            if (renderer != null)
            {
                bool isAsset = AssetDatabase.Contains(renderer);

                if (isAsset)
                {
                    EditorGUILayout.ObjectField("Shared Mesh", renderer.sharedMesh, typeof(UnityEngine.Mesh), false);
                }
                else
                {
                    EditorGUILayout.HelpBox(string.Format("{0} not exist in AssetDatabase. Reselect renderer asset in model data.", renderer.gameObject.name), MessageType.Error);
                }
            }

            serializedObject.ApplyModifiedProperties();

            Mesh mesh = renderer != null? renderer.sharedMesh: null;

            EditorGUI.BeginDisabledGroup(mesh == null);

            EditorGUILayout.Space();

            originDataToggle = EditorGUILayout.Foldout(originDataToggle, "Origin Data");

            if (originDataToggle)
            {
                EditorGUILayout.Space();

                EditorGUI.indentLevel++;

                if (mesh != null)
                {
                    EditorGUILayout.LabelField("Bones", renderer.bones != null ? renderer.bones.Length.ToString() : "null");
                    EditorGUILayout.LabelField("Vertex Count", mesh.vertexCount.ToString());
                    EditorGUILayout.LabelField("Index Count", mesh.triangles.Length.ToString());
                    EditorGUILayout.LabelField("Bone Weight Count", mesh.boneWeights != null ? mesh.boneWeights.Length.ToString() : "null");
                }
                else
                {
                    EditorGUILayout.HelpBox("Mesh is null.. please insert data above", MessageType.Error);
                }

                EditorGUI.indentLevel--;

                EditorGUI.EndDisabledGroup();
            }

            EditorGUILayout.Space();

            convertedDataToggle = EditorGUILayout.Foldout(convertedDataToggle, "Converted Data");

            if (convertedDataToggle)
            {
                EditorGUILayout.Space();

                EditorGUI.indentLevel++;

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Root Bone Name", chunk.rootBoneName != null ? chunk.rootBoneName : "null");

                EditorGUI.BeginDisabledGroup(chunk.rootBoneName == null);

                if (GUILayout.Button("Clear"))
                {
                    Undo.RecordObject(chunk, "Root Bone Name Clear");

                    chunk.rootBoneName = null;

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }

                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Each Bones Data", chunk.inverseRestPoseMatrixArray != null ? chunk.inverseRestPoseMatrixArray.Length.ToString() : "null");

                EditorGUI.BeginDisabledGroup(chunk.inverseRestPoseMatrixArray == null);

                if (GUILayout.Button("Clear"))
                {
                    Undo.RecordObject(chunk, "Bone Transform Data Clear");

                    chunk.indexedBoneNameArray = null;

                    chunk.inverseRestPoseMatrixArray   = null;
                    chunk.inverseRestPoseDQArray       = null;
                    chunk.inverseRestPoseRotationArray = null;

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }

                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();

                EditorGUILayout.LabelField("Vertex Count", chunk.dataPerVertex != null ? chunk.dataPerVertex.Length.ToString() : "null");

                EditorGUI.BeginDisabledGroup(chunk.dataPerVertex == null);

                if (GUILayout.Button("Clear"))
                {
                    Undo.RecordObject(chunk, "Mesh Data Clear");

                    chunk.dataPerVertex = null;
                    chunk.skinPerVertex = null;

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }

                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();

                EditorGUI.indentLevel++;

                EditorGUILayout.LabelField("1 Bone", chunk.boneVertexCount.x.ToString());
                EditorGUILayout.LabelField("2 Bone", chunk.boneVertexCount.y.ToString());
                EditorGUILayout.LabelField("3 Bone", chunk.boneVertexCount.z.ToString());
                EditorGUILayout.LabelField("4 Bone", chunk.boneVertexCount.w.ToString());

                EditorGUI.indentLevel--;

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Index Count", chunk.indices != null ? chunk.indices.Length.ToString() : "null");

                EditorGUI.BeginDisabledGroup(chunk.indices == null);

                if (GUILayout.Button("Clear"))
                {
                    Undo.RecordObject(chunk, "Index Clear");

                    chunk.indices = null;

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }

                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();

                EditorGUI.indentLevel--;
                EditorGUILayout.Space();

                EditorGUI.BeginDisabledGroup(mesh == null);

                if (GUILayout.Button(addTitle))
                {
                    Undo.RecordObject(chunk, addTitle);

                    AddDataPerVertex();

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
                }

                if (GUILayout.Button(overrideTitle))
                {
                    Undo.RecordObject(chunk, overrideTitle);

                    OverrideDataPerVertex();

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
                }

                if (GUILayout.Button(fillTitle))
                {
                    Undo.RecordObject(chunk, fillTitle);

                    FillDataPerVertex();

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
                }

                EditorGUILayout.Space();

                if (GUILayout.Button("Clear Converted Mesh Data"))
                {
                    Undo.RecordObject(chunk, "Clear Converted Mesh Data");

                    targetAs.Clear();

                    EditorUtility.SetDirty(target);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
                }

                EditorGUILayout.Space();

                centerOfRotationDataToggle = EditorGUILayout.Foldout(centerOfRotationDataToggle, "Center Of Rotation");

                if (centerOfRotationDataToggle)
                {
                    EditorGUILayout.Space();

                    EditorGUI.indentLevel++;

                    SerializedProperty clusterArrayProperty = serializedObject.FindProperty("clusterArray");
                    EditorGUILayout.PropertyField(clusterArrayProperty, true);

                    EditorGUILayout.LabelField("Clustered Vertex Index Count", chunk.clusteredVertexIndexArray != null ? chunk.clusteredVertexIndexArray.Length.ToString() : "null");
                    EditorGUILayout.LabelField("Clustered Index Index Count", chunk.clusteredTriangleIndexArray != null ? chunk.clusteredTriangleIndexArray.Length.ToString() : "null");

                    EditorGUILayout.Space();

                    distanceThreshold = EditorGUILayout.DelayedFloatField("Distance Threshold", distanceThreshold);

                    EditorGUILayout.Space();

                    if (GUILayout.Button("Calculate Center Of Cluster"))
                    {
                        Undo.RecordObject(chunk, "Calculate Center Of Cluster");

                        IEnumerator <int> enumer    = chunk.CalculateCluster(distanceThreshold);
                        DateTime          startTime = DateTime.Now;

                        while (enumer.MoveNext())
                        {
                            EditorUtility.DisplayProgressBar("Calculate Center Of Cluster", enumer.Current.ToString(), (float)enumer.Current / chunk.vertexCount);
                        }

                        EditorUtility.ClearProgressBar();

                        Debug.Log(String.Format("Time : {0}", ((double)(DateTime.Now - startTime).Ticks / TimeSpan.TicksPerSecond)));

                        EditorUtility.SetDirty(target);
                        AssetDatabase.SaveAssets();
                        AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
                    }

                    EditorGUILayout.Space();

                    SerializedProperty calculateThreadNumberProperty = serializedObject.FindProperty("calculateThreadNumber");
                    EditorGUILayout.PropertyField(calculateThreadNumberProperty);

                    SerializedProperty similarityKernelProperty = serializedObject.FindProperty("similarityKernel");
                    EditorGUILayout.PropertyField(similarityKernelProperty);

                    SerializedProperty similarityThresholdProperty = serializedObject.FindProperty("similarityThreshold");
                    EditorGUILayout.PropertyField(similarityThresholdProperty);

                    EditorGUILayout.Space();

                    EditorGUILayout.LabelField("Center Of Rotation", chunk.centerOfRotationPositionArray != null ? chunk.centerOfRotationPositionArray.Length.ToString() : "null");

                    EditorGUILayout.Space();

                    if (GUILayout.Button("Log vertices"))
                    {
                        System.Text.StringBuilder builder = new System.Text.StringBuilder();

                        Array.ForEach(chunk.centerOfRotationPositionArray, (cor) => { builder.Append(cor.ToString("F4")).Append("\n"); });

                        Debug.Log(builder.ToString());
                    }

                    if (GUILayout.Button("Calculate Center Of Rotation Position"))
                    {
                        Undo.RecordObject(chunk, "Calculate Center Of Rotation Position");

                        RenderChunkHandler.CoRProcessThreadState[] stateArray = chunk.CalculateCenterOfRotation(chunk.calculateThreadNumber, similarityKernel, similarityThreshold);

                        if (stateArray != null)
                        {
                            while (!Array.TrueForAll(stateArray, (state) => state.done || state.fail))
                            {
                                int sumedProcessCount = 0;
                                for (int i = 0; i < stateArray.Length; i++)
                                {
                                    sumedProcessCount += stateArray[i].processCount;
                                }

                                EditorUtility.DisplayProgressBar(
                                    "Calculate Center Of Rotation Position",
                                    String.Format("Processed vertex number : {0}", sumedProcessCount),
                                    (float)sumedProcessCount / chunk.vertexCount
                                    );
                            }

                            int emptyCount = 0;
                            for (int i = 0; i < stateArray.Length; i++)
                            {
                                emptyCount += stateArray[i].emptyCount;
                            }

                            Debug.LogFormat("Calculated similarity count : {0}, empty similarity count : {1}", chunk.vertexCount - emptyCount, emptyCount);

                            EditorUtility.ClearProgressBar();

                            EditorUtility.SetDirty(target);
                            AssetDatabase.SaveAssets();
                            AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
                        }
                    }

                    EditorGUI.indentLevel--;
                }

                EditorGUI.EndDisabledGroup();
            }

            EditorGUILayout.Space();

            logSimilarityToggle = EditorGUILayout.Foldout(logSimilarityToggle, "Log Similarity and Weight Distance");

            if (logSimilarityToggle)
            {
                EditorGUI.indentLevel++;

                EditorGUILayout.Space();

                cmpIndex1 = EditorGUILayout.IntSlider("Compare Index 1", cmpIndex1, 0, chunk.vertexCount - 1);
                cmpIndex2 = EditorGUILayout.IntSlider("Compare Index 2", cmpIndex2, 0, chunk.vertexCount - 1);
                simKernel = EditorGUILayout.FloatField("Similarity Kernel", simKernel);

                EditorGUILayout.Space();

                EditorGUILayout.LabelField
                (
                    "Vertex Weight 1",
                    String.Format
                    (
                        "{0}, {1}",
                        chunk.skinPerVertex[cmpIndex1].index, chunk.skinPerVertex[cmpIndex1].weight
                    )
                );
                EditorGUILayout.LabelField
                (
                    "Vertex Weight 2",
                    String.Format
                    (
                        "{0}, {1}",
                        chunk.skinPerVertex[cmpIndex2].index, chunk.skinPerVertex[cmpIndex2].weight
                    )
                );

                EditorGUILayout.Space();

                EditorGUILayout.LabelField("Similarity", chunk.GetSimliarity(cmpIndex1, cmpIndex2, simKernel).ToString());
                EditorGUILayout.LabelField("Weight distance", chunk.skinPerVertex[cmpIndex1].GetWeightDistance(chunk.skinPerVertex[cmpIndex2]).ToString());

                EditorGUILayout.Space();

                EditorGUI.indentLevel--;
            }

            serializedObject.ApplyModifiedProperties();
        }