glsl-zoom
v0.1.0
Published
glsl-zoom is a shader generator for WebGL, to easily display a specific subwindow (zoom) of a larger texture
Downloads
10
Maintainers
Readme
glsl-zoom
####Description
glsl-zoom is a shader generator for WebGL, to easily display a specific subwindow (zoom) of a larger texture.
See glsl-zoom-demo.js
for usage.
####Dependencies
- nodejs
- browserify
- glsl-quad
- regl (for demo)
- resl (for demo)
- jquery-browserify (for demo)
- nunjucks (for demo)
- budo (for quick demo as an alternative to running browserify)
####Demo
To run the demo, run:
cd ./glsl-zoom
#install npm dependencies
npm install
#browser should open with the demo
budo glsl-zoom-demo.js --open
Results:
branch | demo --------|------- master | glsl-zoom-demo develop | glsl-zoom-demo
####Docs
const zoom = require('./glsl-zoom.js');
The general idea is:
- the library acts almost like glsl-quad.
- it provides vertices, indices, uvs, vertex and fragment shaders.
- it requires the same uniforms as
glsl-quad
. - it requires two additional uniforms that represent the view-rectangle within the texture.
- a smaller view-rectangle means a closer zoom.
- the view-rectangle is specified via a "lower" and "upper" set of coordinates.
- the view-rectangle is in the same units as the uvs.
zoom.verts
- A list of vertices that can be used for webgl positions, that make up a quad (two triangles).
zoom.indices
- A list of indices that can be used for webgl triangles, that make up a quad (two triangles).
zoom.uvs
- A list of uv attributes for the vertices.
zoom.shader.vert()
- Returns the webgl 1.0 vertex shader to use.
- The vertex shader expects:
- A uniform float named
u_clip_y
, representing whether to flip the y-axis; values of 1 or -1. - An attribute list of vec2 positions of the vertices named
a_position
. - An attribute list of vec2 uvs of the vertices named
a_uv
.
- A uniform float named
zoom.shader.frag({borderClamp = false, borderColor = 'vec4(0,0,0,1)})
- A function that returns the webgl 1.0 fragment shader to use.
borderClamp
- A boolean indicating if the shader should use a border color when showing things off the edge of the texture; default is false, and the result is whatever WebGL clamping is chosen.borderColor
- A string containing a glsl vec4 value that will be used the for the over-the-border-color ifborderClamp
is set to true. can optionally use the keyword stringuniform
, which will then make the fragment shader expect a uniformvec4
with the nameu_border
.- The fragment shader uniforms:
- A uniform shader (sampler2D) named
u_tex
. - A uniform
vec2
namedu_zoom_uv_lower
, having values in the range [0,1], and representing the "lower" corner of a rectangle in uv-space of the texture. Note that opengl convention is uv-origin at the lower-left. - A uniform
vec2
namedu_zoom_uv_upper
, having values in the range [0,1], and representing the "upper" corner of a rectangle in uv-space of the texture. Note that opengl convention is uv-origin at the lower-left. - Optionally, if
borderClamp
is set as true, a uniformvec4
namedu_border
, having a color value (each component in the range[0, 1]
). This color will be used for pixels that are not within the texture (i.e instead of whatever clamp the texture is set to).
- A uniform shader (sampler2D) named
####Advanced Docs
Controlling the view window is simple, but powerful, but can be a bit of work.
glsl-zoom
provides some helper functions to do this. The following is the API documentation
of these functions.
zoomRegion
A common argument in the API, which represents a "circular" zoom region, with a center, and a radius. Note that although it has a "radius", the library currently supports only "manhattan distance", which effectively makes it a rectangle.
The form is documented here, instead of in each method:
// pointing at the center, with a radius covering the entire texture.
let zoomRegion = {
center: {x: .5, y: .5},
radius: {x: .5, y: .5}
};
zoom.region.translate ({zoomRegion, delta, bounds = null, boundType = 'overlap'})
This function translates a zoomRegion
in-place, by delta
.
zoomRegion
- The region that needs to be translated.delta
- The delta to translate thezoomRegion
by; of the form{x: 0.1, y: -0.2}
.bounds
- An optional parameter that will bound the translation, the type of bounding is specified by theboundType
argument.bounds
is of the formbounds = {lower: {x: 0, y: 0}, upper: {x: 1, y: 1}}
. Defaults tonull
, which means it will not be bounded and the function will translate freely.boundType
- A string value, one ofoverlap
orclamp
. Goes together with thebounds
parameter. Defaults tooverlap
. **NOTE: this argument is namedboundType
, NOTboundsType
. *clamp
- thezoomRegion
will not be allowed to translate outside of thebounds
at all. *overlap
- thezoomRegion
will not be allowed to translate to a location where it can no longer see thebounds
region.
zoom.region.scale (zoomRegion, ratio, bounds = null, boundType = 'overlap', minimumRadius = {x: 1.0 / (1 << 30), y: 1.0 / (1 << 30)}, maximumRadius = null)
Scales the zoomRegion
by modifying the radius. Operates in-place.
Similar to zoom.region.translate()
, see that method for more detailed
docs on some of the params.
zoomRegion
- The region that needs to be translated.ratio
- The radius will be multiplied by this value.bounds
- The radius will not grow outside of the bounds, which has a different logical meaning depending on the value ofboundType
. Seezoom.region.translate()
.boundType
- Modifies the meaning of thebounds
argument. Seezoom.region.translate()
.minimumRadius
- Before and after scaling, the radius will be clamped betweenminimumRadius
andmaximumRadius
, if they are notnull
. This can be important for avoidingNaNs
. Defaults to a very small number (1.0 / (1 << 30)
).
zoom.region.clamp ({ zoomRegion, bounds = null, boundType = 'overlap', minimumRadius = {x: 1.0 / (1 << 30), y: 1.0 / (1 << 30)}, maximumRadius = null})
Clamps the region, by bounds
or by radius. See zoom.region.translate()
.
zoom.region.clone ({zoomRegion})
Returns a deep copy of a zoomRegion
.
zoom.test.bounds.overlaps ({zoomRegion, bounds})
Checks if a zoomRegion
overlaps a bounds
. See zoom.region.translate()
.
zoom.test.bounds.contains ({zoomRegion, bounds})
Checks if a zoomRegion
is completely contained by bounds
. See zoom.region.translate()
.
zoom.util.delta.kbd ({downKeys})
A helper function that computes a delta
from the current set of keyboard keys that are pressed.
downKeys - A dictionary of JavaScript "key codes" as keys, and
true/false` values to indicate which keys are currently pressed.Returns a dictionary of the form
{x: +1, y: 0}
which indicates what the combination of arrow keys, numpad keys,WASD
keys make up in intended direction.
zoom.uv.lower ({zoomRegion})
Returns a list of the two lower coordinates.
So a region like zoomRegion = {center: {x: 0.5, y: 0.5}, radius: {x: 0.1, y: 0.1}}
would result
in a list such as [0.4, 0.4]
.
zoom.uv.lower ({zoomRegion})
Returns a list of the two upper coordinates.
So a region like zoomRegion = {center: {x: 0.5, y: 0.5}, radius: {x: 0.1, y: 0.1}}
would result
in a list such as [0.6, 0.6]
.
####Usage
See glsl-zoom-demo.js
for a full demo using regl
and resl.
An excerpt:
const drawTexture = regl({
vert: zoom.shader.vert(),
frag: zoom.shader.frag({borderClamp: true, borderColor: 'uniform'}),
attributes: {
a_position: zoom.verts,
a_uv: zoom.uvs
},
elements: zoom.indices,
uniforms: {
u_tex: regl.prop('texture'),
u_clip_y: 1,
u_zoom_uv_lower: regl.prop('lower'),
u_zoom_uv_upper: regl.prop('upper'),
u_border: [0, 0, 0, 1]
}
});
// will zoom into a region of the texture from `(0.2, 0.2) => (0.7, 0.7)`, a 2X zoom in.
// change these values to control the view-window.
drawTexture({texture, lower: [.2, .2], upper: [.7, .7]});