GithubHelp home page GithubHelp logo

regl's Introduction

๐Ÿ‘‘

regl

Fast functional WebGL

NPM Version Build Status File Size Downloads Standard

Example

regl simplifies WebGL programming by removing as much shared state as it can get away with. To do this, it replaces the WebGL API with two fundamental abstractions, resources and commands:

  • A resource is a handle to a GPU resident object, like a texture, FBO or buffer.
  • A command is a complete representation of the WebGL state required to perform some draw call.

To define a command you specify a mixture of static and dynamic data for the object. Once this is done, regl takes this description and then compiles it into optimized JavaScript code. For example, here is a simple regl program to draw a triangle:

// Calling the regl module with no arguments creates a full screen canvas and
// WebGL context, and then uses this context to initialize a new REGL instance
const regl = require('regl')()

// Calling regl() creates a new partially evaluated draw command
const drawTriangle = regl({

  // Shaders in regl are just strings.  You can use glslify or whatever you want
  // to define them.  No need to manually create shader objects.
  frag: `
    precision mediump float;
    uniform vec4 color;
    void main() {
      gl_FragColor = color;
    }`,

  vert: `
    precision mediump float;
    attribute vec2 position;
    void main() {
      gl_Position = vec4(position, 0, 1);
    }`,

  // Here we define the vertex attributes for the above shader
  attributes: {
    // regl.buffer creates a new array buffer object
    position: regl.buffer([
      [-2, -2],   // no need to flatten nested arrays, regl automatically
      [4, -2],    // unrolls them into a typedarray (default Float32)
      [4,  4]
    ])
    // regl automatically infers sane defaults for the vertex attribute pointers
  },

  uniforms: {
    // This defines the color of the triangle to be a dynamic variable
    color: regl.prop('color')
  },

  // This tells regl the number of vertices to draw in this command
  count: 3
})

// regl.frame() wraps requestAnimationFrame and also handles viewport changes
regl.frame(({time}) => {
  // clear contents of the drawing buffer
  regl.clear({
    color: [0, 0, 0, 0],
    depth: 1
  })

  // draw a triangle using the command defined above
  drawTriangle({
    color: [
      Math.cos(time * 0.001),
      Math.sin(time * 0.0008),
      Math.cos(time * 0.003),
      1
    ]
  })
})

See this example live

Check out the gallery. The source code of all the gallery examples can be found here.

Setup

regl has no dependencies, so setting it up is pretty easy. There are 3 basic ways to do this:

Live editing

To try out regl right away, you can use the live editor in the gallery.

npm

The easiest way to use regl in a project is via npm. Once you have node set up, you can install and use regl in your project using the following command:

npm i -S regl

For more info on how to use npm, check out the official docs.

If you are using npm, you may also want to try budo which is a live development server.

Run time error checking and browserify

By default if you compile regl with browserify then all error messages and run time checks are removed. This is done to reduce the size of the final bundle. If you are developing an application, you should run browserify using the --debug flag in order to enable error messages. This will also generate source maps which make reading the source code of your application easier.

Standalone script tag

You can also use regl as a standalone script if you are really stubborn. The most recent versions can be found in the dist/ folder and is also available from npm cdn in both minified and unminified versions.

There are some difference when using regl in standalone. Because script tags don't assume any sort of module system, the standalone scripts inject a global constructor function which is equivalent to the module.exports of regl:

<!DOCTYPE html>
<html>
  <head>
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
    <meta charset=utf-8>
  </head>
  <body>
  </body>
  <script language="javascript" src="https://npmcdn.com/regl/dist/regl.js"></script>
  <script language="javascript">
    var regl = createREGL()

    regl.frame(function () {
      regl.clear({
        color: [0, 0, 0, 1]
      })
    })
  </script>
</html>

Why regl

regl just removes shared state from WebGL. You can do anything you could in regular WebGL with little overhead and way less debugging. regl emphasizes the following values:

  • Simplicity The interface is concise and emphasizes separation of concerns. Removing shared state helps localize the effects and interactions of code, making it easier to reason about.
  • Correctness regl has more than 30,000 unit tests and above 95% code coverage. In development mode, regl performs strong validation and sanity checks on all input data to help you catch errors faster.
  • Performance regl uses dynamic code generation and partial evaluation to remove almost all overhead.
  • Minimalism regl just wraps WebGL. It is not a game engine and doesn't have opinions about scene graphs or vector math libraries. Any feature in WebGL is accessible, including advanced extensions like multiple render targets or instancing.
  • Stability regl takes interface compatibility and semantic versioning seriously, making it well suited for long lived applications that must be supported for months or years down the road. It also has no dependencies limiting exposure to risky or unplanned updates.

While regl is lower level than many 3D engines, code written in it tends to be highly compact and flexible. A comparison of regl to various other WebGL libraries across several tasks can be found here.

In order to prevent performance regressions, regl is continuously benchmarked. You can run benchmarks locally using npm run bench or check them out online. The results for the last few days can be found here.

These measurements were taken using our custom scripts bench-history and bench-graph. You can read more about them in the development guide.

