Beyond Unity 6 - Core Engine Woos

Allow me to rephrase.

@ anybody on the Unity engineering? coding? demigod? team.

The Issue:
The importer is currently importing values from .blend files incorrectly.

The error is not unity floating point related in scene as I can manually fix the values without issue.
In Short: The values are wrongly imported.

There is no other explanation that i can think of for what I am experiencing, which is half a work days
worth of back log trying to spot and fix the differences between Blender and Unity.

Even if blender uses double precision, when dealing with a figure that is less then 7 figures long,
there is next to zero error when the value is passed to a float, that I know of.

Now, before I waist a month developing a proper exporter and importer that handles everything
properly from; mesh to object to animation to w/e is required. I would like to ask the following question
of the people that actively develop the code for the Engine or those that do actually know or can get
the answers to 2, simple, strait forward questions of which the second is only available based on the
condition of the first.

The Questions:

Is the Importer planned to be fixed? and if so, when?

Or if this Question Post is to complicated.

using UnityDevTeam;
using UnityEngine;
using UnityEditor;

namespace HonourDemon {
   public class ImportIssue : UnityEditor {
      public string plannedFixDate; //Update value in inspector. I have my hands full fixing shit that aint really meant to be broke and don't have the time to implement UI.
      //On Second thought. Add it to the comments here as well incase some one resets the interface
      //ToDo: initialize plannedFixDate with value;
      
      private void Awake() {
         UnityDevTeam.PingUnityDevTeam("Hello?");
      }

      private void Start() {
         UnityDevTeam.PingUnityDevTeam("?"); //Some times a second ping helps
         UnityDevTeam.SendMessage("Help");
      }
      
      /// <summary>
      /// This Class Provides an answer to the Questions:
      /// Is the .blend Importer planned to be fixed? and if so, when?
      /// <summary>
      private string DoQuestion(bool _isOk) {
         string answer = "No";
         If(_isOK) answer = "Yes. Date: " + plannedFixDate;
         return answer;
      }

   }
}

More Context + Bonus irritation and Sarcasm:
Due to the unpredictability of floats, i have opted to create primitive collider reference objects in blender. But i know right? When I ask some one to write down the number 10 and they write down the number 11, I’m just suppose to be happy with that, aren’t I.

Second edit: for missing some using statements;

Old Version for Reference:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Anybody @Unity got any idea as to when we mere mortals will be graced with a fully functional and error free importer for .blend or at least .FBX files.

Heck I don’t mind manually fixing coords and hoping that the recommended settings on export and import will do as advertised, like the next peasant.
But surely Unity has been around long enough that the default fbx export settings will do and the unity importer does the rest…right? No need to worry about scaling or any of that stuff. Being able to have 9 nested layers of objects. Meshes and Objects being named correctly…etc.
My big concern how ever is that the coords in blender and unity don’t align a lot of the time and that a known value with less than 7 figures of precession {-5.0921} is prone to floating point errors in Unity {5.092068}. What is it about the number one that Unity so hates that it would even deny itself the number.

SO. In Summary.

I won’t be responding to anything, other then a clear cut answer from the Unity Team, So do not be concerned if I do not reply to my fellow mortals.
Ultimately, Just hoping for an update, on the future of the Unity Game Engine, as this has been an issue since…
ah heck, you know when.

Context Follows:


*

Attached Image is just one of many, more than I care to count issues, in one single import.
I’ll allow you dear reader to play spot the difference, as i have already waisted countless hours
manually adjusting simple small known numbers arbitrarily changed by who knows what metric
that miss Aligns every random who’s its of what what.

P.S. if any one wants to play more ‘Spot the Difference’
I will gladly upload more examples from the same file.
I do have over 200 hundred of them.

Exactly the reason why making any change NOW would be disastrous to almost everyone who got their workflows all figured out and set up. There have always been oddities converting meshes between 3D Modeling and Game Engines, those issues are neither unique to Unity nor Blender.

Meaning: don’t hold your breath for ANY changes. Instead, learn what others are doing and whether you need to make any changes to the way you design the models in order to avoid these issues - if they are issues (that matter) to begin with.

I suppose Blender and others use double precision values internally. Nothing can technically be done about this when most game engines and GPUs only use floating point values.

These values are accurate enough to not pose any issues barring some fringe things where perhaps two (purposefully not merged) faces do not touch precisely and thus shadows/lights may be leaking. Where such precise accuracy matters, models are built on a grid with snapping.

No proper reply in 5 days.

Well Here is an Update:

I still want a bloody answer though.
Even if I had not had to write a custom importer,
this ain’t on Team Unity. it ain’t. You handle Game Engine stuff.
Not me
Forward in blender should be forward in unity on import.
Even if you do not reply, send an e-mail when you fix it,
so that I don’t loose my shit during Unity version upgrades.

If you would be so kind
Unity Game Engine End User
Bruce J Boyd
aka: Honour Demon.

Edit: Script was Parent at the wrong time. my bad.
Edit2: Grabbing Global Rotation instead. My bad again
Edit3: Found all the errors and mis implementations in my code.
-not supply that though. Their is enough here to get the ball rolling. RUF IT

