找回密码
 立即注册
查看: 342|回复: 0

将镜像模型导入Unity后法线翻转的问题

[复制链接]
发表于 2022-1-12 08:35 | 显示全部楼层 |阅读模式
封面PID:#942524671
一:问题概述

一般在3dmax行业内通常老手会少用“镜像”这个操作,因为3dmax本身的镜像是从发布到现在的3dmax 2021一直存在BUG的。(Blender和C4D似乎不存在这个问题)。
模型镜像后,法线也跟着反转了(3dmax本身默认开启了双面显示的功能,所以很难发现这个问题,除非给模型勾选了“背面消隐”),就像下图这样 ↓ (已开启背面消隐)



可以很明显地看到Utah Teapot的法线是反的,能够看到内部

正因为把镜像的模型导入进Unity3d或UE里总会出现各种各样的法线问题,所以老手也会用一些方案来解决这个问题,包括

  • Reset XForm(外网也推荐的方案)
  • 把已经镜像的模型添加法线修改器翻转再塌陷(但这样在3dmax里就很难直观地观看模型了,属于是模型导出之前的最后一步放弃治疗的操作hhh)
  • 塌陷成可编辑网格而不是可编辑多边形(蜜汁操作?)
  • Unity中使用微调过的Shader,例如加一句Cull Off/Front/Back等(不建议瞎使用,浪费性能)



4种解决方案

二:脚本解决

我测试了似乎高版本的Unity已经解决了这个镜像模型导入后的问题?不需要以上的解决方案导进去显示也是正常的(我使用的untiy 2020.2.4 URP管线)。
但无奈的是楼底下程序部门还一直使用旧版本的Unity 5.2,让他们换SRP得重构之前写的代码,我嘴皮子都磨烂了还是不肯换2333,换用SRP这个东西估计一时半会儿是没法在新项目上落实了。(悲)
基于这个eggpain的问题我写了一个unity脚本供参考,似乎也可以解决这个问题,hhh,不多说了代码奉上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlipNormal : MonoBehaviour
{
    public GameObject InvertObject;
    //选择一个要反转的物体

    void Awake()
    {
        InvertSphere();//瞎取一个函数名
    }

    void InvertSphere()
    {
        //==============================================
        Vector3[] normals = InvertObject.GetComponent<MeshFilter>().sharedMesh.normals;
        //这一段把模型的每一个法线反转了
        for(int i = 0; i < normals.Length; i++)
        {
            normals = -normals;
        }
        InvertObject.GetComponent<MeshFilter>().sharedMesh.normals = normals;
        //更新反转后的法线
        //==============================================

        //仅仅翻转法线还不够,必须根据三角形遍历顺序把1-2-3改变成3-2-1,这样渲染管线应用阶段才会读翻转后的法线(在obj里表现为同时反转v和vn);
        //三角形换序的同时别忘了submesh也要继承,不然submesh对应的子材质就会变成仅有一个(Cuz Every material has a separate tri list)
        Material[] materials = InvertObject.GetComponent<Renderer>().materials;
        int SubmeshNum =  materials.Length;//统计子材质数量
        for (int j = 0; j < SubmeshNum; j++)
        {
            int[] triangles = InvertObject.GetComponent<MeshFilter>().sharedMesh.GetTriangles(j);//按每个submesh遍历三角形
            for (int index = 0; index < triangles.Length; index += 3)//submesh的每个三角形换序
            {
                int intermediate = triangles[index];
                triangles[index] = triangles[index + 2];
                triangles[index + 2] = intermediate;
            }
            InvertObject.GetComponent<MeshFilter>().sharedMesh.SetTriangles(triangles, j);//更新反转后的submesh三角形
        }
        //==============================================

    }
}

这个脚本直接拖到模型上面就能用了,并支持包含子材质的模型,不用一个个子材质换双面shader也算是优势之一?



三:参考资料

1:Unity法线翻转(flip normal)
2:SubMeshDescriptor

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-16 15:54 , Processed in 0.090882 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表