Hi everyone, this is the first version of zShapes
(~3.5MB, includes samples).
WHAT IT IS [BRIEFLY]
zShapes is a tool that allows you to render resolution independent vector graphics in real-time on your GPU. The tool can convert any Java2D shape to a set of triangles that can later be rendered with OpenGL. Antialiasing is also supported.
HOW IT STARTED
zShapes started as a little weekend project. I had been impressed by UlfJack's Thinlet
port to LWJGL, except one thing: it was lacking fonts. So I was thinking "now he's going to have to do the whole texture thing, what a bunch of crap that technique is". He was going to do it, I'm doing it in Marathon, everyone else is doing it. My next thought, "it should be possible to do this right with today's GPUs". So I decided that it was going to be a "font rendering" weekend. Turned out to be a month of course.
WHAT IT IS
After an exhaustive search of my paper library, I came across a really interesting paper:Resolution Independent Curve Rendering using Programmable Graphics Hardware
, by Charles Loop and Jim Blinn
The paper describes a technique that can be used to render any quadratic Bezier curve using a single drawing primitive: a triangle and a simple function that is evaluated per-pixel. Basically zShapes is an implementation of this technique. It is a simple library at it's core, but is accompanied by an editor, that provides a UI to do the shape->triangle conversion, and a viewer, that renders the shapes with OpenGL.
The primary function in the Editor is the shape triangulation. You give it any Java2D shape and it outputs the generated triangles. It's not a simple delaunay triangulation, a lot of work is done to remove overlaps and clean-up the mesh, and a lot of triangle breaking & triangle additions are needed to support the antialiasing implementation.
There are two ways to produce work for the Editor:
- A simple dialog allows you to create some text using any font supported by the system. The text outline (as a Java2D shape) is then converted to triangles.
- Any SVG file can be imported and used as a Java2D shape. I use the Batik SVG Toolkit
After a triangulation, the generated mesh can be exported to file.
The Editor has a few other features that were added to make it more user friendly:
- Easy navigation/zooming
- A console that logs what the triangulator is doing
- Various overlays for debugging (shape overlay, points, statistics, etc)
The Viewer is an LWJGL application that renders the generated meshes. It provides basic navigation/zooming and support for toggling antialiasing. What's important though is the rendering implementations. The technique is supposed to work with fragment shaders, but I've implemented the following variations:
With no antialiasing
- NV_register_combiners (GeForce 3 or better)
- ATI_fragment_shader (ATI 8500 or better)
- GLSL fragment shaders (GeForce FX, ATI 9500 or better)
- GLSL fragment shaders, using shader derivatives (GeForce FX, ATI X1x00 or better)
- GLSL fragment shaders, using texture derivatives (ATI 9x00, ATI Xx00)
It was a little difficult to overcome the accuracy limitations of NV_RCs and ATI_FS, but it's usable now by many more users.
- It's a resolution independent technique (duh). You can zoom in as much as you want and it never produces aliasing. The only limitation is GPU accuracy, that can cause some artifacts in extreme cases (when zooming, also the non-GLSL paths are more sensitive).
- Rendering is very fast. Also, if compared to the alternative (massive triangle tesselation), there's a very nice balance between vertex and fragment processing.
- It has tiny memory overhead. The meshes are generally low-poly (depending on the shape of course) and the geometry data is only 3 floats per vertex.
- Antialiasing is done in the shader using derivatives. That means it doesn't need multisampling to work, neither POLYGON_SMOOTH. It's very fast too.
- No shape coloring/shading is currently supported. The renderer only generates an alpha value (in shape or out of shape). Basic shading could be very easily added though (colors, gradients, etc).
- The Editor triangulation is quite slow.
- Cubic curves are currently approximated with quadratics. Depending on the error threshold, many unnecessary triangles may be generated.
- Antialiasing is quite poor is certain cases.
- The Editor currently runs on Windows & Linux only. MacOSX is also supported for the Viewer.
There are a lot of improvements that can be done, but I don't think I'll spend much more time on this. Given enough interest, I could set up a project on SF for others to contribute, though. Given no interest, I'll post the source here as-is. Anyway, my e-mail is spasi [at] zdimensions [dot] gr. The list:
- The triangulation is currently done using Triangle
, a powerful and robust delaunay triangulator, which is unfortunately written in C. This limits the Editor to Windows & Linux only. A Java port of Triangle, or any other decent Java-based triangulator would be nice to have. Also, it would more easily allow the library to be used at runtime.
- All the algorithms are almost brute-force and "linear" in design. Virtually every part of the implementation can be sped up and optimized memory-wise.
- The Editor currently misses a way to produce a "font map", that is, a glyph list that can used to render any text in a GL application. I'll do this soon anyway.
- Support for display lists and VBO should be added in the Viewer.
- Support for basic SVG coloring features may be added to the Viewer.
- It's not much of library as-is. Both the triangulator and the renderers should be made more general.
- Support for JOGL rendering could be added.
- The RICR paper also describes how to render cubic curves. My math skills are too limited for that though, I couldn't understand it and also didn't have time to understand it. It would be a great addition though. Especially for SVG shapes that are heavy on cubic curvers, a significant reduction in triangle count could be achieved (a tradeoff for a few more fragment shader instructions).
- I don't think I've completely understood the way antialiasing is supposed to work. Basically external triangles are added to the mesh, but that has forced me to implement more than one hack to overcome quality issues (also the triangle count is increased unnecessarily). I may contact the paper authors about this.
- Subpixel antialiasing could be implemented.
- Another interesting technique that could be explored is GLSL Conics
SCREENSHOTS (Editor | Viewer, click for hi-res)
A text example:
An SVG example:
That's it, C&C welcome.