/// ~Legal Notice:
/// This is the Property of Bruce James Boyd. Written and/generated by Bruce James Boyd.
/// Even if Shared in public, you have no rights to the bits that drove him insane for 2 weeks.
/// Do not copy. "learn understand and write your own code from scratch"
/// Unity Classes and functions and w/e is unity's legal issue. the Structure and my stuff is mine.
/// You are how ever free to use this as a referance to create your own solution.
/// Works in unity 6000.0.28f. No garenties for other versions importers.
/// Proper spelling and/or grammer; not included.
/// ~end of Legal Notice
/// 
/// It took many other classes to be written to get to this result. And guess what, it works.
/// This little that a trained professional would have been able to sort out in a hour or two.
/// 
/// 
/// 
/// 4 weeks of game dev down the drain cause shart aint implemented correctly. Unity and BLender have their own foreward spaces
/// Now if I call unity's transform.forward that is what I will get without bloating my assets with empties.
/// Don't fill yourself with junkfood, eat organic instead.
/// 
/// 
/// 
/// Just in case some one does ever need a hand.
/// Don't mess with the x y and z, just RUF it.
/// Unity: x : R   Blender:    x : -R
/// Unity: y : U   Blender:    y : -F
/// Unity: z : F   Blender:    z : U
/// Logic is RUF so just translate:
/// Unity Vector3 = blender Vector3(-R , U, -F);
/// -or Unity Vector3 = blender Vector3(-Bx , Bz, -By);
/// Don't forget that the natural space for meshes are diffrent, so the Blender RUF is R-FU 
/// -and the same for rotation you have to R-FU:W them. 
/// Don't use euler, you are translating data not human readability.
/// 
/// But for anything else, RUF it. If you aint RUF'ing it, you aint hitting the spot.
/// 
/// FYI: I had to clean up the langauge alot in this...Like a f'ing lot. I even had to remove
/// -the comment that took up alot of screen space around the mesh conversion. Thats how strait foreward it was. 
/// One axial flip + one axial direction flip...
/// WTF man, W T F.
/// One more Notice However: I aint refactory or optimizing this shit, untill i get paid, cause its Editor Based and should never have been my problem.
/// </summary>

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System;
using System.Globalization;

namespace BJB {

    /// <summary>
    /// Band aid Solution. 
    /// Honestly though;
    /// Unless the band aids are a part of a provocative swimware set.
    /// It aint sexy.
    /// Just saying.
    /// Say no to bloat.
    /// </summary>
    public class BJBImportPostprocessor : AssetPostprocessor {
        private string[] content;

        /// <summary>
        /// The Right Timing for Mesh? Not Sure hey
        /// </summary>
        /// <param name="importedObject"></param>
        void OnPostprocessModel(GameObject importedObject) {
            // Check if the asset is a `.blend` file
            if (assetPath.EndsWith(".blend")) {
                Debug.Log($"Processing .blend file: {assetPath}");
                // Apply custom logic to the imported GameObject
                GetDataFromTxt(importedObject);
                FixTransform(importedObject);
                FixMesh(importedObject);
            }
        }

        /// <summary>
        /// Text is easy to manipulate, post export.
        /// </summary>
        /// <param name="importedObject"></param>
        void GetDataFromTxt(GameObject importedObject) {
            //Get String Data From Text
            //ToDo
            string[] txtFilePaths = Directory.GetFiles(Application.dataPath, "*.txt", SearchOption.AllDirectories);
            for (int i = 0; i < txtFilePaths.Length; i++) {
                string txtFileName = Path.GetFileNameWithoutExtension(txtFilePaths[i]);
                if (txtFileName == importedObject.name) {
                    string pulledString = File.ReadAllText(txtFilePaths[i]);
                    content = pulledString.Split("\n");
                    Array.Sort(content);
                }
            }
        }

