snogglethorpe / snogray

Snogray renderer

Home Page:http://www.nongnu.org/snogray

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add "Surface Loaders"

snogglethorpe opened this issue · comments

Currently snogray has two types of loaders: scene loaders and mesh loaders. However the first is often too broad (it load an entire top-level scene, and is restricted to "scene formats"), and the second too narrow (it can only load into a single mesh, and snogray's meshes are fairly restrictive).

Users generally don't want to worry about such details, and probably just want to load files full of geometry/lights/whatever and add them to the scene without worrying about format details.

A better way would be to add a new concept, the "surface loader", e.g. surface.load, which would load surfaces (including meshes) / materials / lights etc from a single file, and return a surface of some sort. The only guarantee would be that it would return a surface of some sort; in practice it would probably be a surface-group, but could be a mesh in some cases, etc; the only guarantee would be that it's a surface.

This would make it much easier to deal with things like mesh formats that are too flexible for our meshes, e.g. which contain multiple materials, and would even allow a way to load entire scenes and incorporate them into other scenes as atomic units.

Mesh loaders would still have some place, for those (rare) cases where you want to a load a mesh and then do further manipulation on it, but they would mostly become an internal mechanism.

Possible interface:

surface.load (filename [, params])

... where params is a table of various other optional parameters, and would just be passed directly to the loader for the most part (an exception might be a "format" param overriding the scene format).

The new surface loaders would be pretty much exactly the same as existing scene loaders except that they wouldn't deal with camera information. Probably the two should be variants of the same mechanism, e.g., surface loaders could accept an optional "camera" parameter, and perform any camera manipulation on that.

Maybe it's better to just toss the concept of a "scene loader" entirely, and make surface loaders the abstraction used for all general loading. The camera fits awkwardly into the concept of a scene-loader anyway, so it would be really no worse to just have it fit awkwardly into surface-loaders instead... :]

Loading a scene would then become simply something like:

scene:add (surface.load (scenefile, {camera = camera, ...other params...}))

Internally, the scene already just stores everything in a surface-group anyway. [This might result in more surface-groups being used, but that's not really an issue, as they are bypassed during rendering.]

Some issues:

  • Surface-groups currently can only store surfaces (naturally enough), but it would be trivial to have them support a list of lights as well.
  • Currently scene loaders expect an environ argument, which contains fields for scene, camera, params (top-level rendering / output / etc parameters), and manipulates those accordingly. What should the interface to surface-loaders look like? If loading a non-top-level surface, having scene seems a little bit of a misnomer, but it might be good enough (loading a surface is then like loading an "embedded scene"). A surface-group presently mostly the same interface as a scene anyway, so having a surface-group store in the scene variable would do nicely.
  • environ is currently defined once in the top-level driver (as a scene is only loaded once). maybe this definition should be moved into the Lua loader so that loaded surfaces all have their own environment.
  • What should the rules be for top-level versus non-top-level use? Simply have camera and params be nil? Have a dummy camera object that just ignores manipulation (so that scene files could be loaded as-is for both top-level and non-top-level use)?

An additional good interface to add would be a surface.model variant that allows one to just load a model from a file, e.g., surface.model "mymodel.obj". Internally it would just do surface.model (surface.load (...)), but it would be a nice and natural interface for users.

Additionally some though should be given to how to deal with transforms. A loaded surface can always be put into a model and instanced, but that may sometimes be too annoying, or have efficiency effects. Possible solutions: (1) expose some sort of "transform" parameter to surface loaders and have them transform all loaded geometry by that, (2) extend all surface types to support a transform method for destructive transformation, so users could safely transform anything they loaded, or (3) both.