Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues 1 fix #2

Merged
merged 5 commits into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
648 changes: 648 additions & 0 deletions .editorconfig

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions Assets/Editor/PackageVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;

public static class PackageVersion
{
private static ListRequest _request;
private static int _progressId;

/// <summary>
/// Package check will start on Editor start
/// </summary>
[InitializeOnLoadMethod]
public static void GetPackageList()
{
// List packages installed for the project
_request = Client.List();
_progressId = Progress.Start("Package version check");
//Injection update loop
EditorApplication.update += VersionCheck;
}

/// <summary>
/// Make sure the collection version conforms to the specification
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Error in Status</exception>
private static void VersionCheck()
{
switch (_request.Status)
{
case StatusCode.Success:
{
Progress.Report(_progressId, 2, 3, "Checking the version");
//version detection operation
foreach (var info in _request.Result)
if (info.name == "com.unity.collections")
Debug.Log(info.version);

Progress.Report(_progressId, 3, 3);
break;
}
case StatusCode.Failure:
{
Debug.LogWarning(_request.Error.message);
break;
}
case StatusCode.InProgress:
{
Progress.Report(_progressId, 1, 3, "Waiting package list");
return;
}
default:
throw new ArgumentOutOfRangeException();
}

Progress.Remove(_progressId);
EditorApplication.update -= VersionCheck;
}
}
3 changes: 3 additions & 0 deletions Assets/Editor/PackageVersion.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Assets/Editor/SmoothNormals.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions Assets/Editor/SmoothNormals/BakeNormalJob.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

internal struct BakeNormalJob : IJobParallelFor
{
[ReadOnly] private NativeArray<Vector3> _normals;
[ReadOnly] private NativeArray<Vector4> _tangents;
[ReadOnly] private NativeArray<Vector3> _vertex;
[ReadOnly] private NativeParallelMultiHashMap<Vector3, Vector3> _result;
[ReadOnly] private readonly bool _existColors;
private NativeArray<Color> _colors;

public BakeNormalJob(NativeArray<Vector3> vertex, NativeArray<Vector3> normals, NativeArray<Vector4> tangents,
NativeParallelMultiHashMap<Vector3, Vector3> result, bool existColors, NativeArray<Color> colors)
{
_normals = normals;
_tangents = tangents;
_vertex = vertex;
_result = result;
_existColors = existColors;
_colors = colors;
}

void IJobParallelFor.Execute(int index)
{
var smoothedNormals = Vector3.zero;
var vertex = _vertex[index];

foreach (var values in _result.GetValuesForKey(vertex)) smoothedNormals += values;

smoothedNormals = smoothedNormals.normalized;

var biNormal = (Vector3.Cross(_normals[index], _tangents[index]) * _tangents[index].w).normalized;

var tbn = new Matrix4x4(
_tangents[index],
biNormal,
_normals[index],
Vector4.zero);
tbn = tbn.transpose;

//Calculate the normal vector in model space
var bakedNormal = tbn.MultiplyVector(smoothedNormals).normalized;

//Remapping [-1,1] to [0,1]
var color = new Color
{
r = bakedNormal.x * 0.5f + 0.5f,
g = bakedNormal.y * 0.5f + 0.5f,
b = bakedNormal.z * 0.5f + 0.5f,
/*
* Choose a color channel
* b = _existColors ? m_Colors[index].b : 1,
*/
a = _existColors ? _colors[index].a : 1
};
_colors[index] = color;
}
}
3 changes: 3 additions & 0 deletions Assets/Editor/SmoothNormals/BakeNormalJob.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions Assets/Editor/SmoothNormals/CollectNormalJob.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

internal struct CollectNormalJob : IJobParallelFor
{
// Mark read-only to improve performance
[ReadOnly] private NativeArray<Vector3> _normals, _vertex;

private NativeParallelMultiHashMap<Vector3, Vector3>.ParallelWriter _result;

public CollectNormalJob(NativeArray<Vector3> normals, NativeArray<Vector3> vertex,
NativeParallelMultiHashMap<Vector3, Vector3>.ParallelWriter result)
{
_normals = normals;
_vertex = vertex;
_result = result;
}

void IJobParallelFor.Execute(int index)
{
_result.Add(_vertex[index], _normals[index]);
}
}
3 changes: 3 additions & 0 deletions Assets/Editor/SmoothNormals/CollectNormalJob.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,111 +1,16 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using Unity.Collections;
using Unity.Jobs;
using System.IO;

