Evict draft.org to blag, 2021-07-27-procedural-meshes.org
This commit is contained in:
parent
d9ce4b4dc3
commit
af477efb7b
164
draft.org
164
draft.org
@ -1,164 +0,0 @@
|
|||||||
* This post needs a title
|
|
||||||
|
|
||||||
(TODO: a note to me, reading later: you don't need to give your
|
|
||||||
entire life story here.)
|
|
||||||
|
|
||||||
(TODO: pictures will make this post make a *lot* more sense, and it
|
|
||||||
may need a lot of them)
|
|
||||||
|
|
||||||
Context Free is one of my favorite projects since I discovered it
|
|
||||||
about 2010. It's one I've written about before (TODO: link to my
|
|
||||||
posts), played around in (TODO: link to images), presented on, as
|
|
||||||
well as re-implemented myself in different ways (see: [[https://github.com/hodapp87/contextual][Contextual]]).
|
|
||||||
That is sometimes because I wanted to do something Context Free
|
|
||||||
couldn't, such as make it realtime and interactive, and sometimes
|
|
||||||
because implementing its system of recursive grammars and
|
|
||||||
replacement rules can be an excellent way to learn things in a new
|
|
||||||
language. (I think it's similar to [[https://en.wikipedia.org/wiki/L-system][L-systems]], but I haven't yet
|
|
||||||
learned those very well.)
|
|
||||||
|
|
||||||
I've also played around in 3D graphics, particularly raytracing,
|
|
||||||
since about 1999 in PolyRay and POV-Ray. POV-Ray is probably what
|
|
||||||
led me to learn about things like implicit surfaces, parametric
|
|
||||||
surfaces, and procedural geometry - its scene language is full of
|
|
||||||
constructs for that. Naturally, this led me to wonder how I might
|
|
||||||
extend Context Free's model to work more generally with 3D geometry,
|
|
||||||
and let me use it to produce procedural geometry.
|
|
||||||
|
|
||||||
[[http://structuresynth.sourceforge.net/index.php][Structure Synth]] of course already exists as a straightforward
|
|
||||||
generalization of Context Free's model to 3D (thank you to Mikael
|
|
||||||
Hvidtfeldt Christensen's blog [[http://blog.hvidtfeldts.net/][Syntopia]], another of my favorite
|
|
||||||
things ever, for introducing me to it awhile ago). See also
|
|
||||||
[[https://kronpano.github.io/BrowserSynth/][BrowserSynth]]. However, at some point I realized they weren't
|
|
||||||
exactly what I wanted. Structure Synth lets you combine together 3D
|
|
||||||
primitives to build up a more complex scene - but doesn't try to
|
|
||||||
properly handle any sort of *joining* of these primitives in a way
|
|
||||||
that respects many of the 'rules' of geometry that are necessary for
|
|
||||||
a lot of tools, like having a well-defined inside/outside, not being
|
|
||||||
self-intersecting, being manifold, and so forth.
|
|
||||||
|
|
||||||
Tools like [[https://openscad.org/][OpenSCAD]], based on [[https://www.cgal.org/][CGAL]], handle the details of this, and
|
|
||||||
I suspect that [[https://www.opencascade.com/][Open CASCADE]] (thus [[https://www.freecadweb.org/][FreeCAD]]) also does. In CAD work,
|
|
||||||
it's crucial. I experimented with similar recursive systems with
|
|
||||||
some of these, but I quickly ran into a problem: they were made for
|
|
||||||
actual practical applications in CAD, not for my nonsensical
|
|
||||||
generative art, and they scaled quite poorly with the sort of
|
|
||||||
recursion I was asking for.
|
|
||||||
|
|
||||||
Implicit surfaces (or one of the many
|
|
||||||
equivalent-except-for-when-it's-not names for this, e.g. F-Reps or
|
|
||||||
distance bounds or SDFs or isosurfaces) handle almost all of this
|
|
||||||
well! They express CSG (TODO: link to CSG) operations, they can be
|
|
||||||
rendered directly on the GPU via shaders, operations like blending
|
|
||||||
shapes or twisting them are easy... for more on this, see [[http://blog.hvidtfeldts.net/][Syntopia]]
|
|
||||||
again, or nearly anything by [[https://iquilezles.org/][Inigo Quilez]], or look up raymarching
|
|
||||||
and sphere tracing, or see [[https://ntopology.com/][nTopology]], or Matt Keeter's work with
|
|
||||||
[[https://www.libfive.com/][libfive]] and [[https://www.mattkeeter.com/research/mpr/][MPR]]. They're pure magic and they're wonderfully elegant
|
|
||||||
and I'll probably have many other posts on them.
|
|
||||||
|
|
||||||
However, there is one big issue: turning implicit surfaces to good
|
|
||||||
meshes for rendering /is a huge pain/, and while many renderers can
|
|
||||||
handle implicit surfaces directly, Blender's renderers cannot. I
|
|
||||||
have other posts on this as well, but for now, take it on faith.
|
|
||||||
This is why I did not try to use implicit surfaces for this project.
|
|
||||||
(TODO: Make those posts.)
|
|
||||||
|
|
||||||
With these limitations in mind, around 2018 June I had started
|
|
||||||
jotting some ideas down. The gist is that I wanted to create
|
|
||||||
"correct-by-construction" meshes from these recursive grammars. By
|
|
||||||
that, I meant: incrementally producing the desired geometry as a
|
|
||||||
mesh, triangle-by-triangle, in such a way that guaranteed that the
|
|
||||||
resultant mesh had the desired detail level, was a manifold surface,
|
|
||||||
and that it was otherwise a well-behaved mesh (e.g. no degenerate
|
|
||||||
triangles, no self-intersection, no high-degree vertices, no
|
|
||||||
triangles of extreme angles) - rather than attempting to patch up
|
|
||||||
the mesh after its creation, or subdividing it to the necessary
|
|
||||||
detail level. For something similar to what I mean (though I didn't
|
|
||||||
have this in mind at the start), consider the [[https://en.wikipedia.org/wiki/Marching_squares][marching squares]]
|
|
||||||
algorithm, which is guaranteed to produce closed, manifold meshes.
|
|
||||||
|
|
||||||
(TODO: Illustrate this somehow)
|
|
||||||
|
|
||||||
The form it took in my notes was in sort of "growing" or "extruding"
|
|
||||||
a mesh per these recursive rules, building in these guarantees (some
|
|
||||||
of them at least) by way of inductive steps.
|
|
||||||
|
|
||||||
My meandering path to implementing it went something like this:
|
|
||||||
|
|
||||||
- Write some very ad-hoc Python to generate a mesh of a parametric
|
|
||||||
conversion of my annoying spiral isosurface from 2005 by breaking
|
|
||||||
it into planar "slices" or "frames", which move along the geometry
|
|
||||||
and then are connected together at corresponding vertices.
|
|
||||||
- Explore [[https://github.com/thi-ng/geom][thi.ng/geom]] and pretty quickly give up - but in the
|
|
||||||
process, discover [[https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.42.8103][Parallel Transport Approach to Curve Framing]].
|
|
||||||
- Implement that paper in Python, reusing the basic model from my
|
|
||||||
prior code. (See [[https://github.com/Hodapp87/parallel_transport][parallel_transport]])
|
|
||||||
- Again continue with this model, allowing more arbitrary operations
|
|
||||||
than parallel frame transport, eventually integrating most of what
|
|
||||||
I wanted with the recursive grammars. (See
|
|
||||||
[[https://github.com/Hodapp87/automata_scratch/tree/master/python_extrude_meshgen][automata_scratch/python_extrude_meshgen]])
|
|
||||||
- Keep running into limitations in python_extrude_meshgen, and start
|
|
||||||
[[https://github.com/Hodapp87/prosha][Prosha]] in Rust - partly as a redesign/rewrite to avoid these
|
|
||||||
limitations, and partly because I just wanted to learn Rust.
|
|
||||||
- Realize that Rust is the wrong tool for the job, and rewrite
|
|
||||||
*again* in Python but with a rather different design and mindset.
|
|
||||||
|
|
||||||
(this is, of course, ignoring projects on various other tangents)
|
|
||||||
|
|
||||||
(TODO: Maybe split these off into sections for each one?)
|
|
||||||
|
|
||||||
Somewhere in here, I concluded that my fundamental idea was
|
|
||||||
half-broken. It half-worked: I was able to produce closed, manifold
|
|
||||||
meshes this way, and it could be tedious, but not *that* difficult.
|
|
||||||
However, all of my attempts to also produce "good" meshes this way
|
|
||||||
failed miserably.
|
|
||||||
|
|
||||||
(TODO: Can I find examples of this?)
|
|
||||||
|
|
||||||
A few of the same fundamental issues kept cropping up. One is that
|
|
||||||
the recursive rules I used for generating geometry (inspired heavily
|
|
||||||
by those in Context Free) were inherently based around discrete
|
|
||||||
steps, generating discrete entities, like vertices, edges, and face;
|
|
||||||
it made no sense to "partially" apply a rule, especially if that
|
|
||||||
rule involved some kind of branching. I kept trying to treat it as
|
|
||||||
something continuous for the sake of being able to "refine" the mesh
|
|
||||||
to as fine of detail as I wanted. Further, I was almost never
|
|
||||||
consistent with the nature of this continuity: sometimes I wanted to
|
|
||||||
treat it like a parametric curve (one continuous parameter),
|
|
||||||
sometimes I wanted to treat it like a parametric surface (two
|
|
||||||
continuous parameters), sometimes I wanted to treat it like an
|
|
||||||
implicit surface (with... theoretically two continuous parameters,
|
|
||||||
just not explicit ones?). It was a mess, and it's part of why my
|
|
||||||
Prosha repository is a graveyard of branches.
|
|
||||||
|
|
||||||
The recursive rules were still excellent at expressing arbitrarily
|
|
||||||
complex, branching geometry - and I really wanted to keep this basic
|
|
||||||
model around somehow. After some reflection, I believed that the
|
|
||||||
only way to do this was to completely separate the process of
|
|
||||||
meshing/refinement/subdivision from the recursive rules.
|
|
||||||
|
|
||||||
This would have been obvious if I read the guides from [[https://graphics.pixar.com/opensubdiv/overview.html][OpenSubdiv]]
|
|
||||||
instead of reimplementing it badly. Their [[https://graphics.pixar.com/opensubdiv/docs/subdivision_surfaces.html][subdivision surface]]
|
|
||||||
documentation covers a lot, but I found it incredibly clear and
|
|
||||||
readable. Once I understood how OpenSubdiv was meant to be used, it
|
|
||||||
made a lot of sense: I shouldn't be trying to generate the "final"
|
|
||||||
mesh, I should be generating a mesh as the /control cage/, which
|
|
||||||
guides the final mesh. Further, I didn't even need to bother with
|
|
||||||
OpenSubdiv's C++ API, I just needed to get the geometry into
|
|
||||||
Blender, and Blender would handle the subdivision via OpenSubdiv.
|
|
||||||
|
|
||||||
One minor issue is that this control cage isn't just a triangle
|
|
||||||
mesh, but a triangle mesh plus edge creases. I needed a way to get
|
|
||||||
this data into Blender. However, the only format Blender can read
|
|
||||||
edge creases from is [[http://www.alembic.io/][Alembic]]. Annoyingly, its [[http://docs.alembic.io/reference/index.html#alembic-intro][documentation]] is
|
|
||||||
almost completely nonexistent, the [[https://alembic.github.io/cask/][Cask]] bindings still have spotty
|
|
||||||
Python 3.x support, and when I tried to run their example code to
|
|
||||||
produce some files, and Blender was crashing when importing them.
|
|
||||||
Until I shave that yak, I am instead generating the mesh data
|
|
||||||
directly in Blender (via its Python interpreter), adding it to the
|
|
||||||
scene, and then setting its creases via its Python API.
|
|
||||||
|
|
||||||
TODO while I'm not so tired:
|
|
||||||
|
|
||||||
What is the aim of this post? To explain Prosha? To explain
|
|
||||||
current work, including Prosha?
|
|
||||||
Loading…
x
Reference in New Issue
Block a user