当前位置:网站首页>Cartoon rendering - average normal stroke
Cartoon rendering - average normal stroke
2022-07-02 09:03:00 【Ink pool Ivory】
【01】 Cartoon rendering from scratch - Stroke article ]
Recently learning rendering , I also learned when I started Back facing Stroke method , However, the cube is seriously fragmented , Just skip .
After reading this article, I learned how to average normals , The author saves the average normal to the tangent data of the model , It is also mentioned that you can convert to tangent space and then save to color or uv On . Because he only made the scheme of saving tangent data , I just want to try the scheme of using tangent space normals , Only when you write it out can you understand it well .
Slightly modify the author's tools , Save the grid locally .
《UnityShader Introduction to topic 》 Normal mapping related chapters of this book , Referred to the TBN matrix , stay C# Achieve it , And similar to the normal map, the numerical range is processed to [0,1].
Tools : Model average normal writes vertex color
[MenuItem("Tools/ Model average normal writes vertex color ")]
public static void WriteToColor()
{
MeshFilter[] meshFilters = Selection.activeGameObject.GetComponentsInChildren<MeshFilter>();
foreach (var meshFilter in meshFilters)
{
Mesh mesh = Object.Instantiate(meshFilter.sharedMesh);
ToColor(mesh);
AssetDatabase.CreateAsset(mesh, "Assets/" + meshFilter.name + "New.mesh");
}
SkinnedMeshRenderer[] skinMeshRenders = Selection.activeGameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (var skinMeshRender in skinMeshRenders)
{
Mesh mesh = Object.Instantiate(skinMeshRender.sharedMesh);
ToColor(mesh);
AssetDatabase.CreateAsset(mesh, "Assets/" + skinMeshRender.name + "New.mesh");
}
}
private static void ToColor(Mesh mesh)
{
var averageNormalHash = new Dictionary<Vector3, Vector3>();
for (var j = 0; j < mesh.vertexCount; j++)
{
if (!averageNormalHash.ContainsKey(mesh.vertices[j]))
{
averageNormalHash.Add(mesh.vertices[j], mesh.normals[j]);
}
else
{
averageNormalHash[mesh.vertices[j]] =
(averageNormalHash[mesh.vertices[j]] + mesh.normals[j]).normalized;
}
}
var averageNormals = new Vector3[mesh.vertexCount];
for (var j = 0; j < mesh.vertexCount; j++)
{
averageNormals[j] = averageNormalHash[mesh.vertices[j]];
// Go to tangent space And set it to [0,1] Range
var mNormal = mesh.normals[j];
var mTangent = mesh.tangents[j];
var mBinormal = Vector3.Cross(mNormal, new Vector3(mTangent.x, mTangent.y, mTangent.z)) * mTangent.w;
// Construction is by column , Here you need to press line
Matrix4x4 matrix = new Matrix4x4(new Vector3(mTangent.x, mTangent.y, mTangent.z).normalized, mBinormal.normalized, mNormal.normalized, Vector4.zero);
Matrix4x4 tmatrix = Matrix4x4.Transpose(matrix);
//[-1,1]=>[0,2]=>[0,1]
averageNormals[j] = (tmatrix.MultiplyVector(averageNormals[j]).normalized + Vector3.one) / 2.0f;
}
var colors = new Color[mesh.vertexCount];
for (var j = 0; j < mesh.vertexCount; j++)
{
colors[j] = new Color(averageNormals[j].x, averageNormals[j].y, averageNormals[j].z, 0);
}
mesh.colors = colors;
}
stay Shader It's similar , Transpose the matrix , It is the matrix from tangent space to model space
v2f vert(appdata v)
{
v2f o;
float4 pos = UnityObjectToClipPos(v.vertex);
TANGENT_SPACE_ROTATION;
float3 anormal = v.colors.rgb * 2 - 1;
// Transpose here ( The inverse ) once , because rotation Is the matrix from model space to tangent space
anormal = normalize(mul(transpose(rotation), anormal));
float3 viewNormal = mul((float3x3)UNITY_MATRIX_IT_MV, anormal.xyz);
float3 ndcNormal = normalize(TransformViewToProjection(viewNormal.xyz)) ;// Transform normals to NDC Space
float aspect = _ScreenParams.x / _ScreenParams.y;// Find the screen aspect ratio
ndcNormal.x /= aspect;
//pos.w It's about distance It will be removed after cutting , Zoom in and out , But we hope the trace in the distance is as big , So take it back , Avoid being eliminated
pos.xy += 0.01 * _OutlineScale * ndcNormal.xy * pos.w;
o.vertex = pos;
return o;
}
TANGENT_SPACE_ROTATION; You will get the model space to tangent space matrix rotation, Another transpose is tangent to model .
anormal Is the average normal in the restored model space
In order to be on the screen , No matter far or near, the stroke size remains the same , That is, to restore “ Perspective division ” To deal with , take w Multiply the weight back .
in addition , We found the extended x The incremental , After viewport transformation , It will be adjusted according to the screen resolution , The horizontal screen becomes larger and the vertical screen smaller , Therefore, it is also necessary to eliminate this influence .
边栏推荐
- NPOI 导出Word 字号对应
- 【Go实战基础】gin 高效神器,如何将参数绑定到结构体
- C# 高德地图 根据经纬度获取地址
- Kubedm deploys kubernetes v1.23.5 cluster
- Kubernetes deploys Loki logging system
- commands out of sync. did you run multiple statements at once
- QT -- how to set shadow effect in QWidget
- First week of JS study
- C#钉钉开发:取得所有员工通讯录和发送工作通知
- MYSQL安装出现问题(The service already exists)
猜你喜欢

C language implementation of mine sweeping game

远程连接IBM MQ报错AMQ4036解决方法

Linux安装Oracle Database 19c

Installing Oracle database 19C for Linux

win10使用docker拉取redis镜像报错read-only file system: unknown

Synchronize files using unison

Avoid breaking changes caused by modifying constructor input parameters

commands out of sync. did you run multiple statements at once

查看was发布的应用程序的端口

Qt——如何在QWidget中设置阴影效果
随机推荐
Openshift deployment application
Function ‘ngram‘ is not defined
Qt的拖动事件
Select sort and insert sort
Pyspark de duplication dropduplicates, distinct; withColumn、lit、col; unionByName、groupBy
Oracle 相关统计
一个经典约瑟夫问题的分析与解答
OpenFeign 简单使用
WSL安装、美化、网络代理和远程开发
【Go实战基础】gin 如何验证请求参数
Minecraft air Island service
C # save web pages as pictures (using WebBrowser)
Openshift container platform community okd 4.10.0 deployment
图像变换,转置
Gateway is easy to use
使用递归函数求解字符串的逆置问题
Illegal use of crawlers, an Internet company was terminated, the police came to the door, and 23 people were taken away
How to realize asynchronous programming in a synchronous way?
判断是否是数独
Qt的右键菜单