nanovg icon indicating copy to clipboard operation
nanovg copied to clipboard

Few questions

Open BrodaJarek opened this issue 6 years ago • 7 comments

What are bounds for? What are nvg__calculateJoins and nvg__expandFill? I would like to learn how to render 2d signed distance field quad, triangle, you know, primitive geometry, but with high quality. Do you have any tutorials? I have searched whole Internet to get some informations, but I am a noob in those subjects (not exactly, I know basics, batching etc.) and could not find any useful informations.

BrodaJarek avatar Feb 04 '19 20:02 BrodaJarek

I don't have any good resources. I have learned most of 2D rendering snippet by snippet from various sources.

NanoVG uses stencil buffer to render non-convex polygons. To do that, it first renders the shape of the polygon in the stencil buffer, and then renders a quad containing the all vertices to fill the polygon. bounds is the bounding box of a path.

nvg__calculateJoins takes a polygon as input and wides it to a triangle strip which is used to render the path. nvg__expandFill is similar but is used to alter a filled path for antialiasing. In order to render anti-aliased polygon, the polygon is shrank by 0.5px and then a smooth "feather" is drawn outside the polygon. The 0.5px inset is important, or else the polygon will look too fat.

This is good source on anti-aliased lines: https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter22.html

So the whole rendering process first turns all shapes (circles, paths, rects) in to bezier curves, then the curves are tessellated into polygons, and finally the path is either expanded to a stroke, or filled polygon.

There's a quite a bit of buffering going on, so that might make it a bit hard to

memononen avatar Feb 04 '19 20:02 memononen

Thank you. I have got few more questions. What is bevel (in nbevel n means number/count I guess)? What stand for dl and dmr, and dm(point struct) (I guess d means difference, but l and mr and dm? l may be length)? dlx0, dly0, dlx1, dly1, dmr2 in calculateJoins Why do you calculate cross product? Does not it calculate an axis in a third dimension?

BrodaJarek avatar Feb 05 '19 21:02 BrodaJarek

nbevel describes how many points on the path needs beveling, see: https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty

Each point on the path has direction vector (dx/dy), dlx* & dly* are normals (towards left) at that point. dm* is "middle" vector between those two normals and is used to calculate the miter offset together with dmr2. I think I have borrowed some ideas for the line joins from libart. You should check that out, maybe it is better documented.

memononen avatar Feb 06 '19 04:02 memononen

I have been searching for libart, but I could not find any library (or even some notes) called like this. If I have not reached a volume of questions yet: what is xform, feather, paint matrix?

BrodaJarek avatar Feb 16 '19 10:02 BrodaJarek

Libart can be found here: https://www.levien.com/libart/

  • xform is 2D 2x3 affine transfrom matrix, similar is used by html5 canvas
  • feather means the 1px gradient at the edges of shapes, this is used for anti-aliasing. gradients may use the same term, there it means the width of a gradient
  • paint matrix defines the orientation and location of the gradient/pattern, in the backend it is inversed, meaning that if you transform a world position with the matrix, it will return a normalized (in range 0..1) point along the pattern. i.e. in linear gradient, this 0..1 point defines the interpolation between start/end color

memononen avatar Feb 16 '19 16:02 memononen

I'm slowly beginning to understand. So there are 2 xforms. One for geometry transformation and one for "painting" transformations and as I see they are not connected somehow. There are still few things cannot get. Paint matrix for example.

  • on cpu it is mat3x4, but gpu stores it as mat3x3. Why cannot it be 3x3 on a cpu side?

  • meaning that if you transform a world position with the matrix - I cannot find where it world position is transformed with this matrix. I could've got it wrong. What is world position - vertex position in a clip space or position * model = world space?

BrodaJarek avatar Feb 18 '19 22:02 BrodaJarek

Nanovg uses 2D affine matrix throughout. A 2D affine matrix is 2x3, where top 2x2 is the rotation/scale/shear part, and the last column is position. The matrix is actually 3x3, but since the bottom row is always [0 0 1], it does not need to be stored. https://en.wikipedia.org/wiki/Affine_transformation

The 2x3 matrix is converted to 3x3 matrix for opengl rendering. It's done because GL ES2 has only square matrices. I think the 3x4 matrix thing happened when we moved to uniform buffers. I was probably needed for the buffer memory layout.

World position is the one defined by the NanoVG viewport (after nanovg transformations). That is, if you dont change the transform, and set position to (10,10), that is world position. It is fpos in the shaders. The opengl vertex position can be different, because of hi-dpi rendering.

memononen avatar Feb 19 '19 07:02 memononen