0
$\begingroup$

In my OBJ file (exported with Blender), I noticed that there are many digits:

o MyObject
v 0.900000 10.750000 -0.750000
v 0.900000 9.250000 -0.750000
v 0.750000 10.750000 0.900000
v 0.750000 9.250000 0.900000
...

Is there any ways to reduce the exported file size by removing those extra 0?

Example:

o MyObject
v .9 10.75 -.75
v .9 9.25 -.75
v .75 10.75 0.9
v .75 9.25 0.9
...

And if not, is there any add-on, open source software or online tool that allows you to simplify OBJ files like this?

$\endgroup$
2
  • $\begingroup$ Thanks for the information. Yes, an OBJ file can be manually minified like this and still by readable, I tried and it works. $\endgroup$
    – BarryCap
    Jun 21 at 16:11
  • $\begingroup$ oh, good. Without knowing you were here, I reposted my comment as an answer. $\endgroup$
    – TheLabCat
    Jun 21 at 16:14
1
$\begingroup$

Blender does not have such tools, except for the inbuilt python interpreter, which definitely has the necessary programming power to do this. However, an external python interpreter can also do it. This is not really about Blender, since most OBJ files I’ve seen also have these extra decimal places. I’m not sure if removing them would leave the file still readable. It might, though, and if you’re really desperate I could try to point you in the right direction in terms of code.

Edit: Run this code in any python interpreter, with the two variables FILE_IN and FILE_OUT configured appropriately. If you are using the blender python interpreter, I recommend placing this in blender’s text editor first, then clicking the little run button in the header.

#OBJ zero stripper v1.0

“””
This version of the script is blender compatible:
While it does not use or rely on any Blender API features,
it can be run inside the Blender interpreter without a hitch.