        /// <summary>
        /// Fix the generated Prefab. Be -RU-F with it
        /// </summary>
        /// <param name="importedObject"></param>
        void FixTransform(GameObject importedObject) {
            //Do Fix and Get; Transforms | Parents
            Transform[] children = importedObject.GetComponentsInChildren<Transform>();
            importedObject.transform.position = Vector3.zero;
            importedObject.transform.rotation = Quaternion.identity;
            importedObject.transform.localScale = Vector3.one;
            Transform[] parents = new Transform[children.Length];
            for (int t = 0; t < children.Length; t++) {
                parents[t] = children[t].parent;
                children[t].parent = null;
            }
            //Data 0: Name, 1: MeshName 2: Global Position 3: Global Rotation 4: Scale 5: Dimentions
            for (int c = 0; c < content.Length; c++) {
                //Debug.Log(children.Length);
                string[] data = content[c].Split('=');
                for (int t = 0; t < children.Length; t++) {
                    if (children[t].name == data[0]) {
                        string[] pos = data[2].Split(",");
                        string[] rot = data[3].Split(",");
                        string[] scale = data[4].Split(",");

                        //Do Position and -R-FU IT
                        float Bx = MathF.Round(float.Parse(CleanString(pos[0]), CultureInfo.InvariantCulture), 5);
                        float By = MathF.Round(float.Parse(CleanString(pos[1]), CultureInfo.InvariantCulture), 5);
                        float Bz = MathF.Round(float.Parse(CleanString(pos[2]), CultureInfo.InvariantCulture), 5);
                        children[t].position = new Vector3(-Bx, Bz, -By);

                        //Do Rotation and be R-FU:W IT
                        Bx = MathF.Round(float.Parse(CleanString(rot[0]), CultureInfo.InvariantCulture));
                        By = MathF.Round(float.Parse(CleanString(rot[1]), CultureInfo.InvariantCulture));
                        Bz = MathF.Round(float.Parse(CleanString(rot[2]), CultureInfo.InvariantCulture));
                        float Bw = MathF.Round(float.Parse(CleanString(rot[3]), CultureInfo.InvariantCulture));
                        children[t].rotation = new Quaternion(Bx, -Bz, By, Bw);

                        //Do Scale and RFU it
                        Bx = MathF.Round(float.Parse(CleanString(scale[0]), CultureInfo.InvariantCulture), 5);
                        By = MathF.Round(float.Parse(CleanString(scale[1]), CultureInfo.InvariantCulture), 5);
                        Bz = MathF.Round(float.Parse(CleanString(scale[2]), CultureInfo.InvariantCulture), 5);
                        children[t].localScale = new Vector3(Bx, Bz, By);//This layout was kept for easy reading for mortals
                        //children[t].localScale = new Vector3(MathF.Round(float.Parse(CleanString(scale[0]), CultureInfo.InvariantCulture), 5),MathF.Round(float.Parse(CleanString(scale[2]), CultureInfo.InvariantCulture), 5),MathF.Round(float.Parse(CleanString(scale[1]), CultureInfo.InvariantCulture), 5));
                        //Could possible make more human readable by moving the math to CleanString as well and returning the float. don't know about float accuracy though.
                    }
                }
            }
            //Nope Parent Here and grab globals
            for (int t = 0; t < children.Length; t++) {
                children[t].SetParent(importedObject.transform, true);
            }
        }

        /// <summary>
        /// Translate the mesh. Be RU-F with it
        /// </summary>
        /// <param name="importedObject"></param>
        void FixMesh(GameObject importedObject) { //ToDo: maybe not, the other cycle is chaotic. We already iterating the data in FixTransform(). Move this in their when U want a break from game development
            // Find and modify all MeshFilter components
            foreach (var meshFilter in importedObject.GetComponentsInChildren<MeshFilter>()) {
                Mesh mesh = meshFilter.sharedMesh;
                for (int c = 0; c < content.Length; c++) {
                    string[] data = content[c].Split('=');
                    if (mesh.name == data[0]) {
                        mesh.name = data[1];
                    }
                }

                if (mesh != null) {
                    //Debug.Log($"Modifying mesh: {mesh.name}");
                    //Gets V-vertices
                    List<Vector3> V = new List<Vector3>();
                    mesh.GetVertices(V);
                    //R-FU it
                    for (int vc = 0; vc < V.Count; vc++) {
                        V[vc] = new Vector3(V[vc].x, V[vc].z, -V[vc].y);
                    }
                    mesh.SetVertices(V);

                    mesh.RecalculateBounds();
                    mesh.RecalculateNormals();
                    mesh.RecalculateTangents();
                }
            }

            //ToDo: To be RUF'ed up later
            /*
            foreach (var skinnedMeshRenderer in importedObject.GetComponentsInChildren<SkinnedMeshRenderer>()) {
                Mesh mesh = skinnedMeshRenderer.sharedMesh;
                if (mesh != null) {
                    Debug.Log($"Modifying skinned mesh: {mesh.name}");
                    // Example: Flip UVs vertically
                    Vector2[] uvs = mesh.uv;
                    for (int i = 0; i < uvs.Length; i++) {
                        uvs[i] = new Vector2(uvs[i].x, 1.0f - uvs[i].y);
                    }
                    mesh.uv = uvs;
                    // Recalculate bounds after modifying UVs
                    mesh.RecalculateBounds();
                }
            }
            */
        }

        //Clean it
        private string CleanString(string _in) {        
            _in = _in.TrimEnd('\n');
            _in = _in.TrimEnd('0');
            if (_in.EndsWith('.'))
                _in = _in.Substring(0, _in.Length - 1);
            //Debug.Log(_in);
            return _in;
        }
    }
}
//Yes, comment in the third person. You never know when you will change class or level up.
#endif

Dude, it’s Christmas time. Everyone is likely on leave at the moment.

If you have a reproducible bug, make a bug report.

Hey,

Apologies for the delay; we’ve just been catching up with everything after the winter break.

I’m a part of the engineering group that works with Asset Importers, and I really would echo what spiney199 adds above, please do file a bug if you have discovered an issue. It’s generally the fastest way for issues to get directly to our dev team, and will give us access to some files to dig-in.

That being said; as CodeSmile points out, most game engines are float based so it wouldn’t be surprising if there are some small discrepancies between Blender & Imported Unity data as it makes its way through the system. If we can get the files via a bug-report we can look into it and confirm.