internal struct CollectNormalJob : IJobParallelFor
{
// Mark read-only to improve performance
[ReadOnly] private NativeArray<Vector3> m_Normals, m_Vertex;

private NativeMultiHashMap<Vector3, Vector3>.ParallelWriter m_Result;

public CollectNormalJob(NativeArray<Vector3> normals, NativeArray<Vector3> vertex, NativeMultiHashMap<Vector3, Vector3>.ParallelWriter result)
{
m_Normals = normals;
m_Vertex = vertex;
m_Result = result;
}

void IJobParallelFor.Execute(int index)
{
m_Result.Add(m_Vertex[index], m_Normals[index]);
}
}

internal struct BakeNormalJob : IJobParallelFor
{
[ReadOnly] private NativeArray<Vector3> m_Normals;
[ReadOnly] private NativeArray<Vector4> m_Tangents;
[ReadOnly] private NativeArray<Vector3> m_Vertex;
[ReadOnly] private NativeMultiHashMap<Vector3, Vector3> m_Result;
[ReadOnly] private readonly bool m_ExistColors;
private NativeArray<Color> m_Colors;

public BakeNormalJob(NativeArray<Vector3> vertex, NativeArray<Vector3> normals, NativeArray<Vector4> tangents, NativeMultiHashMap<Vector3, Vector3> result, bool existColors, NativeArray<Color> colors)
{
m_Normals = normals;
m_Tangents = tangents;
m_Vertex = vertex;
m_Result = result;
m_ExistColors = existColors;
m_Colors = colors;
}

void IJobParallelFor.Execute(int index)
{
var smoothedNormals = Vector3.zero;
var vertex = m_Vertex[index];

foreach (var values in m_Result.GetValuesForKey(vertex))
{
smoothedNormals += values;
}

smoothedNormals = smoothedNormals.normalized;

var biNormal = (Vector3.Cross(m_Normals[index], m_Tangents[index]) * m_Tangents[index].w).normalized;

var tbn = new Matrix4x4(
m_Tangents[index],
biNormal,
m_Normals[index],
Vector4.zero);
tbn = tbn.transpose;

//Calculate the normal vector in model space
var bakedNormal = tbn.MultiplyVector(smoothedNormals).normalized;

//Remapping [-1,1] to [0,1]
var color = new Color
{
r = (bakedNormal.x * 0.5f) + 0.5f,
g = (bakedNormal.y * 0.5f) + 0.5f,
b = (bakedNormal.z * 0.5f) + 0.5f,
// b = m_ExistColors ? m_Colors[index].b : 1,
a = m_ExistColors ? m_Colors[index].a : 1
};
m_Colors[index] = color;
}
}
using UnityEditor;
using UnityEngine;

public class OutlineModelImporter : AssetPostprocessor
{
private const string Suffix = "_ol";
private const string Prefix = "smoothed_";

// Called before model import
private void OnPreprocessModel()
{
// Only smoothed_xxx can enter
if (!assetPath.Contains(Prefix)) return;

// Change the import settings
// Use Unity's own algorithm to smooth the model will force the merge of coincident vertices
var model = assetImporter as ModelImporter;
if (model == null) throw new NullReferenceException();

model.importNormals = ModelImporterNormals.Calculate;
model.normalCalculationMode = ModelImporterNormalCalculationMode.AngleWeighted;
model.normalSmoothingAngle = 180.0f;
model.importAnimation = false;
model.materialImportMode = ModelImporterMaterialImportMode.None;
Debug.Log("Temporary file created successfully");
}

// Called after the Game Object is generated
// The modification to the Game Object will affect the generated result but the reference will not be retained
private void OnPostprocessModel(GameObject modelObject)
Expand All @@ -117,22 +22,20 @@ private void OnPostprocessModel(GameObject modelObject)
var model = assetImporter as ModelImporter;
if (model == null) throw new NullReferenceException();

string srcPath = model.assetPath;
string dstPath = Path.GetDirectoryName(srcPath) + "/" + Prefix + Path.GetFileName(srcPath);
var srcPath = model.assetPath;
var dstPath = Path.GetDirectoryName(srcPath) + "/" + Prefix + Path.GetFileName(srcPath);

string copyPath = Application.dataPath + "/" + dstPath[7..];
var copyPath = Application.dataPath + "/" + dstPath[7..];
if (File.Exists(copyPath))
{
//If it exists, smooth its normal
//If the object exists, smooth its normal
var copy = AssetDatabase.LoadAssetAtPath<GameObject>(dstPath);

Dictionary<string, Mesh> originalMesh = GetMesh(modelObject);
Dictionary<string, Mesh> smoothedMesh = GetMesh(copy);
var originalMesh = GetMesh(modelObject);
var smoothedMesh = GetMesh(copy);

foreach (var (name, mesh) in originalMesh)
{
mesh.colors = ComputeSmoothedNormalByJob(smoothedMesh[Prefix + name], mesh);
}

AssetDatabase.DeleteAsset(dstPath);
AssetDatabase.Refresh();
Expand All @@ -147,10 +50,29 @@ private void OnPostprocessModel(GameObject modelObject)
}
}

