Three.JS and WebGL Experiment Platform

If you do not play and do not consider photos of girls you know in contact, then programming is my favorite pastime at the computer. I especially like “fast” programming. This is programming when the project is small and when we are not doing basic research, and planning does not need documentation. By the way, at work, all projects are not like that, and even focused on a closed audience. This is mainly why you are reading my article now, and I also want to get to Habr.

I want to share with you the results of my weekend project. This is a pure client javascript / html application, which consists of a source editor in Javascript and GLSL -shaders, mini-linker, windows with Three.JS / WebGL and a small runtime interface. All this is glued to jquery, and a video gallery is screwed on top. The gallery features several demonstrations. You can select your favorite demo and play with its code, as well as export and import entire projects from several files via JSON.

The code for each demo can be located in several files. These files are loaded by ajax and are immediately stored in local storage where they can be edited, added new and deleted. I repeat, the application is purely client. To add files to local storage, use the file api. You can add only text files, because with the volume of local storage you can’t get around when storing base64 representations of binary files.

I will not give a link to a working application, because I do not have my normal hosting. All that remains is to download the sources and place them on your web server. A web server is still needed, because recently WebGL has been forbidden to download textures from the local file system.

All sources are available on Bitbucket in the Mercurial system: https://bitbucket.org/Bangybug/treejsplayground , there is also the opportunity to download the Zip archive.

There is still a small video to interest you:

If you are interested and decide to download the source, then I consider it a duty to warn that it works only on Chrome normally (I have 21.0.1180.60). In Firefox (I have 14.0.1), WebGL is now disabled, and to enable it, you will need to type about: config in the address bar, then set the filter on webgl, set force-enabled = true and disabled = false . But the sorrows of Firefox do not end there - read below about the Gallery.

How it all began and what it turned into


In the beginning there was a need to write a shader. I do not have much experience in this matter, so the plans were to ask for advice from my virtual friends. I also wanted to make their work a little easier by immediately showing my prototype, without the need to install something, but with the possibility of flying to make changes and observe the result.

Conceived - done, the choice immediately fell on WebGL. I didn’t want to build my bike out of calls to WebGL functions, as the Three.JS library turned up successfully. Then the thought flickered that it would be nice to choose a backlit editor instead of textarea. The choice fell on ACE . It seemed to me pretty high quality, works with large files, supports code folding , analyzes the code and can tell where the error is, or how to do it better.

Then I wanted to make a semblance of a project manager, which would include a list of files and could delete and add files at the discretion of the client. I basically didn’t want to get in touch with the server code, there was only one way out - Html5 innovations: File API and Local Storage , at the same time see what and how.

After the project manager with the list of files was ready, the need for a linker for source files automatically matured. An elementary linker was written which, using the eval function goes through all the files. If in one of the source codes the functionality of another, which the linker has not yet reached, is required, then it is enough to call the special linker function APP.require . In this case, the linker will not go through previously connected files.

So without meeting any problems, I decided to continue the lesson. Interest has shifted to other Html5 innovations in CSS and visual effects. I wanted to make a video gallery where each video would be shown with some kind of CSS effect. There are already difficulties. About them is written further.

The final step was to separate the shader code into a separate source type. When editing shaders, the editor switched to C grammar . This turned out to be convenient, because otherwise it would be necessary to store the shader code either inside Javascript or inside Html.

Compilation of project files and minimal runtime interface


As already noted, there is an elementary linker. It is located in the app / linker.js file . It has a require function, which is available from source as APP.require . This function should be called in order to ensure the correct connection order of compiled sources. An example of use is the Brothers in arms demo (see gallery).

There is also a minimal runtime interface, which consists of the following objects:

  • APP.page.webgl.renderer - a ready-to-use Renderer object from Three.JS;
  • APP.page.webgl.viewport - an object with the width and height properties , set automatically when the WebGL window is initialized, values ​​are taken from webgl.css ;
  • APP.page.webgl.viewportMouse - an object with getX () and getY () functions that return the last coordinates of the pointer when it was above the WebGL window;
  • APP.shader (vertexShaderFileName, fragmentShaderFileName, uniforms) - returns a new THREE.ShaderMaterial object assembled from the specified routines and uniforms constants . In the future, you can change the values ​​of the properties of the uniforms object , and the shader will automatically pick them up before rendering.

This is the minimum runtime that is provided for the client source. In turn, the main and exit functions must be defined in the client source . These functions are responsible for starting and stopping the demonstration. It is recommended that you clear the resources inside exit.

Video Gallery Experiments


Here I suffered difficulties. First, border-radius in Chrome does not apply to the video element . More precisely, it applies only to an image that is used as a poster. As soon as the video starts playing, the fillets disappear. The box-reflection style only works in webkit.

Firefox came up with layout issues, and, sadly, with the very idea of ​​a video gallery. You can’t just take and stick even 4-5 video elements, even if only one of them plays when you hover over. Firefox sends a lot of requests, this page ends up and even my local Apache httpd. We have to close the browser.

In Chrome, there are no problems with suspension, although there is still something to meditate on when looking at memory consumption.

In the end, I just added the parameter to the app / gallery.js / initialize - useImages file . When set to true, there will be pictures instead of video.

Shader Compilation


To compile the shaders, I added the APP.shader function , it is described above. I’ll just clarify that the code from Three.JS is used here. This code will automatically set an attribute called “position” in your vertex shader . Keep this in mind, do not try to write a shader with a different name for this attribute. There is an alternative - to rewrite the function app / webgl.js / shader , but at the same time, you will lose the ability to use the drawer from Three.JS.

Comparison with pure WebGL sample code


It goes without saying that there will be much less code on Three.JS. And if you use my playground, then the code will still decrease. The only obstacle is the need to understand how certain WebGL functions are wrapped in the Three.JS library. For example, the TRIANGLE_STRIP vertex data submission mode in Three.JS corresponds to a THREE.Ribbon object .

For comparison, open directories with an identical project: / defaults / sources / water and / defaults / sources / water_webgl . This way you can get an idea of ​​the differences when using pure WebGL and Three.JS.

Preparing a new demonstration and inserting it into the project


All demos are described in app / gallery.js / projects . A typical description looks like this:
		'spheres' : 
		{
			files : [{type:'source', path:'defaults/sources/spheres/main.js', content:null}],
			category : 'Basic',
			title : 'Many ballz',
			image : 'defaults/sources/spheres/img.png',
			video : 'defaults/sources/spheres/video.ogv',
			description: 'Basic demo from Three.JS package, creates 50k spheres with different materials. Demonstrates on-the-fly texture generation.'
		}

To record the video, I used the free Camstudio program . From it you need to get a video in the size of 320x200. To do this, you can pre-set the window size to 320x200 in webgl.css , and in Camstudio itself configure video capture from this area. Hotkeys also help, they eliminate the need to edit video. I recommend immediately choosing the directory where the video files will be added. Preferably not root.

So that the video can be embedded in the video element, you have to convert it to OGG Theora. I used FFMpeg2Theora .

Using Parameters in Url


For convenience, it is possible to use parameters in url. For example, to show the gallery, it is enough to add the following to the address :? Gallery = category , where category is the category of demonstrations (see description of the demonstration).

You can immediately redirect to the desired project by adding ? Project = project_id , where project_id is the key in app / gallery.js / projects , for example spheres .