GithubHelp home page GithubHelp logo

pywavefront / pywavefront Goto Github PK

View Code? Open in Web Editor NEW
303.0 14.0 80.0 3.66 MB

Python library for importing Wavefront .obj files

License: BSD 3-Clause "New" or "Revised" License

Python 100.00%
python wavefront pyglet python3 wavefront-obj 3d loader opengl-library

pywavefront's Introduction

pypi CircleCI

preview

PyWavefront

PyWavefront reads Wavefront 3D object files (something.obj, something.obj.gz and something.mtl) and generates interleaved vertex data for each material ready for rendering.

  • Python 3.4+ is supported in 1.x versions
  • Python 2.7 is supported in 0.x versions

A simple (optional) visualization module is also provided for rendering the object(s). The interleaved data can also be used by more modern renderers thought VBOs or VAOs.

Currently the most commonly used features in the specification has been implemented:

  • Positions
  • Texture Coordinates
  • Normals
  • Vertex Color
  • Material parsing
  • Texture and texture parameters

We currently don't support parameter space vertices, line elements or smoothing groups. Create an issue or pull request on github if needed features are missing.

The package is on pypi or can be cloned on github.

pip install pywavefront

Also check out the roadmap for future plans.

Usage

Basic example loading an obj file:

import pywavefront
scene = pywavefront.Wavefront('something.obj')

A more complex example

  • strict (Default: False) will raise an exception if unsupported features are found in the obj or mtl file
  • encoding (Default: utf-8) of the obj and mtl file(s)
  • create_materials (Default: False) will create materials if mtl file is missing or obj file references non-existing materials
  • collect_faces (Default: False) will collect triangle face data for every mesh. In case faces with more than three vertices are specified they will be triangulated. See the documentation of ObjParser#consume_faces() in obj.py.
  • parse (Default: True) decides if parsing should start immediately.
  • cache (Default: False) writes the parsed geometry to a binary file for faster loading in the future
import pywavefront
scene = pywavefront.Wavefront(
    'something.obj',
    strict=True,
    encoding="iso-8859-1",
    parse=False,
)
scene.parse()  # Explicit call to parse() needed when parse=False

# Iterate vertex data collected in each material
for name, material in scene.materials.items():
    # Contains the vertex format (string) such as "T2F_N3F_V3F"
    # T2F, C3F, N3F and V3F may appear in this string
    material.vertex_format
    # Contains the vertex list of floats in the format described above
    material.vertices
    # Material properties
    material.diffuse
    material.ambient
    material.texture
    # ..

Binary Cache

When cache=True the interleaved vertex data is written as floats to a .bin file after the file is loaded. A json file is also generated describing the contents of the binary file. The binary file will be loaded the next time we attempt to load the obj file reducing the loading time significantly.

Tests have shown loading time reduction by 10 to 100 times depending on the size and structure of the original obj file.

Loading myfile.obj will generate the following files in the same directory.

myfile.obj.bin
myfile.obj.json

Json file example:

{
  "created_at": "2018-07-16T14:28:43.451336",
  "version": "0.1",
  "materials": [
    "lost_empire.mtl"
  ],
  "vertex_buffers": [
    {
      "material": "Stone",
      "vertex_format": "T2F_N3F_V3F",
      "byte_offset": 0,
      "byte_length": 5637888
    },
    {
      "material": "Grass",
      "vertex_format": "T2F_N3F_V3F",
      "byte_offset": 5637888,
      "byte_length": 6494208
    }
  ]
}

These files will not be recreated until you delete them. The bin file is also compressed with gzip to greatly reduce size.

Visualization

Pyglet is required to use the visualization module.

pip install pyglet

Example:

import pywavefront
from pywavefront import visualization

[create a window and set up your OpenGl context]
obj = pywavefront.Wavefront('something.obj')

[inside your drawing loop]
visualization.draw(obj)

Logging

The default log level is ERROR. This is configurable including overriding the formatter.

import logging
import pywavefront

pywavefront.configure_logging(
    logging.DEBUG,
    formatter=logging.Formatter('%(name)s-%(levelname)s: %(message)s')
)

Examples

The examples directory contains some basic examples using the visualization module and further instructions on how to run them.

Generating a Wavefront file with Blender