Projects using regl

The following is an incomplete list of projects using regl:

If you have a project using regl that isn't on this list that you would like to see added, please send us a pull request!

regl is still under active developement, and anyone willing to contribute is very much welcome to do so. Right now, what we need the most is for people to write examples and demos with the framework. This will allow us to find bugs and deficiencies in the API. We have a list of examples we would like to be implemented here, but you are of course welcome to come up with your own examples. To add an example to our gallery of examples, please send us a pull request!

regl has extensive API documentation. You can browse the docs online here.

The latest changes in regl can be found in the CHANGELOG.

For info on how to build and test headless, see the contributing guide here

All code (c) 2016 MIT License

Development supported by the Freeman Lab and the Howard Hughes Medical Institute (@freeman-lab on GitHub)

Asset licenses

Many examples use creative commons or public domain artwork for illustrative purposes. These assets are not included in any of the redistributable packages of regl.

  • Peppers test image for cube comparison is public domain
  • Test video (doggie-chromakey.ogv) by L0ckergn0me, used under creative commons license
  • Cube maps (posx.jpeg, negx.jpeg, posy.jpeg, negy.jpeg, posz.jpeg, negz.jpeg) by Humus, used under creative commons 3 license
  • Environment map of Oregon (ogd-oregon-360.jpg) due to Max Ogden (@maxogd on GitHub)
  • DDS test images (alpine_cliff_a, alpine_cliff_a_norm, alpine_cliff_a_spec) taken from the CC0 license 0-AD texture pack by Wildfire games
  • Tile set for tile mapping demo (tiles.png) from CC0 licensed cobblestone paths pack
  • Audio track for audio.js example is "Bamboo Cactus" by 8bitpeoples. CC BY-ND-NC 1.0 license
  • Matcap (spheretexture.jpg) by Ben Simonds. CC 3 license.
  • Normal map (normaltexture.jpg) by rubberduck. CC0 license.

regl's People

Contributors

2xaa avatar ahaoboy avatar archmoj avatar ataber avatar benjamind avatar dy avatar erkaman avatar freeman-lab avatar fuzhenn avatar jpweeks avatar jwerle avatar kevzettler avatar maikeru avatar mathisonian avatar mdtusz avatar mikolalysenko avatar monfera avatar necolo avatar prinzhorn avatar rezmason avatar rich-harris avatar rreusser avatar s3ththompson avatar stojg avatar thammin avatar tomduncalf avatar unconed avatar vorg avatar willbamford avatar zzmp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

regl's Issues

The batch example is unbearable to look at.

In the batch example
http://regl.party/examples?batch

there are some triangles in the background that flashes so fast it is probably epilepsy inducing. It is impossible to read the code of that example, because you keep getting distracted by those accursed triangles.

I propose that you change the frequency that the triangles change their colors at.

if you modify this code

      Math.sin((0.1 + Math.sin(batchId)) * count + 3.0 * batchId),
      Math.cos(0.02 * count + 0.1 * batchId),
      Math.sin((0.3 + Math.cos(2.0 * batchId)) * count + 0.8 * batchId),

so that it becomes

    Math.sin( ((0.1 + Math.sin(batchId)) * count + 3.0 * batchId)*0.02 ),
      Math.cos( (0.02 * count + 0.1 * batchId)*0.02 ),
      Math.sin( ((0.3 + Math.cos(2.0 * batchId)) * count + 0.8 *batchId )*0.02 ),

the example is suddenly much more bearable to look at.

The dynamic demo suffers from the same problem:
http://regl.party/examples?dynamic
Also the lighting demo flashes at an ridiculous rate
http://regl.party/examples?lighting

So I would suggest that you do the same thing with them.

What do you think?

The examples dds, envmap, theta360, tile, and video don't work

When I load the example dds on http://regl.party , I just get a black black screen, and in the console it says


index.js:409XMLHttpRequest cannot load . Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.loadXHR @ index.js:409
index.js:409Uncaught TypeError: Cannot read property 'forEach' of undefinedloadXHR @ index.js:409
../../../../home/admin/browserify-cdn/node_modules/browserify/node_modules/browser-pack/_prelude.js:1Not allowed to load local resource: blob:http%3A//regl.party/0902f0ef-e9db-452d-a3e9-07b055d25bf0

The same thing happens for all the examples dds, envmap, theta360, tile, and video. I can't run them locally on my machine either. I just get the same error.

Getting canvas/context variables

Hi!

Is there a simple way to get canvas element or context, created by regl instance? E. g. if I want to pass viewport size or canvas size to fragment shader. I skimmed through API / created objects and did not find any related properties.

One of the ways seems to be passing a function to uniform

...
uniforms: {
    size: function (a,b,stats) {
        return [stats.width,stats.height];
    }
},
..

What are simpler ways for that? Creating and managing own canvas?

Thanks.

Code duplication in texture.js

Right now cube maps and 2d textures share a lot of common code. This should be abstracted out and reused to reduce code bloat.

The README needs to explicitly list selling points of the framework

