Skip to content

Commit

Permalink
Quick-and-dirty stereoscopic implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
dondi committed Mar 21, 2017
1 parent a984ca5 commit d7eebbf
Show file tree
Hide file tree
Showing 5 changed files with 678 additions and 0 deletions.
95 changes: 95 additions & 0 deletions hello-webgl-vr/glsl-utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* A set of utility functions that are common across many types of
* WebGL programs.
*/
(() => {
/*
* Returns the WebGL rendering context.
*/
let getGL = (canvas) => canvas.getContext("webgl");

/*
* Initializes a vertex buffer for the given array of vertices.
*/
let initVertexBuffer = (gl, vertices) => {
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
return buffer;
};

/*
* Sets up a GLSL shader of the given type.
*/
let compileShader = (gl, shaderSource, shaderType, compileError) => {
let shader = gl.createShader(shaderType);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);

// Check for an error.
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
if (compileError) {
compileError(shader);
}

return null;
} else {
return shader;
}
};

/*
* Links a GLSL program.
*/
let linkShaderProgram = (gl, vertexShader, fragmentShader) => {
let shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
return shaderProgram;
};

/*
* Initializes a simple shader program, using these parameters:
*
* - gl: The WebGL context to use.
* - vertexShaderSource: The vertex shader source code.
* - fragmentShaderSource: The fragment shader source code.
*
* Optional parameters:
*
* - compileError: The function to call if a shader does not compile.
* - linkError: The function to call if the program does not link.
*/
let initSimpleShaderProgram = (gl, vertexShaderSource, fragmentShaderSource, compileError, linkError) => {
let vertexShader = compileShader(gl, vertexShaderSource, gl.VERTEX_SHADER, compileError);
let fragmentShader = compileShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER, compileError);

// If either shader is null, we just bail out. An error would have
// been reported to the compileError function.
if (!vertexShader || !fragmentShader) {
return null;
}

// Link the shader program.
let shaderProgram = linkShaderProgram(gl, vertexShader, fragmentShader);
if (gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
return shaderProgram;
}

// If we get here, something must have gone wrong.
if (linkError) {
linkError(shaderProgram);
}

return null;
}

window.GLSLUtilities = {
getGL,
initVertexBuffer,
compileShader,
linkShaderProgram,
initSimpleShaderProgram
};
})();
5 changes: 5 additions & 0 deletions hello-webgl-vr/hello-webgl-vr.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
canvas {
display: block;
margin-left: auto;
margin-right: auto;
}
111 changes: 111 additions & 0 deletions hello-webgl-vr/hello-webgl-vr.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Hello WebGL (cheap VR version)!</title>
<link rel="stylesheet" href="hello-webgl-vr.css" />
</head>
<body>
<h1>Hello WebGL (cheap VR version)</h1>

<p>You’ll need a WebGL-capable web browser to see anything here;
instructions can be found in this
<a href="http://www.khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">official
WebGL wiki page</a>.</p>

<p>This page demonstrates a super-cheap form of VR. If you look closely, note how each scene is
just a tiny bit off-center, in different directions—the key technique behind stereoscopic vision.</p>

<p>Because we don’t have goggles to isolate what each eye is seeing, you’ll need to fool your brain a bit.
Try holding your hand between you and the display first, then focus on your hand. Without changing how your
eyes are configured, move your hand away. It takes some practice, and you might need to adjust your distance
from the display. Also, some folks do better when the scene is stationary; others when it is in motion.</p>

<p>The result won’t be perfect, but you get the idea. Now go get a VR headset 🕶</p>

<canvas id="hello-webgl-vr" width="1536" height="512">
Sorry, your web browser does not appear to support
the <code>canvas</code> element, either.
</canvas>

<!-- jQuery makes some things more convenient. -->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>

<!-- GLSLUtilities is a starting point for holding functionality that
is common to many WebGL programs. -->
<script src="glsl-utilities.js"></script>

<!-- Shapes is a library that generates "canned" shapes. -->
<script src="shapes.js"></script>

<!-- Set up shaders: we've placed the source in script elements for
simplicity. Shaders are ideally kept in separate files for easier
maintenance, but in that situation, additional code and security
constraints are involved. -->

<!-- The vertex shader is a complete pass-through. -->
<script id="vertex-shader" type="x-shader/x-vertex">
#ifdef GL_ES
precision highp float;
#endif

attribute vec3 vertexPosition;

// Note this new additional output.
attribute vec3 vertexColor;
varying vec4 finalVertexColor;
uniform mat4 rotationMatrix;
uniform mat4 translationMatrix;

void main(void) {
vec4 rotatedVertex = rotationMatrix * vec4(vertexPosition, 1.0);

// Super-cheap, highly non-generalizable perspective effect.
float foreshortening = 0.6 + (1.0 - rotatedVertex.z) / 5.0;
mat4 foreshorteningMatrix = mat4(
foreshortening,
0.0,
0.0,
0.0,

0.0,
foreshortening,
0.0,
0.0,

0.0,
0.0,
foreshortening,
0.0,

0.0,
0.0,
0.0,
1.0
);

gl_Position = translationMatrix * foreshorteningMatrix * rotatedVertex;
finalVertexColor = vec4(vertexColor, 1.0);
}
</script>

<!-- The fragment shader produces a single unconditional color. -->
<script id="fragment-shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif

varying vec4 finalVertexColor;

void main(void) {
// We vary the color based on the fragment's z coordinate,
// which, at this point, ranges from 0 (near) to 1 (far).
// Note the ".rgb" subselector.
gl_FragColor = vec4((1.0 - gl_FragCoord.z) * finalVertexColor.rgb, 1.0);
}
</script>

<!-- This script sets up the specific scene for this page. -->
<script src="hello-webgl-vr.js"></script>
</body>
</html>
Loading

0 comments on commit d7eebbf

Please sign in to comment.