当前位置: 首页 > article >正文

Unity-AI-Deepseek生成的生成模型代码

结果

能用,不是很理想,从左到右,分别是body,眼睛,演睫毛,手指套(如果你知道这是什么)结果不是很理想 

(下面代码已包含,修复的切线只能传Vector3参数,Unity2022测试)

你们帮我看看,到底这个代码的质量如何,是否能用

明显它是知道的

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using UnityEngine.UIElements;

public class SkinnedMeshSplitterWindow : EditorWindow
{
    private GameObject targetObject;
    private Vector2 scrollPos;
 
    [MenuItem("Tools/Skinned--Mesh Splitter")]
    public static void ShowWindow()
    {
        GetWindow<SkinnedMeshSplitterWindow>("Mesh Splitter");
    }
 
    void OnGUI()
    {
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
        
        // 目标对象选择
        targetObject = (GameObject)EditorGUILayout.ObjectField("Target Object", 
            targetObject, typeof(GameObject), true);
 
        EditorGUILayout.Space(10);
 
        if (targetObject != null)
        {
            DrawMeshInfo();
            EditorGUILayout.Space(10);
            
            if (GUILayout.Button("Split SubMeshes", GUILayout.Height(30)))
            {
                SplitMeshes(targetObject);
            }
        }
        else
        {
            EditorGUILayout.HelpBox("Select a GameObject with MeshFilter or SkinnedMeshRenderer", 
                MessageType.Info);
        }
 
        EditorGUILayout.EndScrollView();
    }
 
    void DrawMeshInfo()
    {
        var smr = targetObject.GetComponent<SkinnedMeshRenderer>();
        var mf = targetObject.GetComponent<MeshFilter>();
 
        if (smr != null && smr.sharedMesh != null)
        {
            EditorGUILayout.LabelField("Skinned Mesh Info:", EditorStyles.boldLabel);
            EditorGUILayout.LabelField($"SubMeshes: {smr.sharedMesh.subMeshCount}");
            EditorGUILayout.LabelField($"Materials: {smr.sharedMaterials.Length}");
        }
        else if (mf != null && mf.sharedMesh != null)
        {
            EditorGUILayout.LabelField("Static Mesh Info:", EditorStyles.boldLabel);
            EditorGUILayout.LabelField($"SubMeshes: {mf.sharedMesh.subMeshCount}");
            EditorGUILayout.LabelField($"Materials: {targetObject.GetComponent<MeshRenderer>()?.sharedMaterials.Length ?? 0}");
        }
        else
        {
            EditorGUILayout.HelpBox("No valid mesh component found", MessageType.Warning);
        }
    }
 
    void SplitMeshes(GameObject originalObject)
    {
        // 处理SkinnedMeshRenderer
        var skinnedRenderer = originalObject.GetComponent<SkinnedMeshRenderer>();
        if (skinnedRenderer != null)
        {
            SplitSkinnedMesh(skinnedRenderer);
        }
 
        // 处理MeshFilter
        var meshFilter = originalObject.GetComponent<MeshFilter>();
        if (meshFilter != null)
        {
            SplitStaticMesh(meshFilter);
        }
    }
 
    void SplitSkinnedMesh(SkinnedMeshRenderer originalRenderer)
    {
        Mesh originalMesh = originalRenderer.sharedMesh;
        Transform rootBone = originalRenderer.rootBone;
        Transform[] bones = originalRenderer.bones;
        Material[] materials = originalRenderer.sharedMaterials;
 
        for (int subMeshIndex = 0; subMeshIndex < originalMesh.subMeshCount; subMeshIndex++)
        {
            GameObject newGo = CreateNewObject(originalRenderer.gameObject, subMeshIndex, "Skinned");
            
            SkinnedMeshRenderer newRenderer = newGo.AddComponent<SkinnedMeshRenderer>();
            newRenderer.sharedMesh = ProcessSubMesh(originalMesh, subMeshIndex);
            newRenderer.bones = bones;
            newRenderer.rootBone = rootBone;
            newRenderer.sharedMaterials = GetSubMaterials(materials, subMeshIndex);
        }
    }
 