The following presumes you are using Blender to generate your mesh:

  • Using Blender, create a mesh with a UV-mapped texture. The UV-mapping is important! If it is working properly, you will see the texture applied within Blender's 3d view.
  • Export the mesh from Blender using the Wavefront format, including normals.
  • Reference your *.obj file as in the pywavefront example above.

Tests

All tests can be found in the tests directory. To run the tests:

# Install pywavefront in develop mode
python setup.py develop

# Install required packages for running tests
pip install -r test-requirements.txt

# Run all tests
pytest

# Optionally specific tests modules can be runned separately
pytest tests/test_parser.py

Community

PyWavefront Discord server : https://discord.gg/h3Rh4QN

Owners & Maintainers

Contributors

In alphabetical order:

Project History

PyWavefront was originally started by @greenmoss (Kurt Yoder) in 2013. He was the sole maintainer of the project until February 2019 when the PyWavefront Maintainers organization was created adding @einarf (Einar Forselv) as an additional owner and maintainer of the project.

License

PyWavefront is BSD-licensed

pywavefront's People

Contributors

comfreek avatar dancergraham avatar dav92lee avatar einarf avatar greenmoss avatar jerekshoe avatar karrson-archive avatar liam-deacon avatar marxlp avatar mikhail57 avatar mlamarre avatar ogimenez-smtc avatar patrikhuber avatar sergioragostinho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pywavefront's Issues

Attribute Error

AttributeError: 'ObjParser' object has no attribute 'parse_g

Consider updating visualization

Consider updating the visualization code to something more modern. Pyglet is pretty much locked to OpenGL 2.1 released in 2006. Today OpenGL 4.6 is the stable version. I would suggest using OpenGL 3.3 so we an at least visualize all different vertex formats. Most hardware today support his; even 5 year old onboard Intels.

I would suggest using ModernGL (https://github.com/cprogrammer1994/ModernGL) with PyQt5 as this also will align closer to users of this library (mainly coming from the Scientific Computing community).

PyWavefront are missing basic tags/topics on github

PyWavefront don't have any tags/topics set here on github. It can make a difference when people seach up projects. They can be added by clicking the "Manage Topics" right under project description.

Some suggestions: python, python2, python3, wavefront, wavefront-obj, 3D, loader, opengl-library

(Sorry for the nagging!)

python 3

any chance for p3 compatibility?

Cannot install with pip install

Using pip install pywavefront I get the following:

Could not find a version that satisfies the requirement pywavefront (from versions: )
No matching distribution found for pywavefront

error when runing pyglet_demo2.py

I can run ./example/pyglet_demo.py successfully.But when run ./example/pyglet_demo2.py, there is an error in line 15: "meshes = Wavefront('earth.obj')".

Full information:

Traceback (most recent call last):
  File "pyglet_demo2.py", line 15, in <module>
    meshes = Wavefront('earth.obj')
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/__init__.py", line 53, in __init__
    ObjParser(self, self.file_name)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/__init__.py", line 75, in __init__
    self.read_file(file_name)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/parser.py", line 44, in read_file
    self.parse(line, dir=os.path.dirname(file_name))
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/parser.py", line 67, in parse
    parse_function(args)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/__init__.py", line 89, in parse_mtllib
    materials = material.MaterialParser(mtllib).materials
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/material.py", line 118, in __init__
    self.read_file(file_path)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/parser.py", line 44, in read_file
    self.parse(line, dir=os.path.dirname(file_name))
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/parser.py", line 67, in parse
    parse_function(args)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/material.py", line 147, in parse_map_Kd
    self.this_material.set_texture(Kd)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/material.py", line 84, in set_texture
    self.texture = texture.Texture(path)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pywavefront/texture.py", line 41, in __init__
    self.image = pyglet.image.load(self.image_name).texture
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pyglet/image/__init__.py", line 388, in <lambda>
    texture = property(lambda self: self.get_texture(),
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pyglet/image/__init__.py", line 818, in get_texture
    force_rectangle)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pyglet/image/__init__.py", line 803, in create_texture
    rectangle, force_rectangle)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pyglet/image/__init__.py", line 1514, in create
    blank)
  File "/home/dxs/anaconda2/envs/dxs_anaconda_env/lib/python2.7/site-packages/pyglet/gl/lib.py", line 104, in errcheck
    raise GLException(msg)
