Unity报错“(isReadable is false; Read/Write must be enabled in import settings)“解决方法

导入到 Unity 的模型在未设置其 Read/Write 属性时无法在脚本中获取模型的相关信息:

在这里插入图片描述

此时若想在脚本中获取网格的顶点相关的信息则会报错:

public class MeshTest : MonoBehaviour
{
    void Start()
    {
        MeshFilter filter = GetComponent<MeshFilter>();
        if (filter != null)
        {
            Mesh mesh = filter.sharedMesh;
            Vector3[] verticies = mesh.vertices;
            Debug.Log(verticies.Length);
        }
    }
}

在这里插入图片描述

首先,回到代码中,Mesh 类的 vertices 属性具体实现如下:

namespace UnityEngine
{
    public sealed partial class Mesh : Object
    {
    	[FreeFunction(Name = "AllocExtractMeshComponentFromScript", HasExplicitThis = true)]
        extern private System.Array GetAllocArrayFromChannelImpl(VertexAttribute channel, VertexAttributeFormat format, int dim);

        private T[] GetAllocArrayFromChannel<T>(VertexAttribute channel, VertexAttributeFormat format, int dim)
        {
            if (canAccess)
            {
                if (HasVertexAttribute(channel))
                    return (T[])GetAllocArrayFromChannelImpl(channel, format, dim);
            }
            else
            {
                PrintErrorCantAccessChannel(channel);
            }
            return new T[0];
        }

        private T[] GetAllocArrayFromChannel<T>(VertexAttribute channel)
        {
            return GetAllocArrayFromChannel<T>(channel, VertexAttributeFormat.Float32, DefaultDimensionForChannel(channel));
        }

        public Vector3[] vertices
        {
            get { return GetAllocArrayFromChannel<Vector3>(VertexAttribute.Position); }
            set { SetArrayForChannel(VertexAttribute.Position, value, UnityEngine.Rendering.MeshUpdateFlags.Default); }
        }

    }
}

一层层查看,在 GetAllocArrayFromChannel 方法中,首先检查是否可访问,这里的 canAccess 属性获取的就是上面 Read/Write 属性设置的值,最后通过 GetAllocArrayFromChannelImpl 方法获取。

但是,由于权限问题无法直接调用 GetAllocArrayFromChannelImpl 方法来跳过检查,这里可以使用反射来访问 private 成员,以下是为 Mesh 类添加的扩展方法:

// MeshExtensions.cs

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;

public static class MeshExtensions
{
    // 使用反射方式调用 GetAllocArrayFromChannel 方法
    public static Array GetAllocArrayFromChannelImpl(this Mesh mesh, VertexAttribute channel, VertexAttributeFormat format, int dim)
    {
        MethodInfo method = typeof(Mesh).GetMethod("GetAllocArrayFromChannelImpl", BindingFlags.NonPublic | BindingFlags.Instance);
        object[] parameters = { channel, format, dim };
        return (Array)method.Invoke(mesh, parameters);
    }

    //

    static int DefaultDimensionForChannel(VertexAttribute channel)
    {
        if (channel == VertexAttribute.Position || channel == VertexAttribute.Normal)
            return 3;
        else if (channel >= VertexAttribute.TexCoord0 && channel <= VertexAttribute.TexCoord7)
            return 2;
        else if (channel == VertexAttribute.Tangent || channel == VertexAttribute.Color)
            return 4;

        throw new ArgumentException("DefaultDimensionForChannel called for bad channel", "channel");
    }

    public static T[] GetAllocArrayFromChannel<T>(this Mesh mesh, VertexAttribute channel, VertexAttributeFormat format, int dim)
    {
    	// 禁用原有代码中的访问检查
        // if (canAccess)
        {
            if (mesh.HasVertexAttribute(channel))
                return (T[])GetAllocArrayFromChannelImpl(mesh, channel, format, dim);
        }
        // else
        // {
        //     PrintErrorCantAccessChannel(channel);
        // }
        return new T[0];
    }

    public static T[] GetAllocArrayFromChannel<T>(this Mesh mesh, VertexAttribute channel)
    {
        return GetAllocArrayFromChannel<T>(mesh, channel, VertexAttributeFormat.Float32, DefaultDimensionForChannel(channel));
    }

    public static Vector3[] get_vertices(this Mesh mesh)
    {
        return GetAllocArrayFromChannel<Vector3>(mesh, VertexAttribute.Position);
    }

    public static Vector3[] get_normals(this Mesh mesh)
    {
        return GetAllocArrayFromChannel<Vector3>(mesh, VertexAttribute.Normal);
    }

    public static Vector2[] get_uv(this Mesh mesh)
    {
        return GetAllocArrayFromChannel<Vector2>(mesh, VertexAttribute.TexCoord0);
    }

}

在脚本中使用扩展方法:

public class MeshTest : MonoBehaviour
{
    void Start()
    {
        MeshFilter filter = GetComponent<MeshFilter>();
        if (filter != null)
        {
        	// 内置方法
            Mesh mesh = filter.sharedMesh;
            Vector3[] verticies = mesh.vertices;
            Debug.Log(verticies.Length);

			// 使用扩展方法获取顶点数据
            verticies = mesh.get_vertices();
            Debug.Log(verticies.Length);
            Debug.Log(verticies);
            Debug.Log(verticies[0]);
        }
    }
}

控制台输出如下,可以看到能够正常获取到顶点信息:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值