    void SplitStaticMesh(MeshFilter originalFilter)
    {
        Mesh originalMesh = originalFilter.sharedMesh;
        MeshRenderer originalRenderer = originalFilter.GetComponent<MeshRenderer>();
        Material[] materials = originalRenderer?.sharedMaterials;
 
        for (int subMeshIndex = 0; subMeshIndex < originalMesh.subMeshCount; subMeshIndex++)
        {
            GameObject newGo = CreateNewObject(originalFilter.gameObject, subMeshIndex, "Static");
            
            MeshFilter newFilter = newGo.AddComponent<MeshFilter>();
            newFilter.sharedMesh = ProcessSubMesh(originalMesh, subMeshIndex);
            
            MeshRenderer newRenderer = newGo.AddComponent<MeshRenderer>();
            newRenderer.sharedMaterials = GetSubMaterials(materials, subMeshIndex);
        }
    }
 
    GameObject CreateNewObject(GameObject original, int index, string typePrefix)
    {
        GameObject newGo = new GameObject($"{original.name}_{typePrefix}_submesh_{index}");
        newGo.transform.SetParent(original.transform.parent);
        newGo.transform.localPosition = original.transform.localPosition;
        newGo.transform.localRotation = original.transform.localRotation;
        newGo.transform.localScale = original.transform.localScale;
        return newGo;
    }
 
    Mesh ProcessSubMesh(Mesh originalMesh, int subMeshIndex)
    {
        Mesh newMesh = new Mesh();
        
        // 获取三角形数据
        int[] triangles = originalMesh.GetTriangles(subMeshIndex);
        HashSet<int> vertexSet = new HashSet<int>(triangles);
 
        // 创建顶点映射表
        Dictionary<int, int> vertexMap = new Dictionary<int, int>();
        List<Vector3> newVertices = new List<Vector3>();
        
        // 收集所有顶点属性
        List<Vector3> newNormals = new List<Vector3>();
        List<Vector4> newTangents = new List<Vector4>();
        List<Vector2> newUV = new List<Vector2>();
        List<BoneWeight> newBoneWeights = new List<BoneWeight>();
 
        foreach (int index in vertexSet)
        {
            vertexMap[index] = newVertices.Count;
            newVertices.Add(originalMesh.vertices[index]);
            
            if (originalMesh.normals.Length > index)
                newNormals.Add(originalMesh.normals[index]);
            
            if (originalMesh.tangents.Length > index)
                newTangents.Add(originalMesh.tangents[index]);
            
            if (originalMesh.uv.Length > index)
                newUV.Add(originalMesh.uv[index]);
            
            if (originalMesh.boneWeights.Length > index)
                newBoneWeights.Add(originalMesh.boneWeights[index]);
        }
 
        // 重新映射三角形
        int[] newTriangles = new int[triangles.Length];
        for (int i = 0; i < triangles.Length; i++)
        {
            newTriangles[i] = vertexMap[triangles[i]];
        }
 
        // 设置网格数据
        newMesh.SetVertices(newVertices);
        if (newNormals.Count > 0) newMesh.SetNormals(newNormals);
        if (newTangents.Count > 0) newMesh.SetTangents(newTangents);
        if (newUV.Count > 0) newMesh.SetUVs(0, newUV);
        if (newBoneWeights.Count > 0) newMesh.boneWeights = newBoneWeights.ToArray();
        
        newMesh.triangles = newTriangles;
        newMesh.RecalculateBounds();
 
        // 复制混合形状(如果需要)
        if (originalMesh.blendShapeCount > 0)
        {
            for (int i = 0; i < originalMesh.blendShapeCount; i++)
            {
                Vector3[] deltaVertices = new Vector3[originalMesh.vertexCount];
                Vector3[] deltaNormals = new Vector3[originalMesh.vertexCount];
                Vector3[] deltaTangents = new Vector3[originalMesh.vertexCount];
                
                originalMesh.GetBlendShapeFrameVertices(i, 0, deltaVertices, deltaNormals, deltaTangents);
                
                List<Vector3> newDeltaVerts = new List<Vector3>();
                foreach (int index in vertexSet)
                {
                    newDeltaVerts.Add(deltaVertices[index]);
                }
                //做一个转换,不要最后切线的 w;第四个分量(w)是一个符号值(通常为1或-1),用于确定副切线(Bitangent)的方向。
                List<Vector3> temps = new List<Vector3>();
                for (int j =0; j< newTangents.Count; j++) {
                    Vector3 t = newTangents[i];
                    temps.Add(t);
                }
                newMesh.AddBlendShapeFrame(
                    originalMesh.GetBlendShapeName(i),
                    originalMesh.GetBlendShapeFrameWeight(i, 0),
                    newDeltaVerts.ToArray(),
                    deltaNormals.Length > 0 ? newNormals.ToArray() : null,
                    deltaTangents.Length > 0 ? temps.ToArray() : null
                );
            }
        }
 
        return newMesh;
    }
 