pyglet.gl.lib.GLException: invalid value

Thank you very much!

Parser doesn't find the texture

I have downloaded pyglet_demo.py and its ressources terran.png, uv_sphere.mtl and uv_sphere.obj.

I use Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)] on win32 with the latest version of your lib 0.1.2.

When I run the demo, it prints a long stacktrace, but essential message is:

  File "C:\Python27\lib\site-packages\pyglet\resource.py", line 414, in file
    raise ResourceNotFoundException(name)
pyglet.resource.ResourceNotFoundException: Resource "/terran.png" was not found on the path.  Ensure that the filename has the correct captialisation.

I reviewed your parser.py at line 60:

        for arg in args:
            if dir and 'mtllib' in line or 'map_Kd' in line:
                args[i] = dir + '/' + arg.decode("utf-8")
            else:
                args[i] = arg.decode("utf-8")
            i += 1

After I added round brackets around the both in line checks, the code worked.

if dir and ('mtllib' in line or 'map_Kd' in line):

Does this fit your test cases?

Examples broken in python 2

Running pyglet_demo.py or pyglet_demo2.py in python 2 triggers TypeError related to unbound methods. I guess this is related to the separation of the visualization and the fact that python 3 don't have unbound functions. Not a big problem for me personally. I stumbled over it when testing py2 compatibility since this package doesn't really state anywhere what is supported.

$ python pyglet_demo.py
Traceback (most recent call last):
  File "pyglet_demo.py", line 14, in <module>
    meshes = pywavefront.Wavefront('uv_sphere.obj')
  File "../pywavefront/__init__.py", line 51, in __init__
    ObjParser(self, self.file_name)
  File "../pywavefront/__init__.py", line 72, in __init__
    self.read_file(file_name)
  File "../pywavefront/parser.py", line 46, in read_file
    self.parse(line, dir=os.path.dirname(file_name))
  File "../pywavefront/parser.py", line 75, in parse
    parse_function(args)
  File "../pywavefront/__init__.py", line 86, in parse_mtllib
    materials = material.MaterialParser(mtllib).materials
  File "../pywavefront/material.py", line 102, in __init__
    self.read_file(file_path)
  File "../pywavefront/parser.py", line 46, in read_file
    self.parse(line, dir=os.path.dirname(file_name))
  File "../pywavefront/parser.py", line 75, in parse
    parse_function(args)
  File "../pywavefront/material.py", line 131, in parse_map_Kd
    self.this_material.set_texture(Kd)
  File "../pywavefront/material.py", line 82, in set_texture
    self.texture = texture.Texture(path)
TypeError: unbound method init() must be called with _Texture instance as first argument (got str instance instead)

PyWavefront 0.4.0 was only built for Python 2

The last release was only built for python 2 probably because it was created in a python 2 environment. It looks like you have to use the --universal flag (python setup.py bdist_wheel --universal) to create a py2 and py3 whl file.
https://wheel.readthedocs.io/en/stable/#defining-the-python-version

I don't think you need to release a new version since pypi do support uploading several distribution files for the same version. Worst case bump to 4.1.

I didn't really think about this because most projects for work and hobby have been python 3 only for the last couple of years, so setuptools built py3 only pacakges with bdist_wheel in python3 environment.

Support reading .gz files

A lot of obj files are often gzipped by default obviously because of the nature of the format and the 4:1 or higher compression rate with larger files. It would be fairly trivial to support this considering python 2 and 3 has pretty extensive support for reading and writing gzip files.

Configurable logging

I'm reading a lot of huge files causing logs or the terminal to be cluttered with a lot of useless messages. We should make a global logger for this package pywavefront that can easily be configured at info, warning and error level.

This should not be a difficult task to complete.

Wavefront class as entrypoint. Alternatives?

Some thoughts on this. I don't know much about the history of the library, so I might be off here. I suspect the decision to use Wavefront() as the entrypoint was to make to VERY simple to use, something that I definitely support.

The way the Wavefront class is promoted as the entrypoint right now makes it a bit awkward to extend the parsers. The class is the result object and the entrypoint at the same time. Right now we really only have one good way to use a custom parser.

Wavefront.parser_cls = MyCustomParser
result = Wavefront(...)

