Add user docs about Skia coordinate spaces
Includes a general explanation of device vs. local, how shaders don't move with geometry, and how to use canvas transforms. Also shows localMatrix on an SkShader. Finally, links to that from the SkSL page, and adds SkSL-specific notes about coordinates. Bug: skia:11763 Change-Id: I31462aff66ff8514392098b972a10e7c96e4f254 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/393516 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
6d635543e2
commit
0351d5af88
76
site/docs/user/coordinates.md
Normal file
76
site/docs/user/coordinates.md
Normal file
@ -0,0 +1,76 @@
|
||||
---
|
||||
title: 'Skia Coordinate Spaces'
|
||||
linkTitle: 'Coordinates'
|
||||
---
|
||||
|
||||
## <span id="overview">Overview</span>
|
||||
|
||||
Skia generally refers to two different coordinate spaces: **device** and **local**. Device
|
||||
coordinates are defined by the surface (or other device) that you're rendering to. They range from
|
||||
`(0, 0)` in the upper-left corner of the surface, to `(w, h)` in the bottom-right corner - they are
|
||||
effectively measured in pixels.
|
||||
|
||||
---
|
||||
|
||||
## <span>Local Coordinates</span>
|
||||
|
||||
The local coordinate space is how all geometry and shaders are supplied to the `SkCanvas`. By
|
||||
default, the local and device coordinate systems are the same. This means that geometry is
|
||||
typically specified in pixel units. Here, we position a rectangle at `(100, 50)`, and specify that
|
||||
it is `50` units wide and tall:
|
||||
|
||||
<fiddle-embed name='96f782b723c5240aab440242f4c7cbfb'></fiddle-embed>
|
||||
|
||||
Local coordinates are also used to define and evaluate any `SkShader` on the paint. Here, we define
|
||||
a linear gradient shader that goes from green (when `x == 0`) to blue (when `x == 50`):
|
||||
|
||||
<fiddle-embed name='97cf81a465fdeff01d2298e07a0802a3'></fiddle-embed>
|
||||
|
||||
---
|
||||
|
||||
## <span>Shaders Do Not Move With Geometry</span>
|
||||
|
||||
Now, let's try to draw the gradient-filled square at `(100, 50)`:
|
||||
|
||||
<fiddle-embed name='3adc73d23d57084f954f52c6b14c8772'></fiddle-embed>
|
||||
|
||||
What happened? Remember, the local coordinate space has not changed. The origin is still in the
|
||||
upper-left corner of the surface. We have specified that the geometry should be positioned at
|
||||
`(100, 50)`, but the `SkShader` is still producing a gradient as `x` goes from `0` to `50`. We have
|
||||
slid the rectangle across the gradient defined by the `SkShader`. Shaders do not move with the
|
||||
geometry.
|
||||
|
||||
---
|
||||
|
||||
## <span>Transforming Local Coordinate Space</span>
|
||||
|
||||
To get the desired effect, we could create a new gradient shader, with the positions moved to
|
||||
`100` and `150`. That makes our shaders difficult to reuse. Instead, we can use methods on
|
||||
`SkCanvas` to **change the local coordinate space**. This causes all local coordinates (geometry
|
||||
and shaders) to be evaluated in the new space defined by the canvas' transformation matrix:
|
||||
|
||||
<fiddle-embed name='ce89b326b2bbe41587eec738706bf155'></fiddle-embed>
|
||||
|
||||
---
|
||||
|
||||
## <span>Transforming Shader Coordinate Space</span>
|
||||
|
||||
Finally, it is possible to transform the coordinate space of the `SkShader`, relative to the canvas
|
||||
local coordinate space. To do this, you supply a `localMatrix` parameter when creating the
|
||||
`SkShader`. In this situation, the geometry is transformed by the `SkCanvas` matrix. The `SkShader`
|
||||
is transformed by the `SkCanvas` matrix **and** the `localMatrix` for that shader. The other way to
|
||||
think about this: The `localMatrix` defines a transform that maps the shader's coordinates to the
|
||||
coordinate space of the geometry.
|
||||
|
||||
To help illustrate the difference, here's our gradient-filled box. It's first been translated `50`
|
||||
units over and down. Then, we apply a `45` degree rotation (pivoting on the center of the box) to
|
||||
the canvas. This rotates the geometry of the box, and the gradient inside it:
|
||||
|
||||
<fiddle-embed name='d4b52d94342f1b55900d489c7ba8fd21'></fiddle-embed>
|
||||
|
||||
Compare that to the second example. We still translate `50` units over and down. Here, though, we
|
||||
apply the `45` degree rotation *only to the shader*, by specifying it as a `localMatrix` to the
|
||||
`SkGradientShader::MakeLinear` function. Now, the box remains un-rotated, but the gradient rotates
|
||||
inside the box:
|
||||
|
||||
<fiddle-embed name='886fa46943b67e0d6aa78486dcfbcc2c'></fiddle-embed>
|
@ -81,4 +81,18 @@ by Skia clamping the color's RGB values to its alpha.
|
||||
|
||||
## <span id="coords">Coordinate Spaces</span>
|
||||
|
||||
Under construction
|
||||
To understand how coordinates work in SkSL, you first need to understand
|
||||
[how they work in Skia](/docs/user/coordinates). If you're comfortable with Skia's coordinate
|
||||
spaces, then just remember that the coordinates supplied to your `main()` are **local**
|
||||
coordinates. They will be relative to the coordinate space of the `SkShader`. This will match the
|
||||
local space of the canvas and any `localMatrix` transformations. Additionally, if the shader is
|
||||
invoked by another, that parent shader may modify them arbitrarily.
|
||||
|
||||
In addition, the `SkShader` produced from an `SkImage` does not use normalized coordinates (like a
|
||||
texture in GLSL). It uses `(0, 0)` in the upper-left corner, and `(w, h)` in the bottom-right
|
||||
corner. Normally, this is exactly what you want. If you're sampling an `SkImageShader` with
|
||||
coordinates based on the ones passed to you, the scale is correct. However, if you want to adjust
|
||||
those coordinates (to do some kind of re-mapping of the image), remember that the coordinates are
|
||||
scaled up to the dimensions of the image:
|
||||
|
||||
<fiddle-embed name='492ddaa829dd1ff3f1358659cd58557b'></fiddle-embed>
|
||||
|
Loading…
Reference in New Issue
Block a user