(I'm just making this issue so that we don't forget about this.)

Right now, I feel that the README does a poor job of selling the framework to the possible user. I think it is necessary that we explicitly list some big selling points of the framework. Some selling points I came up with are:

  • regl greatly simplifies managing the state machine of WebGL
  • regl makes it easy to load extensions and to adapt the program after the limits of the target device
  • regl, in difference to many other WebGL frameworks, has support for easy usage of instanced rendering
  • regl integrates easily with modules from other frameworks, such as stack.gl.
  • regl is very small, and has very little bloat.
  • regl has much less overhead compared with other frameworks. It is near as fast as hand-optimized WebGL.
  • regl performs strong validation and error checking.

If you can come up with some more selling points, please tell me!

Can't resize a cubic framebuffer with `.resize()`

If you do the below, then an exception is thrown:

const regl = require('../regl')()
var cubeFbo = regl.framebufferCube(10)
cubeFbo.resize(8)

with the exception

check.js:21Error: (regl) framebuffer configuration not supported, status = incomplete attachment(โ€ฆ)raise @ check.js:21updateFramebuffer @ framebuffer.js:314resize @ framebuffer.js:634resize @ framebuffer.js:8161.../regl @ bug.js [sm]:4s @ _prelude.js:1e @ _prelude.js:1(anonymous function) @ _prelude.js:1
check.js:20Uncaught Error: (regl) framebuffer configuration not supported, status = incomplete attachment

but if you resize it like this, then no exception is thrown:

const regl = require('../regl')()
var cubeFbo = regl.framebufferCube(10)
cubeFbo({radius: 8})

Expose a mechanism for loading extensions and handling context creation failures

Right now context and canvas creation are rolled up into one big blob. regl also doesn't have any way of requiring certain extensions and instead just loads all of them opportunistically. All this needs to change before 1.0.0. A better system should have the following properties:

  • A mechanism to report errors during context creation
  • A way to specify some extensions which are required and some which are optional/opportunistically loaded

The relevant chunks of code are the context creation and loading routines here:

https://github.com/mikolalysenko/regl/blob/gh-pages/lib/webgl.js

And extension loading is all done here:

https://github.com/mikolalysenko/regl/blob/gh-pages/lib/extension.js

WebGL types naming conventions

Hi, I'm trying to port my PBR render from pex and I've found some inconsitiencies in how the WebGL enums are converted into strings:

UNSIGNED_SHORT = "uint8" why not "unsigned short"?
FLOAT = "float" why not "float32" then?
HALF_FLOAT = "half float" why not "float16" then?

DEPTH_STENCIL = "depth stencil"
DEPTH_COMPONENT = "depth" why not "depth component" then?

view-uniform can't be found when running from budo

None of the examples that uses view-uniforms seems to work anymore, when running from budo. If I for example run

budo example/camera.js -t glslify --live --open

I just get a black screen, and the error message

check.js:21Error: (regl) invalid uniform view in command
check.js:20Uncaught Error: (regl) invalid uniform view in command

the same thing happens in all the examples that uses a view-uniform. I used git-bisect to determine that the error was introduced in commit e930715 . But that makes no sense, because it only changes a string.