Also, if my custom parser have additional parameters, the Wavefront constructor will need to forward that my class. We can solve that using **kwargs, but it makes things a bit awkward.

Another weird way people could avoid Wavefront object, people can be creative doing this:

result = Wavefront(parse=False)
parser = ObjParser(result, "my.obj", ...)

.. but that will also create an internal parser in Wavefront, so you would have to extend the class to avoid that.

I personally think it would be cleaner if the parser was instantiated directly creating its own "result" object returned in parse().

parser = ObjParser("my.obj", ...)
result = parser.parse()
# And/or the result is available as an attribute
parser.result

Still I think preserving backwards compatibility is important here, so we should support both. We can create a base class ParserResult only containing parse result attributes. Wavefront can extend this class adding the methods it has now.

class ParserResult(object):
    def __init___(self):
        self.file_name = file_name
        self.mtllibs = []
        self.materials = {}
        self.meshes = {}        # Name mapping
        self.mesh_list = []     # Also includes anonymous meshes

class Wavefront(ParserResult):
    """Identical to the old class except we inherit attributes"""
    def __init__(self, file_name, strict=False, ..., *kwargs):
        ... etc ...

Parsers will then have an optional attribute for the Wavefront/ParserResult. If not supplied it will create its own ParseResult instance and return it in parse. In addition the parser class is configurable as a class variable.

class Parser(object):
    """The base parser"""
    result_cls = ParserResult

    def __init__(self, result_instance=None):
        self.result = result_instance or result_cls()

    def parse(self):
        ...
        return self.result

This way we can support Wavefront passing in itself and instantiation of parsers directly. We should still promote the Wavefront() approach as before, but combine this change with covering the more advanced uses of the library with sphinx docs #66

Installation needs an update

When I run pip install PyWavefront I got the following message:

Collecting PyWavefront
  Downloading PyWavefront-0.1.2.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "c:\users\kai\appdata\local\temp\pip-build-l2skpl\PyWavefront\setup.py", line 12, in <module>
        long_description=open('README.md').read(),
    IOError: [Errno 2] No such file or directory: 'README.md'

To workaround it, I replaced the long description with an empty string.

ValueError: invalid literal for int() with base 10: ''

I am trying to open this obj file
https://sketchfab.com/3d-models/hoa-hakananaia-752e69d34933438d8230ac829d22300e

Getting this error:

Traceback (most recent call last):
    scene = pywavefront.Wavefront('/Users/sixer/Downloads/hoa-hakananaia/source/2738963_2014916101619/mesh/sculpt.obj')
  File "/usr/local/lib/python3.7/site-packages/pywavefront/wavefront.py", line 78, in __init__
    cache=cache)
  File "/usr/local/lib/python3.7/site-packages/pywavefront/obj.py", line 81, in __init__
    self.parse()
  File "/usr/local/lib/python3.7/site-packages/pywavefront/obj.py", line 91, in parse
    super(ObjParser, self).parse()
  File "/usr/local/lib/python3.7/site-packages/pywavefront/parser.py", line 136, in parse
    self.dispatcher.get(self.values[0], self.parse_fallback)()
  File "/usr/local/lib/python3.7/site-packages/pywavefront/obj.py", line 273, in parse_f
    self.material.vertices += list(consumed_vertices)
  File "/usr/local/lib/python3.7/site-packages/pywavefront/obj.py", line 381, in consume_faces
    t_index = (int(parts[1]) - 1) if has_vt else None
ValueError: invalid literal for int() with base 10: ''

Pyglet dependency should be optional/extra

As you state in the readme.md

This python module allows you to read Wavefront 3D object files (something.obj and something.mtl) and use them as Python objects. Currently Pyglet is required to render and display these objects.

Objective: create python objects with obj file data. pyglet is totally optional and your package should reflect this.

https://github.com/greenmoss/PyWavefront/blob/4e47c1561b0d0bc3089c695ac151513f58eebe4d/pywavefront/__init__.py#L35
Importing pyglet at this level makes it required. It should only be imported when actually needed.

Texture

Hi, using

import pywavefront
from pywavefront import visualization

obj = pywavefront.Wavefront('me.obj')
visualization.draw(obj)

I get AttributeError: 'ImageData' object has no attribute 'texture'.

What am I doing wrong?