// Called before model import
private void OnPreprocessModel()
{
// Only smoothed_xxx can enter
if (!assetPath.Contains(Prefix)) return;

// Change the import settings
// Use Unity's own algorithm to smooth the model will force the merge of coincident vertices
var model = assetImporter as ModelImporter;
if (model == null) throw new NullReferenceException();

model.importNormals = ModelImporterNormals.Calculate;
model.normalCalculationMode = ModelImporterNormalCalculationMode.AngleWeighted;
model.normalSmoothingAngle = 180.0f;
model.importAnimation = false;
model.materialImportMode = ModelImporterMaterialImportMode.None;
Debug.Log("Temporary file created successfully");
}

/// <summary>
/// Get all meshes in the model and children,MeshFilter and SkinnedMesh
/// Get all meshes in the model and children,MeshFilter and SkinnedMesh
/// </summary>
/// <param name="go">target model</param>
/// <param name="go">Target model</param>
/// <returns>The meshes dictionary </returns>
private Dictionary<string, Mesh> GetMesh(GameObject go)
{
Expand All @@ -170,35 +92,37 @@ private Color[] ComputeSmoothedNormalByJob(Mesh smoothedMesh, Mesh originalMesh)
var smoothedMeshVertexCount = smoothedMesh.vertexCount;
var originalMeshVertexCount = originalMesh.vertexCount;

// original data
// Original data
var originalNormals = new NativeArray<Vector3>(originalMesh.normals, Allocator.Persistent);
var originalVertices = new NativeArray<Vector3>(originalMesh.vertices, Allocator.Persistent);
var originalTangents = new NativeArray<Vector4>(originalMesh.tangents, Allocator.Persistent);
var originalColors = new NativeArray<Color>(originalMeshVertexCount, Allocator.Persistent);
var existColors = originalMesh.colors.Length == originalMeshVertexCount;
if (existColors) originalColors.CopyFrom(originalMesh.colors);

// smoothed data
// Smoothed data
var smoothedNormals = new NativeArray<Vector3>(smoothedMesh.normals, Allocator.Persistent);
var smoothedVertices = new NativeArray<Vector3>(smoothedMesh.vertices, Allocator.Persistent);
var targetNormals = new NativeArray<Vector3>(smoothedMeshVertexCount, Allocator.Persistent);

//result data
var result = new NativeMultiHashMap<Vector3, Vector3>(originalMeshVertexCount * 3, Allocator.Persistent);
// Result data
var result =
new NativeParallelMultiHashMap<Vector3, Vector3>(originalMeshVertexCount * 3, Allocator.Persistent);
var resultParallel = result.AsParallelWriter();

var collectNormalJob = new CollectNormalJob(smoothedNormals, smoothedVertices, resultParallel);
var normalBakeJob = new BakeNormalJob(originalVertices, originalNormals, originalTangents, result, existColors, originalColors);
var normalBakeJob = new BakeNormalJob(originalVertices, originalNormals, originalTangents, result, existColors,
originalColors);

//Job execution
// Job execution
normalBakeJob.Schedule(originalMeshVertexCount, 100,
collectNormalJob.Schedule(smoothedMeshVertexCount, 100)).Complete();

// Copy result
var resultColors = new Color[originalColors.Length];
originalColors.CopyTo(resultColors);

// release memory
// Release memory
smoothedNormals.Dispose();
smoothedVertices.Dispose();
targetNormals.Dispose();
Expand Down
Loading