Configure the absolute variables, respectively FILE_IN and FILE_OUT,
appropriately before running.
"""

#File input and output variables
FILE_IN="C:\\Users\\BarryCap\\3D Objects\\untitled.obj"
FILE_OUT="C:\\Users\\BarryCap\\3D Objects\\untitled_zerostripped.obj"

#Open and read the file.
f=open(FILE_IN)
lines=f.read().splitlines()
f.close()

lines_new=[] #The new file's lines

for l in lines: #For every line from the file...

    nl="" #The new file line

    for item in l.split(" "): #For every space-separated item in the line...

        try: #Attempt converting the item to a float
            item=float(item)

            #Convert the number back to a string, processing the extra zeros out of it based on its numeric value
            if item < 0: #If the item is negative, process the minus sign
                item="-"+str(abs(item)).strip("0")
            elif item == 0: #If the item is zero, avoid the unneeded decimal point
                item="0"
            elif item>0: #If the item is greater than zero, simply strip off the zeros.
                item=str(item).strip("0")

        except ValueError: #If conversion to a float raises a ValueError, do not preprocess the item
            pass
            
        nl+=item+" " #Add the item to the new file line with a space (leaves one at the end)

    lines_new.append(nl) #...and add the finished line to the new file lines
    
f=open(FILE_OUT, "w") #Open the new file in write/create mode

#For each new file line...
for nl in lines_new:

    #...strip off the trailing space from earlier (the if statement is in case the line is empty)
    if nl[-1]==" ":
        nl=nl[:-1]
    f.write(nl+"\n") #...and write the line to the file.

f.close() #Close the file (saves automatically).

#S.D.G.
$\endgroup$
15
  • $\begingroup$ Yes, it would be great if you could do that! I merely don't know anything about Python, though. $\endgroup$
    – BarryCap
    Jun 21 at 16:20
  • $\begingroup$ @BarryCap Working… $\endgroup$
    – TheLabCat
    Jun 21 at 16:30
  • $\begingroup$ @BarryCap done! 😊 $\endgroup$
    – TheLabCat
    Jun 21 at 17:39
  • $\begingroup$ Thanks! I'll try that. $\endgroup$
    – BarryCap
    Jun 21 at 19:21
  • $\begingroup$ Where can I use this code? Like I said before, I don't know much of Python and it's implementation in Blender. Can you please be more specific on how to use this code? $\endgroup$
    – BarryCap
    Jun 21 at 20:31
4
$\begingroup$

Edit the exporter.

Will run thru how to edit changes into addon to do this, .. although for the most part do not recommend making edits to addons....

The addon used to export blend scene to obj is available in the addons folder and can be edited. Make a backup copy to revert... or an addon copy

In version (3.8.0) of the obj exporter that ships with blender, circa line 453 in /addons/io_scene_obj/export_obj.py

        # Vert
        for v in me_verts:
            fw('v %.6f %.6f %.6f\n' % v.co[:])

is where the vertex coordinates are written to file. The %.6f is formatting the float to be written with 6 decimal places.

For example can limit to 4 decimal places with:

        # Vert
        for v in me_verts:
            fw('v %.4f %.4f %.4f\n' % v.co[:])

Please note, this is simply explaining where and why the exporter is writing a consistent n decimal places. Reducing the number will reduce the accuracy for numbers with significant digits outside reduced range

See suggestions given in this stackoverflow post https://stackoverflow.com/questions/41275396/limiting-floats-to-reduce-data-size

Using :n or :g formatting to remove 'insignificant trailing zeros' with:

        # Vert
        for v in me_verts:
            fw('v %g %g %g\n' % v.co[:])

Before:

o Cube
v 1.000000 1.550000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
...

After:

o Cube
v 1 1.55 -1
v 1 -1 -1
v 1 1 1
...

or a combination of two answers,

import re

def fmt(s):
    def repl(matchobj):
         return ''.join(i for i in matchobj.groups() if i)
    return re.sub(
            r"(-?)(?:\b0+(\.\d)(\d*)(?<!-0\.0)(?<!0\.0)\b|\b([1-9]\d*)\.0+\b)|-?(0)+\.0\b", 
            repl , 
            s)



fw(fmt("v %g %g %g" % (1.000000 , 0.550000, -1.000000)))

#v 1 .55 -1    

Similar could also be used to simply read and rewrite the obj file

Instead would look at uitilizing using a tool like sed which can be programmed to look for and replace patterns. If you are familiar with the vi editor, will be familiar with sed commands. This I feel is somewhat outside the scope of BSE.

https://stackoverflow.com/questions/6916695/sed-for-removing-trailing-zeroes-regex-nongreedy

$\endgroup$
7
  • $\begingroup$ Setting it to %.4f Wood strip off sixth Place decimal places if the numbers were there. The idea is to get rid of extra zeros completely, not reduce their number and strip extra data if it is present. $\endgroup$
    – TheLabCat
    Jun 21 at 17:43
  • 1
    $\begingroup$ Editing default decimal number is working, but what I want is to reduce without loss. For example, if %.1f is set, 0.750000 will be written as 0.8, and what I want is .75. But thanks for your help! $\endgroup$
    – BarryCap
    Jun 21 at 17:43
  • 1
    $\begingroup$ Was just an example, see the edit @ZargulTheWizard $\endgroup$
    – p2or
    Jun 21 at 18:26
  • 2
    $\begingroup$ @p2or Cheers for the edit!. $\endgroup$
    – batFINGER
    Jun 21 at 18:29
  • 1
    $\begingroup$ Thank you for editing your answer! I tried editing the export_obj.py file and it's working! $\endgroup$
    – BarryCap
    Jun 21 at 19:56
1
$\begingroup$

There may be an easier way to do it but I found plugging into the file stream would be a good idea. There are actually 2 files created during the export, a .obj and a .mtl.

You need to open in a text editor the file called export_obj.py located in your blender installation folder/2.**/scripts/addons/io_scene_obj.

Then copy and paste the following lines in two locations :

with open(filepath, "w", encoding="utf8", newline="\n") as file:
        def ensure_no_leading_or_trailing_zero(input):
            if input.startswith(("v", "vt", "vn", "Ns", "Ka", "Kd", "Ks", "Ke", "Ni", "d")):
                if input.endswith("\n"):
                    input = input[:-1] # Strip the EOL character
                words = input.split(' ') # Splits the different words
                input = ""
                for i, word in enumerate(words):
                    if i > 0:  # Add space between each "word"
                        input += ' '
                    word = word.rstrip('0').rstrip('.') # Remove trailing zeroes
                    if word.startswith("0."): # Remove leading zeroes
                        word = word[1:]
                    if word.startswith("-0."): # Remove leading zeroes
                        word = "-" + word[2:]
                    input += word
                input += "\n"
            file.write(input)

        fw = ensure_no_leading_or_trailing_zero

First location, around the line 50. Replace the line that starts with with open(... and also the line fw = f.write.

Second location, around line 3000, do the same thing.

It should look like this :

enter image description here

And this :

enter image description here

Remember, in python, the indentation is very important. You can create an indentation if need be with 4 spaces.

Once the text file is edited, save it and close it. You then need to launch blender again for the new exporter settings to load.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.