README needs updating

I good README file is probably the most important thing for the project.

What I think needs to be improved:

  • Link to pypi package
  • State what python versions are supported (2 and 3)
  • Better description about the purpose of this package and its capabilities
  • Install should be early in readme
  • Basic example should include some more info (optional init parameters etc)
  • Visualization example is no longer valid
  • Example section needs updating
  • How can the user access the interleaved vertex data for other uses?

How to access faces?

Hello,
How can I access objects' faces?

When I open the file using
object = pywavefront.Wavefront("object.obj", create_materials = True, collect_faces=True)

I can access the vertices simply by using object.vertices, but when it comes to the faces it is under either 2 folders, meshes or mesh_list, but the folders 0 and None are not accessible:
image

Thank you

binary file cache of parsed scene

Loading large scenes can be very time consuming when they are 50-300MB or even higher. It could be practical supporting dumping the raw parsed result into a .bin file as an optional feature. This would just be serializing the interleaved vertices arrays into a file in binary format with some simple structure.

Parsing the rungholt scene (http://casual-effects.com/data/index.html), often used as a benchmark scene takes about a minute. That's actually not bad for a python parser, but we can do better.

Triangles: 6.7M
Vertices: 12.3M

import .obj without material file

Hi,

I am trying to run a simple example looking like this:

import pywavefront
mesh = pywavefront.Wavefront('path_to_obj/test.obj')

Running this I get the following error that I'm not able to solve:

File "/Library/Python/2.7/site-packages/pywavefront/init.py", line 53, in init
ObjParser(self, self.file_name)
File "/Library/Python/2.7/site-packages/pywavefront/init.py", line 75, in init
self.read_file(file_name)
File "/Library/Python/2.7/site-packages/pywavefront/parser.py", line 44, in read_file
self.parse(line, dir=os.path.dirname(file_name))
File "/Library/Python/2.7/site-packages/pywavefront/parser.py", line 67, in parse
parse_function(args)
File "/Library/Python/2.7/site-packages/pywavefront/init.py", line 120, in parse_f
self.material = material.Material()
TypeError: init() takes exactly 2 arguments (1 given)

Is there a way to load .obj files without a material file?

`strict` should probably be an instance attribute instead of class attribute

strict is currently a class attribute. Changing it will affect the behavior or all parsers.
I suggest making strict an optional parameter to __init__ that defaults to False.

class ObjParser(parser.Parser):
    def __init__(self, wavefront, file_name, strict=False):
        super(ObjParser, self).__init__(file_name, strict=strict)

class Parser(object):
    def __init__(self, file_name, strict=False):
        self.strict = strict

This way the user can be more confident as the value is configured per parser instance.

Personally I will need to have many parser instances in memory at the same time, so this is a valid concern for me. Will this affect anything I don't know about?

Ability to access faces

Is there a function to access faces as loaded from the OBJ file? I could not find any such function in the repo source code.

My use case is the following:

  1. Load a Wavefront OBJ file in V3F format.
  2. Colorize each vertex
  3. Export the list of colorized vertices + faces into an OFF file.

For step 3 I need to export the faces as well.

My OBJ file looks as follows:

g points
v 0 0 0
v 0.000721959 -0.0090243 -0.0139929
v -0.000192831 0.0179897 -0.00965148
v 0.00312371 -0.0223508 -0.0105182
...
g surface
f 512 436 474
f 512 418 436
f 12496 12490 12500
...

Resource files not found on the path

When I try to run the pyglet_demo I get the following error:

pyglet.resource.ResourceNotFoundException: Resource "/terran.png" was not found on the path.  Ensure that the filename has the correct captialisation.

I have tried re-exporting the model from blender using relative, absolute and auto path options but it still fails to find the textures. If I completely remove the texture linkage from the model then the demo runs as expected but without the texture.

I should also probably mention that I am using linux (xubuntu 16.04)

server

How can i run it on server without screen?

Pyglet examples fail in Python 3.7.0

I've got a copy of the example directory and am trying to run the example scripts there.

The Pyglet demos work fine if I run them in Python 2, like so:

$ python --version
Python 2.7.15
$ virtualenv env2
[...]
$ . env2/bin/activate
$ pip install pyglet PyWavefront
[...]
$ python pyglet_demo.py

But in Python 3, I get the following exception and stack trace:

$ python --version
Python 3.7.0
$ virtualenv env3
[...]
$ . env3/bin/activate
$ pip install pyglet PyWavefront
[...]
$ python pyglet_demo.py
Traceback (most recent call last):
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/obj.py", line 379, in consume_faces
    self.next_line()
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/parser.py", line 106, in next_line
    self.line = next(self.lines)  # Will raise StopIteration when there are no more lines
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "pyglet_demo.py", line 15, in <module>
    meshes = pywavefront.Wavefront('uv_sphere.obj')
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/wavefront.py", line 67, in __init__
    cache=cache)
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/obj.py", line 80, in __init__
    self.parse()
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/obj.py", line 90, in parse
    super(ObjParser, self).parse()
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/parser.py", line 136, in parse
    self.dispatcher.get(self.values[0], self.parse_fallback)()
  File "/Users/shane/Projects/pyglet/env3/lib/python3.7/site-packages/pywavefront/obj.py", line 252, in parse_f
    self.material.vertices += list(self.consume_faces())
