Преглед изворни кода

Expand GLTF Model support (#1108)

* Update GLTF support to include loading color for albdeo (saved in the color value of the materialmap), support occlussion and emmission maps.. as well as some quality of life updates.

* clean up to use single image
Tyler Jessilynn Bezera пре 5 година
родитељ
комит
e7fdf8a13d
1 измењених фајлова са 48 додато и 39 уклоњено
  1. 48 39
      src/models.c

+ 48 - 39
src/models.c

@@ -3377,9 +3377,9 @@ static unsigned char *DecodeBase64(char *input, int *size)
 }
 
 // Load texture from cgltf_image
-static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
+static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
 {
-    Texture texture = { 0 };
+    Image rimage = { 0 };
 
     if (image->uri)
     {
@@ -3406,22 +3406,18 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
                 int w, h;
                 unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
 
-                Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
+                rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
 
                 // TODO: Tint shouldn't be applied here!
                 ImageColorTint(&rimage, tint);
-                texture = LoadTextureFromImage(rimage);
-                UnloadImage(rimage);
             }
         }
         else
         {
-            Image rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
+            rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
 
             // TODO: Tint shouldn't be applied here!
             ImageColorTint(&rimage, tint);
-            texture = LoadTextureFromImage(rimage);
-            UnloadImage(rimage);
         }
     }
     else if (image->buffer_view)
@@ -3440,41 +3436,36 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
         unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
         free(data);
 
-        Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
+        rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
         free(raw);
 
         // TODO: Tint shouldn't be applied here!
         ImageColorTint(&rimage, tint);
-        texture = LoadTextureFromImage(rimage);
-        UnloadImage(rimage);
     }
     else
     {
-        Image rimage = LoadImageEx(&tint, 1, 1);
-        texture = LoadTextureFromImage(rimage);
-        UnloadImage(rimage);
+        rimage = LoadImageEx(&tint, 1, 1);
     }
 
-    return texture;
+    return rimage;
 }
 
-// Load glTF mesh data
+// LoadGLTF loads in model data from given filename, supporting both .gltf and .glb
 static Model LoadGLTF(const char *fileName)
 {
     /***********************************************************************************
 
-        Function implemented by Wilhem Barbier (@wbrbr)
+        Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend) 
 
         Features:
           - Supports .gltf and .glb files
           - Supports embedded (base64) or external textures
-          - Loads the albedo/diffuse texture (other maps could be added)
+          - Loads all raylib supported material textures, values and colors
           - Supports multiple mesh per model and multiple primitives per model
 
         Some restrictions (not exhaustive):
           - Triangle-only meshes
           - Not supported node hierarchies or transforms
-          - Only loads the diffuse texture... but not too hard to support other maps (normal, roughness/metalness...)
           - Only supports unsigned short indices (no byte/unsigned int)
           - Only supports float for texture coordinates (no byte/unsigned short)
 
@@ -3547,44 +3538,62 @@ static Model LoadGLTF(const char *fileName)
             //Ensure material follows raylib support for PBR (metallic/roughness flow)
             if (data->materials[i].has_pbr_metallic_roughness)
             {
-                float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
-                float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
+                tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0] * 255);
+                tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1] * 255);
+                tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2] * 255);
+                tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3] * 255);
 
-                // NOTE: Material name not used for the moment
-                //if (model.materials[i].name && data->materials[i].name) strcpy(model.materials[i].name, data->materials[i].name);
-
-                // TODO: REview: shouldn't these be *255 ???
-                tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
-                tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
-                tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
-                tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
-
-                model.materials[i].maps[MAP_ROUGHNESS].color = tint;
+                model.materials[i].maps[MAP_ALBEDO].color = tint;
 
                 if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
                 {
-                    model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
+                    Image albedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromImage(albedo);
+                    UnloadImage(albedo);
                 }
 
-                // NOTE: Tint isn't need for other textures.. pass null or clear?
-                // Just set as white, multiplying by white has no effect
+                //Set tint to white after it's been used by Albedo
                 tint = WHITE;
 
                 if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
                 {
-                    model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
+                    Image metallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromImage(metallicRoughness);
+
+                    float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
+                    model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
+
+                    float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
+                    model.materials[i].maps[MAP_METALNESS].value = metallic;
+
+                    UnloadImage(metallicRoughness);
                 }
-                model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
-                model.materials[i].maps[MAP_METALNESS].value = metallic;
+
+
 
                 if (data->materials[i].normal_texture.texture)
                 {
-                    model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
+                    Image normalImage = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromImage(normalImage);
+                    UnloadImage(normalImage);
                 }
 
                 if (data->materials[i].occlusion_texture.texture)
                 {
-                    model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
+                    Image occulsionImage = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromImage(occulsionImage);
+                    UnloadImage(occulsionImage);
+                }
+
+                if (data->materials[i].emissive_texture.texture)
+                {
+                    Image emissiveImage = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_EMISSION].texture = LoadTextureFromImage(emissiveImage);
+                    tint.r = (unsigned char)(data->materials[i].emissive_factor[0] * 255);
+                    tint.g = (unsigned char)(data->materials[i].emissive_factor[1] * 255);
+                    tint.b = (unsigned char)(data->materials[i].emissive_factor[2] * 255);
+                    model.materials[i].maps[MAP_EMISSION].color = tint;
+                    UnloadImage(emissiveImage);
                 }
             }
         }