Anyways, If I here:

      check.optional(function () {
        function check (pred) {
          env.assert(scope, pred, 'invalid or missing uniform "' + name + '"')
        }

comment out the line

env.assert(scope, pred, 'invalid or missing uniform "' + name + '"')

All the examples work again.

If I build the gallery, then all the examples work. But from budo, they don't work. And since it takes forever to build the gallery, it would be really convenient if I could run them from budo.

Need to run unit tests for non-debug builds as well.

Right now, the unit tests are only run for the debug versions of the tests, that is, with all the checks.
But it would be good to also run the unit tests for non-debug versions of the tests, that is, without all the checks. Sometimes bugs can otherwise slip through, as was seen in PR #85.

Some unused code in `lib/dynamic.js`

I think that there may be some unused features in lib/dynamic.js

At this line here
https://github.com/mikolalysenko/regl/blob/gh-pages/lib/dynamic.js#L9

this.id = (VARIABLE_COUNTER++)
you declare an id for the dynamic variable. But as far as I can see, it is never used anywhere.

Also here https://github.com/mikolalysenko/regl/blob/gh-pages/lib/dynamic.js#L58


  switch (typeof data) {
    case 'boolean':
    case 'number':
    case 'string':
      return new DynamicVariable(type, toAccessorString(data + ''))

    case 'undefined':
      return new DynamicVariable(type | DYN_PENDING_FLAG, null)

    default:
      check.raise('invalid property type')
  }

But in the way that we use defineDynamic, I think that data is always a string. Because it is the string in the shortcuts like regl.prop('scale'). So why do you handle the cases boolean and number? Also, does the undefined case ever occur?

Also at https://github.com/mikolalysenko/regl/blob/gh-pages/lib/dynamic.js#L5

var DYN_FUNC = 0
var DYN_PENDING_FLAG = 128

and at https://github.com/mikolalysenko/regl/blob/gh-pages/regl.js#L30 we have

var DYN_PROP = 1
var DYN_CONTEXT = 2
var DYN_STATE = 3

shouldn't all these five be in one single place? Why are you splitting them up?

`destroy` is never called for `elements`

The elements buffers are never destroyed. There is a method

    reglElements.destroy = function () {
      stats.elementsCount--

      check(elements.buffer !== null, 'must not double destroy elements')
      buffer.destroy()
      elements.buffer = null
    }

in lib/elements.js, but it is never ever called. But it should probably be called somewhere, so that we can clean up after the elements buffers

More examples!

regl is starting to get to a somewhat stable point where we can begin building examples with it. Having more examples is crucial for vetting the API and ferreting out edge cases/bugs that might be lurking in the API.

Anyone can submit an example as a pull request, and to do so all that is required is to fork this repo and then add the necessary file into the examples/ folder.

Passing array straight to attributes

Hi @mikolalysenko!

Currently we are forced to pass buffer instance to attributes:

return regl({
    vert: `
    precision highp float;
    attribute vec2 position;
    void main() {
        gl_Position = vec4(position, 0, 1);
    }
    `,

    frag: `
    precision highp float;
    void main () {
        gl_FragColor = vec4(0,0,0, 1);
    }
    `,

    attributes: {
        position: regl.buffre([-1,-1, -1,3, 3,-1])
    },

    count: 3
});

Wouldnโ€™t it be easier to be able to pass just an array to attributes property? Not a big trouble, but still a bit more easier to remember, especially for the users who are not into webgl terminology.

That is mentioned in API, but the chunk with plain array instead of buffer does not render anything.

Incomplete docs for framebuffers

The docs for framebuffer are incomplete. In the docs, there is a table

Color type Description
'uint8' gl.UNSIGNED_BYTE
'half float' 16 bit float, requires
'float' 32 bit float`

The part 16 bit float, requires is incomplete.

Fix rounding issues in viewport rendering

We should force all examples to use a power-of-2 sized viewport and to implement correct rounding. The current set up using 5x5 viewports is fragile and fails on some computers. The following formula is correct and works whenever the shape of the viewport is 2^n -by- 2^n:

vec4 pixelToClip(vec2 pixel, vec2 shape){
   return vec4(2.0 * (pixel + 0.5) / shape - 1.0, 0, 1)
}

Memory leak if attribute is a `regl.prop`, where `regl.prop` is an array

If some attribute is set to be regl.prop, where regl.prop is an array, we have a memory leak. Minimal example below:

const regl = require('../regl')()

const draw = regl({
  frag: `
  precision mediump float;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }`,

  vert: `
  precision mediump float;
  attribute vec2 position;
  uniform float angle;
  void main() {
    gl_Position = vec4(
      cos(angle) * position.x + sin(angle) * position.y,
        -sin(angle) * position.x + cos(angle) * position.y, 0, 1);
  }`,

  attributes: {
    position: regl.prop('position')
  },

  uniforms: {
    angle: ({tick}) => 0.01 * tick
  },

  depth: {
    enable: false
  },

  count: 3
})

regl.frame(({tick}) => {
  regl.clear({
    color: [0, 0, 0, 1]
  })

  draw({
    position: [-1, 0, 0, -1, 1, 1]
  })
})

run the above program, and put a console.log here
https://github.com/mikolalysenko/regl/blob/gh-pages/lib/buffer.js#L88

you will see that it goes into this branch every single frame, meaning that we are creating a GL-buffer every frame. Instead, the buffer should be put into a pool.

The issue is that this createStream-call:
https://github.com/mikolalysenko/regl/blob/gh-pages/lib/core.js#L1787

doesn't have a corresponding destroyStream-call anywhere.

Updating textures data

Hi!

There is another concern I canโ€™t resolve.
What is the designed way to update textureโ€™s data?
The test is not complete yet, and docs do not cover that case yet.

Should I return texture instance each time in dynamic uniform, like that:

uniforms: {
  image: function () {
    return regl.texture(src);
  }
}

Or I can save reference to created texture and modify it in some fashion?

Thanks!

More test cases!

This is an ongoing process, but the test coverage is still not 100% in regl. Some parts are pretty good (like basic rendering and buffer uploads), but other parts need more work. In no particular order, we need to vet the following subsystems:

  • Textures (specifically the constructor and multitexturing with many uniforms)
  • Instanced rendering
  • Rendering across different extension configurations
  • Compressed textures
  • Constant vertex attributes
  • Frame buffer objects

To help discover new things to test there is a code coverage reporting system set up. To access it, use the command:

npm run cover

And then open up the results in coverage/lcov-report/index.html.

All of the test cases are written using tape. For more info on how to write test cases, check out the development guide.

Test cases and examples for instancing

We don't have any test cases for instancing yet. The feature is implemented and based on some early experiments it seems to work, but we need some unit tests to make sure that everything is sane and all the edge cases are covered.

Finish up framebuffer objects

There are lots of gaps in the framebuffer object API which we need to fill in. Also the constructor is currently untested and allocates a bunch of garbage. The following needs to happen before we release 1.0:

  • We need complete test coverage for framebuffer objects and all code generation pathways associated to them
  • There should be a method for quickly resizing or updating a framebuffer. Calling it repeatedly should have no effect.
  • We need maybe 1-2 more good examples showing different uses of framebuffers

`cube.resize` method has strange parameters

The method cube.resize method has the parameters:

    function resize (w_, h_) {

but it is a cube, so we must always have w_ === h_, so a better parameter would be something like radius.

Also, we need to document cube.resize in API.md

Cube Fbos need test cases

The API for Cube Fbos is pretty much done. All that is remaining now is writing test cases for them.

Allow for dynamic properties in nested attributes/gl state

At the moment regl doesn't allow for dynamic properties in nested structures like attributes or some state descriptions (for example, blendFunc). It would be nice though to be able to write stuff like this:

const command = regl({
   attributes: {
    foo: {
      buffer: regl.prop('bar'),
      offset: 0,
      stride: 8
    }
   }
})

Performance metrics

When optimizing WebGL applications it is useful to keep track of how many resources are occupied. We can do this right now with regl and it expose it to the user transparently. Some possible stats that we could track:

  • Total number of resources (buffers, elements, textures, etc.) which are allocated
  • Total GPU memory allocated to each resource type
  • Last frame time, maybe average frametime or some histogram of times
  • Per-command stats, like execution time, number of vertices drawn, number of texture units, number of attributes used, number of uniforms, etc.

We should also have some infrastructure to take advantage of the disjoint timer query extension within a draw command and use this to report stats.

The depth test does not work for FBOs

If you render a scene to an FBO, the depth test does not seem to work. See this example:

const canvas = document.body.appendChild(document.createElement('canvas'))
const fit = require('canvas-fit')
const regl = require('../regl')(canvas)
const mat4 = require('gl-mat4')
const camera = require('canvas-orbit-camera')(canvas)
window.addEventListener('resize', fit(canvas), false)
const bunny = require('bunny')
const normals = require('angle-normals')

// configure intial camera view.
camera.rotate([0.0, 0.0], [0.0, -0.4])
camera.zoom(300.0)

// create fbo.
const fbo = regl.framebuffer({
  colorBuffer: regl.texture({
    width: 512,
    height: 512,
    wrap: 'clamp'
  }),
  depth: true
})

/*
  configure default state.  draw to fbo.
*/
const setupDefault = regl({
  cull: {
    enable: true
  },
  uniforms: {
    // View Projection matrices.
    view: () => camera.view(),
    projection: ({viewportWidth, viewportHeight}) =>
      mat4.perspective([],
                       Math.PI / 4,
                       viewportWidth / viewportHeight,
                       0.01,
                       3000),

    // light settings. These can of course by tweaked to your likings.
    lightDir: [0.39, 0.87, 0.29],
    ambientLightAmount: 0.3,
    diffuseLightAmount: 0.7
  },
  framebuffer: fbo
})


const drawBunny = regl({
  frag: `
  precision mediump float;
  varying vec3 vNormal;
  uniform vec3 lightDir;
  uniform vec3 color;
  uniform float ambientLightAmount;
  uniform float diffuseLightAmount;
  void main () {
    vec3 ambient = ambientLightAmount * color;
    vec3 diffuse = diffuseLightAmount * color * clamp( dot(vNormal, lightDir ), 0.0, 1.0 );
    gl_FragColor = vec4(ambient + diffuse, 1.0);
  }`,
  vert: `
  precision mediump float;
  attribute vec3 position;
  attribute vec3 normal;
  varying vec3 vNormal;
  uniform mat4 projection, model, view;
  void main () {
    vNormal = normal;
    gl_Position = projection * view * model * vec4(position, 1.0);
  }`,
  attributes: {
    position: bunny.positions,
    normal: normals(bunny.cells, bunny.positions)
  },
  elements: bunny.cells,
  uniforms: {
    model: (_, props, batchId) => {
      var m = mat4.identity([])

      mat4.translate(m, m, props.position)

      var s = props.scale
      mat4.scale(m, m, [s, s, s])

      var r = props.rotation
      mat4.rotateX(m, m, r[0])
      mat4.rotateY(m, m, r[1])
      mat4.rotateZ(m, m, r[2])

      return m
    },
    color: regl.prop('color')
  }
})

// draw the contents of the fbo to the screen.
const drawQuad = regl({
  frag: `
  precision mediump float;
  varying vec2 uv;
  uniform sampler2D tex;
  void main() {
    gl_FragColor = vec4(texture2D(tex, uv).xyz, 1);
  }`,

  vert: `
  precision mediump float;
  attribute vec2 position;
  varying vec2 uv;
  void main() {
    uv = 0.5 * (position + 1.0);
    gl_Position = vec4(position, 0, 1);
  }`,
  attributes: {
    position: [ -4, -4, 4, -4, 0, 4 ]
  },
  uniforms: {
    tex: ({count}) => fbo.color[0]
  },
  depth: { enable: false },
  count: 3
})

regl.frame(({viewportWidth, viewportHeight, deltaTime}) => {

  // render to fbo.
  setupDefault({}, () => {
    regl.clear({
      color: [0, 0, 0, 255],
      depth: 1
    })
    drawBunny([
      {color: [0.6, 0.2, 0.5], scale: 5.2, position: [30.0, -65.0, -80.0], rotation: [-0.5, 0.0, 0.0]},
      {color: [0.3, 0.5, 0.5], scale: 4.1, position: [-50.0, -70.0, -60.0], rotation: [0.7, -0.0, 0.0]},
    ])
  })

  regl.clear({
    color: [0, 0, 0, 255],
    depth: 1
  })
  // now render fbo to quad.
  drawQuad()

  camera.tick()
})

rendering to depth buffer was enabled for the FBO, yet if you render the FBO to a quad, you can see that the depth testing does not work for the bunnies.

WebVR

It is still early, but eventually regl ought to have support for WebVR. This might require modifying the way viewports and context variables are initialized as well as how we interact with requestAnimationFrame().

The current draft API is here, though it is unclear how stable it is yet:

https://w3c.github.io/webvr/

Given that VR isn't a standard yet it probably isn't worth adding VR features into regl for a 1.0.0 release, though we should make sure that whatever APIs we expose don't make it unduly difficult to write WebVR code.

A good way to make sure that things aren't screwed up would be to write a WebVR example using regl and make sure that everything works ok.

`life` example is broken

The life example seems to have broken with the texture rewrite. If I run the example with budo, I get the error

check.js:21Error: (regl) invalid regl object for attachment(โ€ฆ)

the life demo in the gallery also does not work. It seems the issue is that you can't use regl.texture as an attachment to regl.framebuffer.

Context loss

Currently there is some preliminary infrastructure for handling context loss, but it isn't well tested yet and probably doesn't work.

In order to handle context loss events, regl should mirror the state of textures and buffers so that when the context is restored after a loss the state can be updated. However doing this does increase the overhead of each buffer object so it should be something that users can opt-out of if they do not need this feature.

There should also be some event hook on context loss and restore so that users can implement their own policies for restoring GPU resident resources like framebuffer objects.

We need to call `generateMipmap` in `texture.resize`

If a texture uses a mipmap, and we resize it through texture.resize, then the old mipmap will become invalid. I think. So we need to regenerate it by calling gl.generateMipmap again, which we are currently not doing in texture.resize. Otherwise, the resized texture will be using the old mipmap, which is weird.

The gallery should be redesigned.

Right now, the gallery is freaking fugly:

screen shot 2016-07-25 at 18 14 50

The gallery needs a better design(simply choosing better font and formatting will do wonders), and every entry should have an accompanying image, or even better, a video(I have already recorded a couple already, like here and here). A video or an image is important, since due to extension loading issues, the user may be unable to view the example. For those cases, providing an image or a video is much better than nothing.

Remove DDS parsing

Following the discussion from #12, DDS parsing should be removed from the core library to prevent scope creep and to keep things simple.

dynamic viewports and scissors do not allow negative x- and y-values

In the viewport and scissors parsing of the code generator, for dynamic you do a check for negative x- and y-values
https://github.com/mikolalysenko/regl/blob/gh-pages/lib/core.js#L653

          check.optional(function () {
            env.assert(scope,
              BOX_X + '>=0&&' +
              BOX_Y + '>=0&&' +
              BOX_W + '>0&&' +
              BOX_H + '>0',
              'invalid ' + param)
          })

but you do not do the corresponding check for static. You only do this:

https://github.com/mikolalysenko/regl/blob/gh-pages/lib/core.js#L600

        var x = box.x | 0
        var y = box.y | 0

so you do not check for negative x- and y-values for static. This is weird and inconsistent, and should be looked over.

Also, you do not seem to have any test cases for viewports with negative x- and y-values. That's probably why the above bug slipped through.

Size optimization

regl is starting to get a little fat. It is probably worth it to do an audit of the minified code and optimize things.

Some ideas:

  • Replace inline strings with shared variables to reduce duplication.
  • Factor out more common functionality.
  • Try to get regl to compiling with closure compiler's advanced type annotations.

You should not be able to create an FBO where the render targets have different bitplanes

To quote this document:

ES 2.0 requires that all color buffers attached to application-
created framebuffer objects must have the same number of bitplanes
(Chapter 4 overview p91). ES 2.0 also requires that all attached images
have the same width and height (Section 4.4.5 Framebuffer Completeness).

Thus, since WebGL is based on GLES, we have that we cannot create an FBO where the render targets have differing bitplanes. So an FBO with three render targets with bitplanes of uint32, float, float is completely fine. However, something like uint8, float, float will be rejected by the driver.

So we need to add some validation logic that prevents us from creating an FBO with render targets that have differing bitplanes.

Scope + uniforms

Liking regl so far! Scopes required just a bit of thought. Quick question on how scopes and uniforms work together. This works:

var draw = regl({
  // uses offset uniform
  uniforms: {offset: regl.prop('offset')}
});

draw({offset: 1});

And this works:

var draw = regl({
  // uses offset uniform
});

draw(function () {
  regl({uniforms: {offset: 1}})()
});

But this does not:

var draw = regl({
  // cannot use offset uniform
  uniforms: {offset: regl.prop('offset')}
});

draw(function () {
  regl({offset: 1})();
])

This is likely no accident, but it caught me off guard at first. Just curious whether that's necessary by design or just an unimplemented feature.

Cross browser testing

We need to run regl on some non-v8/ANGLE based systems to make sure everything is still working. At least the following systems should all pass:

  • Firefox (Windows/OS X/ Linux)
  • Safari
  • iOS
  • Android

Maybe browserling would work?

Specify color attachments for `gl.read()`

If you are using MRT, you can by using gl.readBuffer(src) specify which color attachment gl.readPixels. will read from. So we could use this to specify which color attachment regl.read should read from.

Although it seems to be a WebGL2.0 feature. If we can't use it, we can probably get around it by using glGetTexImageโ€‹ to read from the color attachment texture instead.

This may be a feature we should consider adding.

Links to API docs are borked on www.npmjs.com

Links to the API docs on npmjs.com point to urls such as https://github.com/mikolalysenko/regl/blob/master/API.md#textures which results in 404s. Actual URLs should be of the form https://github.com/mikolalysenko/regl/blob/gh-pages/API.md#textures.

Benchmark suite and dash board

There is a fairly rudimentary benchmark suite for regl, but it doesn't measure much yet. What exists now is right here:

https://github.com/mikolalysenko/regl/tree/gh-pages/bench

It would be extremely awesome to get this system working more reliably so that we could measure how much overhead each regl command has. Writing good benchmarks in JavaScript is really hard, especially for a complex system like regl. To get a good handle on this we probably need to create some more complicated examples with regl and then plug them into the benchmark harness to record statistics information.

Long term, it would also be cool to have this plug into some big dashboard and to track stats over time so we could make sure that things keep improving performance-wise instead of hitting regressions.

subdata doesn't seem to handle an array of typed arrays.

The method subdata does not seem to handle arrays of typed arrays. If I pass subdata() an array of the form [[Float32Array[3], Float32Array[3], Float32Array[3],...], nothing gets rendered at all. See the below minimal example:

const canvas = document.body.appendChild(document.createElement('canvas'))
const fit = require('canvas-fit')
const regl = require('../regl')(canvas)
const mat4 = require('gl-mat4')
const camera = require('canvas-orbit-camera')(canvas)
window.addEventListener('resize', fit(canvas), false)
const vec3 = require('gl-vec3')

// configure intial camera view.
camera.rotate([0.0, 0.0], [0.0, -0.4])
camera.zoom(-10.0)

// geometry arrays.
const elements = []
var position = []

const N = 10 // num quads of the plane
// create plane vertices
var row
var col
for (row = 0; row <= N; ++row) {
  var z = (row / N) * (8) + -4
  for (col = 0; col <= N; ++col) {
    var x = (col / N) * (8) + -4

    // THE IMPORTANT PART IS BELOW
    //
   //
   //

    // this works!
    position.push(  [x, 0.0, z]  );   

    // but this doesn't work
    //    position.push( vec3.fromValues(x, 0.0, z));

  }
}

const positionBuffer = regl.buffer({
  length: position.length * 3 * 4,
  type: 'float',
  usage: 'dynamic'
})

// create plane faces.
for (row = 0; row <= (N - 1); ++row) {
  for (col = 0; col <= (N - 1); ++col) {
    var i = row * (N + 1) + col

    var i0 = i + 0
    var i1 = i + 1
    var i2 = i + (N + 1) + 0
    var i3 = i + (N + 1) + 1

    elements.push([i3, i1, i0])
    elements.push([i0, i2, i3])
  }
}

const drawPlane = regl({
  context: {
    view: () => camera.view()
  },
  frag: `
  precision mediump float;
  varying vec3 vPosition;
  void main () {
    gl_FragColor = vec4(vPosition.xyz, 1.0);
  }`,

  vert: `
  precision mediump float;

  attribute vec3 position;
  uniform mat4 projection, view;
  varying vec3 vPosition;
  void main() {
    vPosition = position;
    gl_Position = projection * view * vec4(position, 1);
  }`,

  uniforms: {
    view: regl.context('view'),
    projection: ({viewportWidth, viewportHeight}) =>
      mat4.perspective([],
                       Math.PI / 4,
                       viewportWidth / viewportHeight,
                       0.01,
                       1000)
  },
  attributes: {
    position: {
      buffer: positionBuffer,
      normalized: true
    },
  },
  elements: regl.prop('elements')
})

regl.frame(({deltaTime}) => {
  regl.clear({
    color: [0, 0, 0, 255],
    depth: 1
  })
  positionBuffer.subdata(position)
  drawPlane({elements})
  camera.tick()
})

Now notice that if I push normal arrays to position like this:

    position.push(  [x, 0.0, z]  );

then it works, and I am able to render a plane

screen shot 2016-07-01 at 09 34 32

But if I change that line to

    //    position.push( vec3.fromValues(x, 0.0, z));

I just get a black screen. And that is because gl-vec3 creates the vectors as Float32Array[3].
And it would be very nice if I could pass an array of the form [[Float32Array[3], Float32Array[3], Float32Array[3],...] to subdata, because then I could use the methods from gl-vec3 directly on the vertices in the array position.

But note that you can mostly work around this issue. You can actually just store the vectors as normal arrays [] in position, and then use the functions from gl-vec3 on those arrays. However, you have to be careful, because you can't use fromValues, clone, create, or clone, because these all return a typed array Float32Array[3]. So if you want to clone a vector, you'll have to do

var clonedVector = [v[0], v[1], v[2]]

which is a bit annoying. So it would be great if you could pass an array [[Float32Array[3], Float32Array[3], Float32Array[3],...] to subdata. It may also be that the other buffer methods also don't handle this special case.

And it may be that you don't support this by design? If that is the case, you should probably explicitly write that in the documentation...

regl.read() returns uint8 array instead of the fbo/texture type of float

See the console output, it should be an array of floats in range [0,1], specifically an array of all 1s, instead it is an array of all 255 uints.



const image_data = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAACXBIWXMAAABIAAAASABGyWs+AAAA1UlEQVRIx91W0RLDIAgj3P7/l9mDO6ooVifcbuURNWlSTwIRobsCMOyvnH2t4Ho41QaXCcO1cnLh+3S/S8Pn6Lp56KRVAGALupdiALldPkIvUoyOi+AcfcjBih6A3ZphFfh3kYbsXt9A8dwchTBYXr83iim58gmiLk9fxaVfW6TijEqv39f2s7NVwBNu0f8TiEj0Q/epMhseYBERZbiks7OeaJHojQJai1A0HTKmFLCeaDFGmWDR/ORzjj622OgoIl8EL/LDXXp0xCy33offS7cLkh3f34rheTjlbIAQAAAARHpUWHRDb21tZW50AAB42nNNySxJTVFIqlQISCzNUQjOSC3KTcxTSMsvUggPcM7JLEgsKtFRCChNyslMVnDJz03MzAMA0cYSC/gtqgsAAAAASUVORK5CYII=`;
const resl = require('resl');
const regl = require('regl')({
  extensions: ['OES_texture_float', 'OES_texture_float_linear']
});

const quadVerts = [
  [-1.0, -1.0, 0.0], [-1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [1.0, 1.0, 0.0]
];

const quadIndices = [
  [3, 1, 0], [0, 2, 3]
];


resl({
  manifest: {
    texture: {
      type: 'image',
      src: image_data,
      parser: (data) => regl.texture({
        data: data,
        mag: 'nearest',
        min: 'nearest'
      })
    }
  },
  onDone: ({}) => {
    let fbo = regl.framebuffer({
                color: regl.texture({
                  width: 32,
                  height: 32,
                  stencil: false,
                  format: 'rgba',
                  type: 'float',
                  depth: false,
                  wrap: 'clamp'
                })
              });

    const renderToFBO = regl({
      frag: `
        precision mediump float;
        varying vec2 vUv;
        void main () {
          gl_FragColor = vec4(1,1,1,1);
        }
      `,
      vert: `
        precision mediump float;
        attribute vec3 position;
        varying vec2 vUv;

        void main() {
          vUv = (position.xy + 1.0)/2.0;
          gl_Position = vec4(position, 1);
        }
      `,
      attributes: {
        position: quadVerts
      },
      elements: quadIndices,
      uniforms: {
      },
      framebuffer: regl.prop('fbo')
    });

    renderToFBO({fbo: fbo});

    var bindFBO = regl({framebuffer: fbo});   bindFBO(() => {
      console.log(regl.read());
    });


  }
});

We need to validate compressed textures.

There are restrictions on compressed textures, and right now, it seems that our validation code is not taking these restrictions into account. For example, for COMPRESSED_RGB_S3TC_DXT1_EXT we have that.

The byteLength of the ArrayBufferView, pixels, passed to either compressedTexImage2D or compressedTexSubImage2D must match the following equation:

floor((width + 3) / 4) * floor((height + 3) / 4) * 8
If it is not an INVALID_VALUE error is generated.

When level equals zero width and height must be a multiple of 4. When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.

If they are not an INVALID_OPERATION error is generated.

For compressedTexSubImage2D xoffset and yoffset must be a multiple of 4 and width must be a multiple of 4 or equal to the original width of the level. height must be a multiple of 4 or equal to the original height of the level. If they are not an INVALID_OPERATION error is generated.

So if the equation floor((width + 3) / 4) * floor((height + 3) / 4) * 8 is not satisfied, then the compressed texture is simply not valid. The user has to manually add padding data.

Anyways, it appears that all the compressed texture formats have these kinds of restrictions to them. So we probably need to validate them somewhere.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.