├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── index.frag ├── index.js ├── index.vert ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | bundle.js 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | bundle.js 5 | test 6 | test.js 7 | demo 8 | example 9 | .npmignore -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright (c) 2014 [stackgl](http://github.com/stackgl/) contributors 5 | 6 | *stackgl contributors listed at * 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gl-texture2d-read-float 2 | 3 | [![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges) 4 | 5 | Read out the contents of a floating-point 6 | [gl-texture2d](http://github.com/stackgl/gl-texture2d). 7 | 8 | This will *eventually* be supported natively in WebGL 9 | [(it's listed in the OpenGL ES 3 spec)](https://www.khronos.org/opengles/sdk/docs/man31/html/glReadPixels.xhtml), 10 | but this fills that need until then! 11 | 12 | ## Usage 13 | 14 | [![NPM](https://nodei.co/npm/gl-texture2d-read-float.png)](https://nodei.co/npm/gl-texture2d-read-float/) 15 | 16 | ### `read(glTex2d, done(err, data))` 17 | 18 | Reads out the contents of `glTex2d`, which should be an instance of 19 | `gl-texture2d`. When complete, `done(err, data)` will be called where `data` is 20 | a `Float32Array` containing the resulting floats in the texture. 21 | 22 | ``` javascript 23 | const canvas = document.createElement('canvas') 24 | const gl = require('gl-context')(canvas) 25 | 26 | const read = require('gl-texture2d-read-float') 27 | const Texture2d = require('gl-texture2d') 28 | const baboon = require('baboon-image') 29 | const assert = require('assert') 30 | 31 | const texture = Texture2d(gl, baboon) 32 | 33 | read(texture, function(err, data) { 34 | if (err) throw err 35 | 36 | assert.deepEqual(data, baboon.data) 37 | }) 38 | ``` 39 | 40 | A few things to note: 41 | 42 | * Right now, this is slow as it requires reading data back from the GPU. 43 | There's not much that can be done about this for the time being unfortunately. 44 | * The data is retrieved synchronously under the hood, but the API has been made 45 | asynchronous in preparation for WebGL's eventual async `readPixels` equivalent. 46 | * Only `gl.RGBA`/`gl.FLOAT` textures are currently supported. Pull requests are, 47 | however, very welcome! :) 48 | 49 | ## Contributing 50 | 51 | See [stackgl/contributing](https://github.com/stackgl/contributing) for details. 52 | 53 | ## License 54 | 55 | MIT. See [LICENSE.md](http://github.com/stackgl/gl-texture2d-read-float/blob/master/LICENSE.md) for details. 56 | -------------------------------------------------------------------------------- /index.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform sampler2D data; 4 | uniform vec2 size; 5 | 6 | #pragma glslify: encode = require('glsl-read-float') 7 | 8 | void main() { 9 | vec2 uv = gl_FragCoord.xy / size; 10 | float value = texture2D(data, uv)[CHANNEL]; 11 | 12 | gl_FragColor = vec4(encode(value)); 13 | } 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var readFloat = require('glsl-read-float') 2 | var triangle = require('a-big-triangle') 3 | var Symbol = require('es6-symbol') 4 | var Shader = require('gl-shader') 5 | var glslify = require('glslify') 6 | var createFBO = require('gl-fbo') 7 | 8 | var SHADERS = Symbol('gl-texture2d-read-float:shader') 9 | var FBO = Symbol('gl-texture2d-read-float:fbo') 10 | 11 | module.exports = function(texture, done) { 12 | var gl = texture.gl 13 | var width = texture.shape[0] 14 | var height = texture.shape[1] 15 | var viewport = gl.getParameter(gl.VIEWPORT) 16 | var fbo = gl.getParameter(gl.FRAMEBUFFER_BINDING) 17 | var rbo = gl.getParameter(gl.RENDERBUFFER_BINDING) 18 | var tex = gl.getParameter(gl.TEXTURE_BINDING_2D) 19 | var prog = gl.getParameter(gl.CURRENT_PROGRAM) 20 | 21 | gl.viewport(0, 0, width, height) 22 | gl[FBO] = gl[FBO] || createFBO(gl, [1, 1], { float: true }) 23 | gl[SHADERS] = gl[SHADERS] || [0, 1, 2, 3].map(function(n) { 24 | return Shader(gl 25 | , '#define CHANNEL ' + n + '\n' + glslify('./index.vert') 26 | , '#define CHANNEL ' + n + '\n' + glslify('./index.frag') 27 | ) 28 | }) 29 | 30 | var output = new Float32Array(width * height * 4) 31 | var fbdump = new Uint8Array(width * height * 4) 32 | var buffer = gl[FBO] 33 | 34 | buffer.shape = [width, height] 35 | buffer.bind() 36 | 37 | for (var channel = 0; channel < 4; channel++) { 38 | var shader = gl[SHADERS][channel] 39 | 40 | shader.bind() 41 | shader.uniforms.data = texture.bind(0) 42 | shader.uniforms.size = [width, height] 43 | triangle(gl) 44 | 45 | gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, fbdump) 46 | 47 | for (var j = 0, x = 0, n = channel; x < width; x++) 48 | for (var y = 0; y < height; y++, n += 4) { 49 | output[n] = readFloat(fbdump[j++], fbdump[j++], fbdump[j++], fbdump[j++]) 50 | } 51 | } 52 | 53 | gl.viewport(viewport[0], viewport[1], viewport[2], viewport[3]) 54 | gl.bindFramebuffer(gl.FRAMEBUFFER, fbo) 55 | gl.bindRenderbuffer(gl.RENDERBUFFER, rbo) 56 | gl.bindTexture(gl.TEXTURE_2D, tex) 57 | gl.useProgram(prog) 58 | 59 | setTimeout(function() { 60 | done(null, output) 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /index.vert: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | attribute vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 1, 1); 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gl-texture2d-read-float", 3 | "version": "1.0.1", 4 | "description": "Read out the contents of a floating-point gl-texture2d", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "browserify": { 8 | "transform": [ 9 | "glslify" 10 | ] 11 | }, 12 | "scripts": { 13 | "test": "browserify test.js | tap-closer | smokestack | tap-spec", 14 | "hihat": "hihat test.js -p tap-dev-tool" 15 | }, 16 | "author": { 17 | "name": "Hugh Kennedy", 18 | "email": "hughskennedy@gmail.com", 19 | "url": "http://hughsk.io/" 20 | }, 21 | "dependencies": { 22 | "a-big-triangle": "^1.0.2", 23 | "es6-symbol": "^2.0.1", 24 | "gl-fbo": "^2.0.5", 25 | "gl-shader": "^4.0.4", 26 | "glsl-read-float": "^1.1.0", 27 | "glslify": "^2.1.2" 28 | }, 29 | "devDependencies": { 30 | "browserify": "^10.2.4", 31 | "gl-texture2d": "^2.0.9", 32 | "hihat": "0.0.8", 33 | "ndarray": "^1.0.18", 34 | "smokestack": "^3.3.0", 35 | "tap-closer": "^1.0.0", 36 | "tap-dev-tool": "^1.2.0", 37 | "tap-spec": "^4.0.0", 38 | "tape": "^4.0.0" 39 | }, 40 | "repository": { 41 | "type": "git", 42 | "url": "git://github.com/stackgl/gl-texture2d-read-float.git" 43 | }, 44 | "keywords": [ 45 | "ecosystem:stackgl" 46 | ], 47 | "homepage": "https://github.com/stackgl/gl-texture2d-read-float", 48 | "bugs": { 49 | "url": "https://github.com/stackgl/gl-texture2d-read-float/issues" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const Texture = require('gl-texture2d') 2 | const ndarray = require('ndarray') 3 | const test = require('tape') 4 | const read = require('./') 5 | 6 | test('gl-texture2d-read-float', function(t) { 7 | const canvas = document.body.appendChild(document.createElement('canvas')) 8 | const gl = canvas.getContext('webgl') 9 | const data = new Float32Array([0, 1.2, 2.4, 3.6, 4, 5, 6, 7]) 10 | const stride1 = [2, 1, 4] 11 | const stride2 = [1, 2, 4] 12 | 13 | const tex1 = Texture(gl, ndarray(data, stride1), { float: true }) 14 | const tex2 = Texture(gl, ndarray(data, stride2), { float: true }) 15 | 16 | t.plan(4) 17 | 18 | read(tex1, function(err, res) { 19 | t.ifError(err, 'ran without error') 20 | t.deepEqual(res, data, 'RGBA: data returned is equivalent to what was passed in') 21 | }) 22 | 23 | read(tex2, function(err, res) { 24 | t.ifError(err, 'ran without error') 25 | t.deepEqual(res, data, 'RGBA: data returned is equivalent to what was passed in') 26 | }) 27 | }) 28 | --------------------------------------------------------------------------------