RuntimeError: generator raised StopIteration

This may be something new to Python 3.7.0, but I'm not sure what might have changed to break this. :-/

Adding support to meshes without object specification and per vertex color

I'm dealing with a couple of obj file which are not being being properly parsed by PyWaveFront.

The traits are:

  • vertex information is provided without providing an object name per the o keyword, i.e. it's a single nameless object.
  • they have per vertex color (see last two sentences of the "spec" entry).

I'm gonna extend the library to support these for my use case. Should I submit them here as well? I believe they're both still within the specification.

Radically changing internal data structures

Currently it's cumbersome to navigate the parse result. I think some radical changes are needed. There have been a few issues related to this already.

  • Always collect face list
  • Support both quads and triangles
  • Don't create the interleaved vertex list during parsing. This can be obtained through a generator function after. Baking an entire interleaved vertex list also wastes a lot of memory.
  • Binary cache should store vertex list and index list instead. Right now we repeat a lot of data causing large scene geometry to blow up. I have a cached mesh file around 720MB.
  • Store more info in mesh instances so it's possible to obtain geomery for a mesh even if it uses multiple materials. This way users can chose to navigate the scene through materials or meshes.

A version bump to 2.0 probably needed for this kind of change. Proper docs should be written with different use cases. All this would make the library much more suitable for data science as well and not only aimed to render a scene.

Pyglet Batch/Sprite Support

Does PyWaveFront generated meshes compatible with piglet batches or sprites? If not, will it be added as a feature in future?

vertex coloring

I have object files that don't support per vertex coloring.Also I have .mtl files.Is it possible to get per vertex colors

Basic Sphinx documentation

It would be nice to have basic sphinx documentation. Should be simple enough with autodoc + adding a simple guide of some sort. It can really help to bring more people to the project.

It's also quick to set up auto build on commits to for example readthedocs.

configurable parser encoding

Python3's open method opens the file using the systems encoding by default unless otherwise is specified.

In text mode, if encoding is not specified the encoding used is platform dependent: locale.getpreferredencoding(False) is called to get the current locale encoding.

In python2's open seems to always use byte str with US-ASCII encoding. I've bumped into quite a few obj files containing characters outside the python 2 str range.

It might be a good idea to make this a bit more deterministic by passing in utf-8 as the default encoding in the constructor and use codecs.open to read the files. This is slightly slower compared to reading byte strings, but will ensure the parser works in the vast majority of the cases. People who want to optimize can pass in 8 bit encodings if needed.

How to change the code for 3 faced objects

I am a newbie in this field, one of my project involves face objects having only 3 faces. But I could see that all your example objects has 4 faces and this code works super fine only for tose examples. When io try the same for my obj having only 3 faces the output is not proper.

your obj has 4 faces ex:
f 2032/8314/8034 6001/2053/2053 8020/2057/2057 6034/8315/8033
f 2033/8318/8036 6033/8319/8035 6135/8320/7940 6032/8321/8037

My obj has 3 faces ex:
f 4606/4606/4606 9943/9943/9943 9944/9944/9944
f 9944/9944/9944 4603/4603/4603 4606/4606/4606

screenshot

Please help me chnaging the code for my obj file.

