Sirop4ik
Sirop4ik

Reputation: 5243

how to apply texture on 3d model, dynamically?

I have a file where written array of vertexes, indexes, uv, textures and so on, in two words everything in order to draw model with texture on it. For example it is should be 3d cube with texture like wood.

So, what I have for now is - I can present vertexes of cube(I see my model), but I don't know how to apply a texture for this.

there is my code -

public void Start()
    {
        m_stream = DecoderAPI.create_stream_decoder_obj();
        string pathToFile = "path_to_my_file";
        bool isInitialized = DecoderAPI.stream_init_model(m_stream, pathToFile);

        if (isInitialized)
        {
            m_curFrame = DecoderAPI.stream_get_frame_obj(m_stream, 1);

            MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
            meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));
            Mesh mesh = new Mesh();

            //Vertices***
            int vertexCount = DecoderAPI.frame_get_vertex_count(m_curFrame);
            int xyzArrSize = vertexCount * 3;
            float[] xyzArray = new float[xyzArrSize];
            IntPtr xyz = DecoderAPI.frame_get_vertex_xyz(m_curFrame);
            Marshal.Copy(xyz, xyzArray, 0, xyzArrSize);
            Vector3[] vertices = new Vector3[vertexCount];

            for (int i = 0; i < vertexCount; i++)
            {
                vertices[i] = new Vector3(xyzArray[i * 3], xyzArray[i * 3 + 1], xyzArray[i * 3 + 2]);
            }

            mesh.vertices = vertices;
            //***

            //Faces***
            int faceCount = DecoderAPI.frame_face_count(m_curFrame);
            int trisArrSize = faceCount * 3;
            int[] tris = new int[trisArrSize];
            IntPtr indices = DecoderAPI.frame_face_indices(m_curFrame);
            Marshal.Copy(indices, tris, 0, trisArrSize);
            mesh.triangles = tris;
            //***

            mesh.RecalculateNormals();

            MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
            meshFilter.mesh = mesh;


            //TEXTURE ****
            int uvCount = DecoderAPI.frame_get_uv_count(m_curFrame);
            IntPtr uvData = DecoderAPI.frame_get_uv_data(m_curFrame);

            IntPtr textureObj = DecoderAPI.frame_get_texture_obj(m_curFrame);
            DecoderAPI.TextureInfo textureInfo = DecoderAPI.texture_get_info(textureObj);

            int width = textureInfo.width;
            int height = textureInfo.height;
            int channels = textureInfo.channels;
            int stride = textureInfo.stride;

            DecoderAPI.ColorType color_type = textureInfo.color_type;

            IntPtr pixels = textureInfo.pixels;

            HOW TO APPLY THIS TEXTURE DATA TO MY MODEL????
            //***

            DecoderAPI.frame_release(m_curFrame);
        }
    }

I found this answer - https://answers.unity.com/questions/390878/how-do-i-apply-a-texture-to-a-3d-model.html

but I need to know to apply it dynamically

Any suggestions? Or maybe some thinks to tutorials?

EDIT

public void Start()
    {
        m_stream = DecoderAPI.create_stream_decoder_obj();
        string pathToFile = "my_path_to_file";
        bool isInitialized = DecoderAPI.stream_init_model(m_stream, pathToFile);

        if (isInitialized)
        {
            m_curFrame = DecoderAPI.stream_get_frame_obj(m_stream, 1);

            MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();

            meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));

            Mesh mesh = new Mesh();

            //Vertices***
            int vertexCount = DecoderAPI.frame_get_vertex_count(m_curFrame);
            int xyzArrSize = vertexCount * 3;
            float[] xyzArray = new float[xyzArrSize];
            IntPtr xyz = DecoderAPI.frame_get_vertex_xyz(m_curFrame);
            Marshal.Copy(xyz, xyzArray, 0, xyzArrSize);
            Vector3[] vertices = new Vector3[vertexCount];

            for (int i = 0; i < vertexCount; i++)
            {
                vertices[i] = new Vector3(xyzArray[i * 3], xyzArray[i * 3 + 1], xyzArray[i * 3 + 2]);
            }

            mesh.vertices = vertices;
            //***

            //Faces***
            int faceCount = DecoderAPI.frame_face_count(m_curFrame);
            int trisArrSize = faceCount * 3;
            int[] tris = new int[trisArrSize];
            IntPtr indices = DecoderAPI.frame_face_indices(m_curFrame);
            Marshal.Copy(indices, tris, 0, trisArrSize);
            mesh.triangles = tris;
            //***

            mesh.RecalculateNormals();

            //UV***
            int uvCount = DecoderAPI.frame_get_uv_count(m_curFrame);
            IntPtr uvData = DecoderAPI.frame_get_uv_data(m_curFrame);
            int uvArrSize = uvCount * 2;
            float[] uvArr = new float[uvArrSize];
            Vector2[] uv = new Vector2[uvCount];
            Marshal.Copy(uvData, uvArr, 0, uvArrSize);

            for(int i = 0; i < uvCount; i++)
            {
                uv[i] = new Vector2(uvArr[i * 2], uvArr[i * 2 + 1]);
            }

            mesh.uv = uv;
            //***

            MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
            meshFilter.mesh = mesh;

            //TEXTURE ****
            IntPtr textureObj = DecoderAPI.frame_get_texture_obj(m_curFrame);
            DecoderAPI.TextureInfo textureInfo = DecoderAPI.texture_get_info(textureObj);

            int width = textureInfo.width;
            int height = textureInfo.height;
            int channels = textureInfo.channels;
            int stride = textureInfo.stride;

            DecoderAPI.ColorType color_type = textureInfo.color_type;

            IntPtr pixels = textureInfo.pixels;

            Texture2D texture = new Texture2D(width, height);
            texture.LoadRawTextureData(pixels, width * channels *height);
            texture.Apply();

            meshRenderer.material.SetTexture("_MainText", texture);
            //***

            DecoderAPI.frame_release(m_curFrame);
        }
    }

But for now I am getting such an error

UnityException: LoadRawTextureData: not enough data provided (will result in overread).
UnityEngine.Texture2D.LoadRawTextureData (System.IntPtr data, System.Int32 size) (at <a9810827dce3444a8e5c4e9f3f5e0828>:0)
Model.Start () (at Assets/Scripts/Model.cs:98)

What am I doing wrong?

Upvotes: 1

Views: 554

Answers (2)

Rub&#233;n Cant&#243;n
Rub&#233;n Cant&#243;n

Reputation: 124

If you have a texture and a MeshRenderer, it works like this:

void SetYourTexture()
{        
  MeshRenderer yourMeshRenderer = GetComponent<MeshRenderer>();
  //If you only need one texture at the material unity understand _MainText as the mainTexture;
  yourMeshRenderer.material.SetTexture("_MainText", yourTexture);
}

Upvotes: 0

Pino De Francesco
Pino De Francesco

Reputation: 756

First off, your code to construct the cube is missing the UV part, so even if you assign the texture to the material the result is undetermined. Look at the code samples in Mesh manual page about adding the UV as well: https://docs.unity3d.com/ScriptReference/Mesh.html

Once you have the UV, all you have to do is to set the texture using SetTexture (see https://docs.unity3d.com/ScriptReference/Material.SetTexture.html).

On a separate note, in your code, you are using Shared Material instead of Material: that is not advisable unless you have many objects all using the same material and you want to change them all.

EDIT: To get a texture from a pixels buffer you create a Texture2D object of the given size and colour type, then you apply the data like this:

        myTexture.LoadRawTextureData(myPixels);
        myTexture.Apply();

~Pino

Upvotes: 1

Related Questions