1 | gl-shader
|
2 | =========
|
3 | A wrapper for WebGL shaders. Part of [stack.gl](http://stack.gl)
|
4 |
|
5 | # Example
|
6 |
|
7 | Try it out now in your browser: [http://stackgl.github.io/gl-shader/](http://stackgl.github.io/gl-shader/)
|
8 |
|
9 | ```javascript
|
10 | var shell = require('gl-now')()
|
11 | var createShader = require('gl-shader')
|
12 | var shader, buffer
|
13 |
|
14 | shell.on('gl-init', function() {
|
15 | var gl = shell.gl
|
16 |
|
17 | //Create shader
|
18 | shader = createShader(gl,
|
19 | 'attribute vec3 position;\
|
20 | varying vec2 uv;\
|
21 | void main() {\
|
22 | gl_Position = vec4(position, 1.0);\
|
23 | uv = position.xy;\
|
24 | }',
|
25 | 'precision highp float;\
|
26 | uniform float t;\
|
27 | varying vec2 uv;\
|
28 | void main() {\
|
29 | gl_FragColor = vec4(0.5*(uv+1.0), 0.5*(cos(t)+1.0), 1.0);\
|
30 | }')
|
31 |
|
32 | //Create vertex buffer
|
33 | buffer = gl.createBuffer()
|
34 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
|
35 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
36 | -1, 0, 0,
|
37 | 0, -1, 0,
|
38 | 1, 1, 0
|
39 | ]), gl.STATIC_DRAW)
|
40 | })
|
41 |
|
42 | shell.on('gl-render', function(t) {
|
43 | var gl = shell.gl
|
44 |
|
45 | //Bind shader
|
46 | shader.bind()
|
47 |
|
48 | //Set attributes
|
49 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
|
50 | shader.attributes.position.pointer()
|
51 |
|
52 | //Set uniforms
|
53 | shader.uniforms.t += 0.01
|
54 |
|
55 | //Draw
|
56 | gl.drawArrays(gl.TRIANGLES, 0, 3)
|
57 | })
|
58 | ```
|
59 |
|
60 | Here is the result:
|
61 |
|
62 | <img src="https://raw.github.com/stackgl/gl-shader/master/screenshot.png">
|
63 |
|
64 | # Install
|
65 |
|
66 | npm install gl-shader
|
67 |
|
68 | # API
|
69 |
|
70 | ```javascript
|
71 | var createShader = require('gl-shader')
|
72 | ```
|
73 |
|
74 |
|
75 | ### Constructor
|
76 |
|
77 | There are two main usages for the constructor. First,
|
78 |
|
79 | #### `var shader = createShader(vertexSource, fragmentSource[, uniforms, attributes])`
|
80 |
|
81 | Constructs a wrapped shader object with shims for all of the uniforms and attributes in the program.
|
82 |
|
83 | * `gl` is the webgl context in which the program will be created
|
84 | * `vertexSource` is the source code for the vertex shader
|
85 | * `fragmentSource` is the source code for the fragment shader
|
86 | * `uniforms` is an (optional) list of all uniforms exported by the shader program
|
87 | * `attributes` is an (optional) list of all attributes exported by the shader program
|
88 |
|
89 | The optional `uniforms` and `attributes` arrays have the following format. This will be extracted at run-time from the shader, so you can typically omit the `uniforms` and `attributes` arguments.
|
90 |
|
91 | ```js
|
92 | {
|
93 | uniforms: [
|
94 | { type: 'mat4', name: 'projection' },
|
95 | { type: 'sampler2D', name: 'texture0' }
|
96 | ],
|
97 | attribuets: [
|
98 | { type: 'vec3', name: 'position' }
|
99 | ]
|
100 | }
|
101 | ```
|
102 |
|
103 | You can specify a default `location` number for each attribute, otherwise WebGL will bind it automatically.
|
104 |
|
105 | **Returns** A compiled shader object.
|
106 |
|
107 | #### `var shader = createShader(gl, opt)`
|
108 |
|
109 | The same as above, but takes an object instead of a parameter list.
|
110 |
|
111 | * `gl` is a WebGL context
|
112 | * `opt.vertex` a vertex shader source
|
113 | * `opt.fragment` a fragment shader source
|
114 | * `opt.uniforms` (optional) a list of uniforms
|
115 | * `opt.attributes` (optional) a list of attributes
|
116 |
|
117 | **Returns** A wrapped shader object
|
118 |
|
119 | ### Methods
|
120 |
|
121 | #### `shader.bind()`
|
122 | Binds the shader for rendering
|
123 |
|
124 | #### `shader.update(vertSource,fragSource[,uniforms,attributes])`
|
125 | Rebuilds the shader object with new vertex and fragment shaders (same behavior as constructor)
|
126 |
|
127 | #### `shader.update(opt)`
|
128 | Rebuilds the shader object with new vertex and fragment shaders (same behavior as constructor)
|
129 |
|
130 | #### `shader.dispose()`
|
131 | Deletes the shader program and associated resources.
|
132 |
|
133 | ### Properties
|
134 |
|
135 | #### `gl`
|
136 | The WebGL context associated to the shader
|
137 |
|
138 | #### `program`
|
139 | A reference to the underlying program object in the WebGL context
|
140 |
|
141 | #### `vertShader`
|
142 | A reference to the underlying vertex shader object
|
143 |
|
144 | #### `fragShader`
|
145 | A reference to the underlying fragment shader object
|
146 |
|
147 | ### Uniforms
|
148 | The uniforms for the shader program are packaged up as properties in the `shader.uniforms` object. The shader must be bound before the uniforms are assigned. For example, to update a scalar uniform you can just assign to it:
|
149 |
|
150 | ```javascript
|
151 | shader.bind()
|
152 | shader.uniforms.scalar = 1.0
|
153 | ```
|
154 |
|
155 | While you can update vector uniforms by writing an array to them:
|
156 |
|
157 | ```javascript
|
158 | shader.uniforms.vector = [1,0,1,0]
|
159 | ```
|
160 |
|
161 | Matrix uniforms must have their arrays flattened first:
|
162 |
|
163 | ```javascript
|
164 | shader.uniforms.matrix = [ 1, 0, 1, 0,
|
165 | 0, 1, 0, 0,
|
166 | 0, 0, 1, 1,
|
167 | 0, 0, 0, 1 ]
|
168 | ```
|
169 |
|
170 | You can read the value of uniform too if the underlying shader is currently bound. For example,
|
171 |
|
172 | ```javascript
|
173 | shader.bind()
|
174 | console.log(shader.uniforms.scalar)
|
175 | console.log(shader.uniforms.vector)
|
176 | console.log(shader.uniforms.matrix)
|
177 | ```
|
178 |
|
179 | Struct uniforms can also be accessed using the normal dot property syntax:
|
180 |
|
181 | ```javascript
|
182 | shader.uniforms.light[0].color = [1, 0, 0, 1]
|
183 | ```
|
184 |
|
185 | It is also possible to initialize uniforms in bulk by assigning an object:
|
186 |
|
187 | ```javascript
|
188 | shader.uniforms = {
|
189 | model: [1, 0, 0, 0,
|
190 | 0, 1, 0, 0,
|
191 | 0, 0, 1, 0,
|
192 | 0, 0, 0, 1],
|
193 | color: [1, 0, 1, 1]
|
194 | }
|
195 | ```
|
196 |
|
197 | The contents of uniform values are lost when a shader is unbound.
|
198 |
|
199 | ### Attributes
|
200 |
|
201 | The basic idea behind the attribute interface is similar to that for uniforms, however because attributes can be either a constant value or get values from a vertex array they have a slightly more complicated interface. All of the attributes are stored in the `shader.attributes` property.
|
202 |
|
203 | #### `attrib = constant`
|
204 | For non-array attributes you can set the constant value to be broadcast across all vertices. For example, to set the vertex color of a shader to a constant you could do:
|
205 |
|
206 | ```javascript
|
207 | shader.attributes.color = [1, 0, 0, 1]
|
208 | ```
|
209 |
|
210 | This internally uses [`gl.vertexAttribnf`](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml). Setting the attribute will also call `gl.disableVertexAttribArray` on the attribute's location.
|
211 |
|
212 | #### `attrib.location`
|
213 | This property accesses the location of the attribute. You can assign/read from it to modify the location of the attribute. For example, you can update the location by doing:
|
214 |
|
215 | ```javascript
|
216 | attrib.location = 0
|
217 | ```
|
218 |
|
219 | Or you can read the currently bound location back by just accessing it:
|
220 |
|
221 | ```javascript
|
222 | console.log(attrib.location)
|
223 | ```
|
224 |
|
225 | **WARNING** Changing the attribute location requires recompiling the program. This recompilation is deferred until the next call to `.bind()`
|
226 |
|
227 | #### `attrib.pointer([type, normalized, stride, offset])`
|
228 | A shortcut for `gl.vertexAttribPointer`/`gl.enableVertexAttribArray`. See the [OpenGL man page for details on how this works](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttribPointer.xml). The main difference here is that the WebGL context, size and index are known and so these parameters are bound.
|
229 |
|
230 | * `type` is the type of the pointer (default `gl.FLOAT`)
|
231 | * `normalized` specifies whether fixed-point data values should be normalized (`true`) or converted directly as fixed-point values (`false`) when they are accessed. (Default `false`)
|
232 | * `stride` the byte offset between consecutive generic vertex attributes. (Default: `0`)
|
233 | * `offset` offset of the first element of the array in bytes. (Default `0`)
|
234 |
|
235 | #### Matrix attributes
|
236 |
|
237 | Matrix attributes are also supported, however there are a few subtle difference. Due to WebGL limitations, d-dimensional matrix attributes require d separate attribute locations. If `matrix` is a matrix attribute, then the rows of the matrix can be accessed independently using:
|
238 |
|
239 | ```javascript
|
240 | //First row of matrix
|
241 | shader.attributes.matrix[0]
|
242 |
|
243 | //Second row
|
244 | shader.attributes.matrix[1]
|
245 |
|
246 | // ... etc.
|
247 | ```
|
248 |
|
249 | The interface for these attributes is identical to the above interfaces for vector attributes (support constant setters, `.pointer()`, and `.location`).
|
250 |
|
251 | There is also a bulk interface which simplifies working with the matrix as a whole unit. For example, it is possible to update the location of each row of the matrix simultaneously by assigning it a vector value:
|
252 |
|
253 | ```javascript
|
254 | shader.attributes.matrix.location = [1, 2, 3, 4]
|
255 | ```
|
256 |
|
257 | Similarly, if the matrix attribute is stored as a contiguous range in memory, the pointer for each row can be set using `.pointer()`. For example, if `matrix` is a 4x4 matrix attribute then,
|
258 |
|
259 | ```javascript
|
260 | shader.attributes.matrix.pointer(gl.FLOAT, false, 16, 0)
|
261 | ```
|
262 |
|
263 | is equivalent to,
|
264 |
|
265 | ```javascript
|
266 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 0)
|
267 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 4)
|
268 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 8)
|
269 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 12)
|
270 | ```
|
271 |
|
272 | ### Reflection
|
273 |
|
274 | Finally, the library supports some reflection capabilities. The set of all uniforms and data types are stored in the "type" property of the shader object,
|
275 |
|
276 | ```javascript
|
277 | console.log(shader.types)
|
278 | ```
|
279 |
|
280 | This reflects the uniform and attribute parameters that were passed to the shader constructor.
|
281 |
|
282 | ## Acknowledgements
|
283 |
|
284 | (c) 2013-2015 Mikola Lysenko. MIT License
|