Thank you.

Installation failed

Hi !
I don't if it's the right place, to talk about this, sorry if i do wring.

I tried to installed PyWavefront on my computer (windows 10, with anaconda)
I tried both "pip install PyWavefront" and "python setup.py install"

each time I have the error :

Traceback (most recent call last):
File "setup.py", line 12, in
long_description=open('README.md').read(),
File "C:\ProgramData\Anaconda3\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 1741: character maps to

So it seems like there is a wierd character in README.md
As a workaround, i deleted the ~15 lasts lignes of the README, and the installation worked, but maybe you want to fix this

uv texture map

I am interested in creating uv texture map from .jpg and uv coords.
Is it possible with PyWavefront?
Thanks in advance

Can't load a cube.

Hello,

I'm using PyWavefront 0.4.1 with Python 3.7.0 on Arch Linux.

I've tried loading a cube.obj downloaded at http://people.sc.fsu.edu/~jburkardt/data/obj/cube.obj but I get the following error message:

Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/pywavefront/obj.py", line 379, in consume_faces
    self.next_line()
  File "/usr/lib/python3.7/site-packages/pywavefront/parser.py", line 106, in next_line
    self.line = next(self.lines)  # Will raise StopIteration when there are no more lines
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "tool2.py", line 71, in <module>
    App()
  File "tool2.py", line 28, in __init__
    obj = pywavefront.Wavefront('cube.obj')
  File "/usr/lib/python3.7/site-packages/pywavefront/wavefront.py", line 67, in __init__
    cache=cache)
  File "/usr/lib/python3.7/site-packages/pywavefront/obj.py", line 80, in __init__
    self.parse()
  File "/usr/lib/python3.7/site-packages/pywavefront/obj.py", line 90, in parse
    super(ObjParser, self).parse()
  File "/usr/lib/python3.7/site-packages/pywavefront/parser.py", line 136, in parse
    self.dispatcher.get(self.values[0], self.parse_fallback)()
  File "/usr/lib/python3.7/site-packages/pywavefront/obj.py", line 252, in parse_f
    self.material.vertices += list(self.consume_faces())
RuntimeError: generator raised StopIteration

Exception raised when texture coordinates but no normals found

I have an obj file that contains texture coordinates but no normals, which raises an exception when calling pywavefront.Wavefront(mesh_path). I checked in the code and this is done because this situation might lead to a black screen when using a lighting model, which I agree is irritating to the user, because it seems that the mesh couldn't be loaded even though it is actually there.

While this all makes sense, I would suggest to only emit a warning in this case and not raise an exception. In my opinion, it is possible that the user does not want to use a lighting model, so in fact does not need normals, but treats the content of the texture directly as the color attribute. This is in fact what I am trying to do. Irrespective of whether this is good practice or not, I think that it would be preferable let the user decide if having no normals is a problem or not. Also, technically the wavefront format does allow that situation (according to wikipedia).

INFO: Repository has moved

The PyWavefront repository has moved from greenmoss/PyWavefront to pywavefront/PyWavefront. The new pywavefront organization makes it easier to manage owners and maintainters to ensure the project keeps on living and improving. A big thank you to @greenmoss who has managed the old repository for many years.

As a replacement for Slack I have created a Discord server: https://discord.gg/nMNjbn

Work on 2.x will start slowly. The plan is to revamp the project structure and making the parse result a lot more flexible supporting triangles and quads + other optimization. The goal is to make the library easier to use for data science as well as 3d rendering. We also don't want to bake an interleaved vertex array during parsing and instead offer this through generator functions after the parsing is done. Making it possible to navigate the data through both materials and meshes should be possible.

Some tasks after the move:

  • Update all links to the repository
  • Set up new integrations (CI system etc)
  • Ensure new releases can be pushed to PyPI
  • General repository cleanup
  • Document the repository history

Do not triangulate faces

It seems triangulation is forced if one wants to read the faces from the obj file.

Is it possible to not triangulate and still read the face data?

can't reproduce examples

import pywavefront
scene = pywavefront.Wavefront('something.obj')
    scene = pywavefront.Wavefront('something.obj')
AttributeError: module 'pywavefront' has no attribute 'Wavefront'

This is in a venv with python 3.6, I have tried installing via pip and also via setup.py, none works

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.