    Material[] GetSubMaterials(Material[] originalMaterials, int subMeshIndex)
    {
        if (originalMaterials == null || originalMaterials.Length == 0)
            return new Material[0];
 
        int materialIndex = Mathf.Clamp(subMeshIndex, 0, originalMaterials.Length - 1);
        return new Material[] { originalMaterials[materialIndex] };
    }
}

结果,我之后再截图吧

<最终生成结果在倒装,放文章最上面了。。。>

修复切线,切线对不上的。。。

指的是mesh 读取的是 tangents:Vector4,但是add mesh 只能 tangetns:Vector3// unity 的skinnedmesh 万年没有更新,想要对上,全靠“蒙”

1. 为什么有时是Vector3,有时是Vector4

  • Vector4的普遍性
    在Unity的网格数据(Mesh.tangents)中,切线默认存储为Vector4数组。这是因为法线贴图(Normal Mapping)需要完整的切线空间信息,而第四个分量(w)用于控制副切线(Bitangent)的方向。

  • Vector3的简化场景
    如果你在某些代码中看到Vector3的切线,可能是因为:

    • 在不需要法线贴图的场景中(例如仅使用顶点光照),开发者可能忽略第四个分量。

    • 旧版Unity或特定插件未正确处理切线数据。

2. Vector4的第四个分量(w)是什么?

  • 方向符号(Sign of Direction)
    第四个分量(w)是一个符号值(通常为1-1),用于确定副切线(Bitangent)的方向。
    副切线的计算公式为:

    cpp

    复制

    bitangent = cross(normal, tangent.xyz) * tangent.w;

http://www.kler.cn/a/597832.html

相关文章:

  • Matlab:二维绘图篇——plot绘图命令(二)
  • 编译原理——词法分析
  • Linux作业2——有关文件系统权限的练习
  • 物化视图详解:数据库性能优化的利器
  • 美制 / 英制单位换算/公制/帝国制 单位转换速查表
  • 某地基坑及周边建筑物自动化监测项目
  • ctfshow——web入门166~170
  • Can通信流程
  • 蓝桥杯11届 门牌制作
  • k8s问题排查
  • 表达式括号匹配(stack)(信息学奥赛一本通-1353)
  • Android笔记之项目引用第三方库(如:Github等)
  • 施耐德 Unity Pro 项目配置
  • 前后端开发中,图片上传到不同格式(二进制数据ORbase64编码)
  • AI比人脑更强,因为被植入思维模型【17】万物联系思维模型
  • Unity | 游戏数据配置
  • 如何在Linux CentOS上安装和配置Redis
  • Okhttp响应Json数据升级版源代码
  • JS 算术运算符
  • 在 coc.nvim 插件中,自动补全时,候选词后面的 大写字母