started shader fun post
parent
0f5bfec3ff
commit
aabe051aff
|
@ -0,0 +1,50 @@
|
||||||
|
// STEP 1: Prepare the canvas and get WebGL context
|
||||||
|
var vertShaderSource = document.getElementById("vertex-shader").text;
|
||||||
|
var fragShaderSource = document.getElementById("fragment-shader").text;
|
||||||
|
var canvas = document.getElementById('shader-canvas');
|
||||||
|
var gl = canvas.getContext('webgl', {
|
||||||
|
antialias: false,
|
||||||
|
depth: false
|
||||||
|
});
|
||||||
|
// STEP 2: define geometry and store it in buffer objects
|
||||||
|
var verticies = [-1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0];
|
||||||
|
var vertex_buffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticies), gl.STATIC_DRAW);
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, null)
|
||||||
|
// STEP 3: Create and compile shader programs
|
||||||
|
// Vert shader:
|
||||||
|
//var vertCode =
|
||||||
|
// 'attribute vec2 coordinates;' +
|
||||||
|
// 'void main(void) {' +
|
||||||
|
// ' gl_Position = vec4(coordinates, 0.0, 1.0);' +
|
||||||
|
// '}';
|
||||||
|
var vertCode = vertShaderSource;
|
||||||
|
var vertShader = gl.createShader(gl.VERTEX_SHADER);
|
||||||
|
gl.shaderSource(vertShader, vertCode);
|
||||||
|
gl.compileShader(vertShader);
|
||||||
|
// Frag shader:
|
||||||
|
// var fragCode = 'void main(void) {' +
|
||||||
|
// 'gl_FragColor = vec4(0.0, 0.3, 0.5, 1.0);' +
|
||||||
|
// '}';
|
||||||
|
var fragCode = fragShaderSource;
|
||||||
|
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
|
||||||
|
gl.shaderSource(fragShader, fragCode);
|
||||||
|
gl.compileShader(fragShader);
|
||||||
|
// combine shaders:
|
||||||
|
var shaderProgram = gl.createProgram();
|
||||||
|
gl.attachShader(shaderProgram, vertShader);
|
||||||
|
gl.attachShader(shaderProgram, fragShader);
|
||||||
|
gl.linkProgram(shaderProgram);
|
||||||
|
gl.useProgram(shaderProgram);
|
||||||
|
// STEP 4: Associate the shader program to buffer objects
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
|
||||||
|
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
|
||||||
|
gl.vertexAttribPointer(coord, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
gl.enableVertexAttribArray(coord);
|
||||||
|
// STEP 5: Draw the object:
|
||||||
|
gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||||
|
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
|
|
@ -0,0 +1,760 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012, Gregg Tavares.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Gregg Tavares. nor the names of his
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/** @module webgl-utils */
|
||||||
|
// These funcitions are meant solely to help unclutter the tutorials.
|
||||||
|
// They are not meant as production type functions.
|
||||||
|
|
||||||
|
//(function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapped logging function.
|
||||||
|
* @param {string} msg The message to log.
|
||||||
|
*/
|
||||||
|
var log = function(msg) {
|
||||||
|
if (window.console && window.console.log) {
|
||||||
|
window.console.log(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapped logging function.
|
||||||
|
* @param {string} msg The message to log.
|
||||||
|
*/
|
||||||
|
var error = function(msg) {
|
||||||
|
if (window.console) {
|
||||||
|
if (window.console.error) {
|
||||||
|
window.console.error(msg);
|
||||||
|
}
|
||||||
|
else if (window.console.log) {
|
||||||
|
window.console.log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn off all logging.
|
||||||
|
*/
|
||||||
|
var loggingOff = function() {
|
||||||
|
log = function() {};
|
||||||
|
error = function() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the page is embedded.
|
||||||
|
* @return {boolean} True of we are in an iframe
|
||||||
|
*/
|
||||||
|
var isInIFrame = function() {
|
||||||
|
return window != window.top;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a WebGL enum to a string
|
||||||
|
* @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||||
|
* @param {number} value The enum value.
|
||||||
|
* @return {string} The enum as a string.
|
||||||
|
*/
|
||||||
|
var glEnumToString = function(gl, value) {
|
||||||
|
for (var p in gl) {
|
||||||
|
if (gl[p] == value) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "0x" + value.toString(16);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the HTLM for a failure message
|
||||||
|
* @param {string} canvasContainerId id of container of th
|
||||||
|
* canvas.
|
||||||
|
* @return {string} The html.
|
||||||
|
*/
|
||||||
|
var makeFailHTML = function(msg) {
|
||||||
|
return '' +
|
||||||
|
'<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +
|
||||||
|
'<td align="center">' +
|
||||||
|
'<div style="display: table-cell; vertical-align: middle;">' +
|
||||||
|
'<div style="">' + msg + '</div>' +
|
||||||
|
'</div>' +
|
||||||
|
'</td></tr></table>';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mesasge for getting a webgl browser
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var GET_A_WEBGL_BROWSER = '' +
|
||||||
|
'This page requires a browser that supports WebGL.<br/>' +
|
||||||
|
'<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mesasge for need better hardware
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var OTHER_PROBLEM = '' +
|
||||||
|
"It doesn't appear your computer can support WebGL.<br/>" +
|
||||||
|
'<a href="http://get.webgl.org/troubleshooting/">Click here for more information.</a>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a webgl context. If creation fails it will
|
||||||
|
* change the contents of the container of the <canvas>
|
||||||
|
* tag to an error message with the correct links for WebGL.
|
||||||
|
* @param {HTMLCanvasElement} canvas. The canvas element to
|
||||||
|
* create a context from.
|
||||||
|
* @param {WebGLContextCreationAttirbutes} opt_attribs Any
|
||||||
|
* creation attributes you want to pass in.
|
||||||
|
* @return {WebGLRenderingContext} The created context.
|
||||||
|
*/
|
||||||
|
var setupWebGL = function(canvas, opt_attribs) {
|
||||||
|
function showLink(str) {
|
||||||
|
var container = canvas.parentNode;
|
||||||
|
if (container) {
|
||||||
|
container.innerHTML = makeFailHTML(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!window.WebGLRenderingContext) {
|
||||||
|
showLink(GET_A_WEBGL_BROWSER);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = create3DContext(canvas, opt_attribs);
|
||||||
|
if (!context) {
|
||||||
|
showLink(OTHER_PROBLEM);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a webgl context.
|
||||||
|
* @param {HTMLCanvasElement} canvas The canvas tag to get
|
||||||
|
* context from. If one is not passed in one will be
|
||||||
|
* created.
|
||||||
|
* @return {WebGLRenderingContext} The created context.
|
||||||
|
*/
|
||||||
|
var create3DContext = function(canvas, opt_attribs) {
|
||||||
|
var names = ["webgl", "experimental-webgl"];
|
||||||
|
var context = null;
|
||||||
|
for (var ii = 0; ii < names.length; ++ii) {
|
||||||
|
try {
|
||||||
|
context = canvas.getContext(names[ii], opt_attribs);
|
||||||
|
} catch(e) {}
|
||||||
|
if (context) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateCSSIfInIFrame = function() {
|
||||||
|
if (isInIFrame()) {
|
||||||
|
document.body.className = "iframe";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a WebGL context.
|
||||||
|
* makes its backing store the size it is displayed.
|
||||||
|
*/
|
||||||
|
var getWebGLContext = function(canvas, opt_attribs, opt_options) {
|
||||||
|
var options = opt_options || {}
|
||||||
|
|
||||||
|
if (isInIFrame()) {
|
||||||
|
updateCSSIfInIFrame();
|
||||||
|
|
||||||
|
// make the canvas backing store the size it's displayed.
|
||||||
|
if (!options.dontResize) {
|
||||||
|
var width = canvas.clientWidth;
|
||||||
|
var height = canvas.clientHeight;
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var title = document.title;
|
||||||
|
var h1 = document.createElement("h1");
|
||||||
|
h1.innerText = title;
|
||||||
|
document.body.insertBefore(h1, document.body.children[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gl = setupWebGL(canvas, opt_attribs);
|
||||||
|
return gl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a shader.
|
||||||
|
* @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||||
|
* @param {string} shaderSource The shader source.
|
||||||
|
* @param {number} shaderType The type of shader.
|
||||||
|
* @param {function(string): void) opt_errorCallback callback for errors.
|
||||||
|
* @return {WebGLShader} The created shader.
|
||||||
|
*/
|
||||||
|
var loadShader = function(gl, shaderSource, shaderType, opt_errorCallback) {
|
||||||
|
var errFn = opt_errorCallback || error;
|
||||||
|
// Create the shader object
|
||||||
|
var shader = gl.createShader(shaderType);
|
||||||
|
|
||||||
|
// Load the shader source
|
||||||
|
gl.shaderSource(shader, shaderSource);
|
||||||
|
|
||||||
|
// Compile the shader
|
||||||
|
gl.compileShader(shader);
|
||||||
|
|
||||||
|
// Check the compile status
|
||||||
|
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
||||||
|
if (!compiled) {
|
||||||
|
// Something went wrong during compilation; get the error
|
||||||
|
var lastError = gl.getShaderInfoLog(shader);
|
||||||
|
errFn("*** Error compiling shader '" + shader + "':" + lastError);
|
||||||
|
gl.deleteShader(shader);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a program, attaches shaders, binds attrib locations, links the
|
||||||
|
* program and calls useProgram.
|
||||||
|
* @param {WebGLShader[]} shaders The shaders to attach
|
||||||
|
* @param {string[]?} opt_attribs The attribs names.
|
||||||
|
* @param {number[]?} opt_locations The locations for the
|
||||||
|
* attribs.
|
||||||
|
* @param {function(string): void) opt_errorCallback callback for errors.
|
||||||
|
*/
|
||||||
|
var loadProgram = function(
|
||||||
|
gl, shaders, opt_attribs, opt_locations, opt_errorCallback) {
|
||||||
|
var errFn = opt_errorCallback || error;
|
||||||
|
var program = gl.createProgram();
|
||||||
|
for (var ii = 0; ii < shaders.length; ++ii) {
|
||||||
|
gl.attachShader(program, shaders[ii]);
|
||||||
|
}
|
||||||
|
if (opt_attribs) {
|
||||||
|
for (var ii = 0; ii < opt_attribs.length; ++ii) {
|
||||||
|
gl.bindAttribLocation(
|
||||||
|
program,
|
||||||
|
opt_locations ? opt_locations[ii] : ii,
|
||||||
|
opt_attribs[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gl.linkProgram(program);
|
||||||
|
|
||||||
|
// Check the link status
|
||||||
|
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||||
|
if (!linked) {
|
||||||
|
// something went wrong with the link
|
||||||
|
var lastError = gl.getProgramInfoLog (program);
|
||||||
|
errFn("Error in program linking:" + lastError);
|
||||||
|
|
||||||
|
gl.deleteProgram(program);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a shader from a script tag.
|
||||||
|
* @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||||
|
* @param {string} scriptId The id of the script tag.
|
||||||
|
* @param {number} opt_shaderType The type of shader. If not passed in it will
|
||||||
|
* be derived from the type of the script tag.
|
||||||
|
* @param {function(string): void) opt_errorCallback callback for errors.
|
||||||
|
* @return {WebGLShader} The created shader.
|
||||||
|
*/
|
||||||
|
var createShaderFromScript = function(
|
||||||
|
gl, scriptId, opt_shaderType, opt_errorCallback) {
|
||||||
|
var shaderSource = "";
|
||||||
|
var shaderType;
|
||||||
|
var shaderScript = document.getElementById(scriptId);
|
||||||
|
if (!shaderScript) {
|
||||||
|
throw("*** Error: unknown script element" + scriptId);
|
||||||
|
}
|
||||||
|
shaderSource = shaderScript.text;
|
||||||
|
|
||||||
|
if (!opt_shaderType) {
|
||||||
|
if (shaderScript.type == "x-shader/x-vertex") {
|
||||||
|
shaderType = gl.VERTEX_SHADER;
|
||||||
|
} else if (shaderScript.type == "x-shader/x-fragment") {
|
||||||
|
shaderType = gl.FRAGMENT_SHADER;
|
||||||
|
} else if (shaderType != gl.VERTEX_SHADER && shaderType != gl.FRAGMENT_SHADER) {
|
||||||
|
throw("*** Error: unknown shader type");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadShader(
|
||||||
|
gl, shaderSource, opt_shaderType ? opt_shaderType : shaderType,
|
||||||
|
opt_errorCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
var defaultShaderType = [
|
||||||
|
"VERTEX_SHADER",
|
||||||
|
"FRAGMENT_SHADER"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a program from 2 script tags.
|
||||||
|
*
|
||||||
|
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
|
||||||
|
* to use.
|
||||||
|
* @param {string[]} shaderScriptIds Array of ids of the script
|
||||||
|
* tags for the shaders. The first is assumed to be the
|
||||||
|
* vertex shader, the second the fragment shader.
|
||||||
|
* @param {string[]?} opt_attribs The attribs names.
|
||||||
|
* @param {number[]?} opt_locations The locations for the
|
||||||
|
* attribs.
|
||||||
|
* @param {function(string): void) opt_errorCallback callback for errors.
|
||||||
|
* @return {WebGLProgram} The created program.
|
||||||
|
*/
|
||||||
|
var createProgramFromScripts = function(
|
||||||
|
gl, shaderScriptIds, opt_attribs, opt_locations, opt_errorCallback) {
|
||||||
|
var shaders = [];
|
||||||
|
for (var ii = 0; ii < shaderScriptIds.length; ++ii) {
|
||||||
|
shaders.push(createShaderFromScript(
|
||||||
|
gl, shaderScriptIds[ii], gl[defaultShaderType[ii]], opt_errorCallback));
|
||||||
|
}
|
||||||
|
return loadProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a program from 2 sources.
|
||||||
|
*
|
||||||
|
* @param {WebGLRenderingContext} gl The WebGLRenderingContext
|
||||||
|
* to use.
|
||||||
|
* @param {string[]} shaderSourcess Array of sources for the
|
||||||
|
* shaders. The first is assumed to be the vertex shader,
|
||||||
|
* the second the fragment shader.
|
||||||
|
* @param {string[]?} opt_attribs The attribs names.
|
||||||
|
* @param {number[]?} opt_locations The locations for the
|
||||||
|
* attribs.
|
||||||
|
* @param {function(string): void) opt_errorCallback callback for errors.
|
||||||
|
* @return {WebGLProgram} The created program.
|
||||||
|
*/
|
||||||
|
var createProgramFromSources = function(
|
||||||
|
gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback) {
|
||||||
|
var shaders = [];
|
||||||
|
for (var ii = 0; ii < shaderSources.length; ++ii) {
|
||||||
|
shaders.push(loadShader(
|
||||||
|
gl, shaderSources[ii], gl[defaultShaderType[ii]], opt_errorCallback));
|
||||||
|
}
|
||||||
|
return loadProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the corresponding bind point for a given sampler type
|
||||||
|
*/
|
||||||
|
var getBindPointForSamplerType = function(gl, type) {
|
||||||
|
if (type == gl.SAMPLER_2D) return gl.TEXTURE_2D;
|
||||||
|
if (type == gl.SAMPLER_CUBE) return gl.TEXTURE_CUBE_MAP;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object.<string, function>} Setters
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates setter functions for all uniforms of a shader
|
||||||
|
* program.
|
||||||
|
*
|
||||||
|
* @see setUniforms for example
|
||||||
|
*
|
||||||
|
* @param {WebGLProgram} program the program to create setters
|
||||||
|
* for.
|
||||||
|
* @returns {Setters} an object with a setter for each uniform
|
||||||
|
* by name.
|
||||||
|
*/
|
||||||
|
var createUniformSetters = function(gl, program) {
|
||||||
|
var textureUnit = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a setter for a uniform of the given program with it's
|
||||||
|
* location embedded in the setter.
|
||||||
|
* @param {WebGLProgram} program
|
||||||
|
* @param {WebGLUniformInfo} uniformInfo
|
||||||
|
* @returns {function} the created setter.
|
||||||
|
*/
|
||||||
|
var createUniformSetter = function(program, uniformInfo) {
|
||||||
|
var location = gl.getUniformLocation(program, uniformInfo.name);
|
||||||
|
var type = uniformInfo.type;
|
||||||
|
// Check if this uniform is an array
|
||||||
|
var isArray = (uniformInfo.size > 1 && uniformInfo.name.substr(-3) == "[0]");
|
||||||
|
if (type == gl.FLOAT && isArray)
|
||||||
|
return function(v) { gl.uniform1fv(location, v); };
|
||||||
|
if (type == gl.FLOAT)
|
||||||
|
return function(v) { gl.uniform1f(location, v); };
|
||||||
|
if (type == gl.FLOAT_VEC2)
|
||||||
|
return function(v) { gl.uniform2fv(location, v); };
|
||||||
|
if (type == gl.FLOAT_VEC3)
|
||||||
|
return function(v) { gl.uniform3fv(location, v); };
|
||||||
|
if (type == gl.FLOAT_VEC4)
|
||||||
|
return function(v) { gl.uniform4fv(location, v); };
|
||||||
|
if (type == gl.INT && isArray)
|
||||||
|
return function(v) { gl.uniform1iv(location, v); };
|
||||||
|
if (type == gl.INT)
|
||||||
|
return function(v) { gl.uniform1i(location, v); };
|
||||||
|
if (type == gl.INT_VEC2)
|
||||||
|
return function(v) { gl.uniform2iv(location, v); };
|
||||||
|
if (type == gl.INT_VEC3)
|
||||||
|
return function(v) { gl.uniform3iv(location, v); };
|
||||||
|
if (type == gl.INT_VEC4)
|
||||||
|
return function(v) { gl.uniform4iv(location, v); };
|
||||||
|
if (type == gl.BOOL)
|
||||||
|
return function(v) { gl.uniform1iv(location, v); };
|
||||||
|
if (type == gl.BOOL_VEC2)
|
||||||
|
return function(v) { gl.uniform2iv(location, v); };
|
||||||
|
if (type == gl.BOOL_VEC3)
|
||||||
|
return function(v) { gl.uniform3iv(location, v); };
|
||||||
|
if (type == gl.BOOL_VEC4)
|
||||||
|
return function(v) { gl.uniform4iv(location, v); };
|
||||||
|
if (type == gl.FLOAT_MAT2)
|
||||||
|
return function(v) { gl.uniformMatrix2fv(location, false, v); };
|
||||||
|
if (type == gl.FLOAT_MAT3)
|
||||||
|
return function(v) { gl.uniformMatrix3fv(location, false, v); };
|
||||||
|
if (type == gl.FLOAT_MAT4)
|
||||||
|
return function(v) { gl.uniformMatrix4fv(location, false, v); };
|
||||||
|
if ((type == gl.SAMPLER_2D || type == gl.SAMPLER_CUBE) && isArray) {
|
||||||
|
var units = [];
|
||||||
|
for (var ii = 0; ii < info.size; ++ii) {
|
||||||
|
units.push(textureUnit++);
|
||||||
|
}
|
||||||
|
return function(bindPoint, units) {
|
||||||
|
return function(textures) {
|
||||||
|
gl.uniform1iv(location, units);
|
||||||
|
textures.forEach(function(texture, index) {
|
||||||
|
gl.activeTexture(gl.TEXTURE0 + units[index]);
|
||||||
|
gl.bindTexture(bindPoint, tetxure);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}(getBindPointForSamplerType(gl, type), units);
|
||||||
|
}
|
||||||
|
if (type == gl.SAMPLER_2D || type == gl.SAMPLER_CUBE)
|
||||||
|
return function(bindPoint, unit) {
|
||||||
|
return function(texture) {
|
||||||
|
gl.uniform1i(location, unit);
|
||||||
|
gl.activeTexture(gl.TEXTURE0 + unit);
|
||||||
|
gl.bindTexture(bindPoint, texture);
|
||||||
|
};
|
||||||
|
}(getBindPointForSamplerType(gl, type), textureUnit++);
|
||||||
|
throw ("unknown type: 0x" + type.toString(16)); // we should never get here.
|
||||||
|
};
|
||||||
|
|
||||||
|
var uniformSetters = { };
|
||||||
|
var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
|
||||||
|
|
||||||
|
for (var ii = 0; ii < numUniforms; ++ii) {
|
||||||
|
var uniformInfo = gl.getActiveUniform(program, ii);
|
||||||
|
if (!uniformInfo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var name = uniformInfo.name;
|
||||||
|
// remove the array suffix.
|
||||||
|
if (name.substr(-3) == "[0]") {
|
||||||
|
name = name.substr(0, name.length - 3);
|
||||||
|
}
|
||||||
|
var setter = createUniformSetter(program, uniformInfo);
|
||||||
|
uniformSetters[name] = setter;
|
||||||
|
}
|
||||||
|
return uniformSetters;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set uniforms and binds related textures.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* var program = createProgramFromScripts(
|
||||||
|
* gl, ["some-vs", "some-fs");
|
||||||
|
*
|
||||||
|
* var uniformSetters = createUniformSetters(program);
|
||||||
|
*
|
||||||
|
* var tex1 = gl.createTexture();
|
||||||
|
* var tex2 = gl.createTexture();
|
||||||
|
*
|
||||||
|
* ... assume we setup the textures with data ...
|
||||||
|
*
|
||||||
|
* var uniforms = {
|
||||||
|
* u_someSampler: tex1,
|
||||||
|
* u_someOtherSampler: tex2,
|
||||||
|
* u_someColor: [1,0,0,1],
|
||||||
|
* u_somePosition: [0,1,1],
|
||||||
|
* u_someMatrix: [
|
||||||
|
* 1,0,0,0,
|
||||||
|
* 0,1,0,0,
|
||||||
|
* 0,0,1,0,
|
||||||
|
* 0,0,0,0,
|
||||||
|
* ],
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* gl.useProgram(program);
|
||||||
|
*
|
||||||
|
* This will automatically bind the textures AND set the
|
||||||
|
* uniforms.
|
||||||
|
*
|
||||||
|
* setUniforms(uniformSetters, uniforms);
|
||||||
|
*
|
||||||
|
* @param {Setters} setters the setters returned from
|
||||||
|
* createUniformSettersForProgram
|
||||||
|
* @param {Object.<string, value>} an object with values for the
|
||||||
|
* uniforms.
|
||||||
|
*/
|
||||||
|
var setUniforms = function(setters, values) {
|
||||||
|
Object.keys(values).forEach(function(name) {
|
||||||
|
var setter = setters[name];
|
||||||
|
if (setter) {
|
||||||
|
setter(values[name]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates setter functions for all attributes of a shader
|
||||||
|
* program
|
||||||
|
*
|
||||||
|
* @see setAttributes for example
|
||||||
|
*
|
||||||
|
* @param {WebGLProgram} program the program to create setters
|
||||||
|
* for.
|
||||||
|
* @returns {Setters} an object with a setter for each uniform
|
||||||
|
* by name.
|
||||||
|
*/
|
||||||
|
var createAttributeSetters = function(gl, program) {
|
||||||
|
var attribSetters = {
|
||||||
|
};
|
||||||
|
|
||||||
|
function createAttribSetter(index) {
|
||||||
|
return function(b) {
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, b.buffer);
|
||||||
|
gl.enableVertexAttribArray(index);
|
||||||
|
gl.vertexAttribPointer(
|
||||||
|
index, b.numComponents || b.size, b.type || gl.FLOAT, b.normalize || false, b.stride || 0, b.offset || 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
|
||||||
|
for (var ii = 0; ii < numAttribs; ++ii) {
|
||||||
|
var attribInfo = gl.getActiveAttrib(program, ii);
|
||||||
|
if (!attribInfo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var index = gl.getAttribLocation(program, attribInfo.name);
|
||||||
|
attribSetters[attribInfo.name] = createAttribSetter(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attribSetters;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets attributes and binds buffers.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* var program = createProgramFromScripts(
|
||||||
|
* gl, ["some-vs", "some-fs");
|
||||||
|
*
|
||||||
|
* var attribSetters = createAttributeSetters(program);
|
||||||
|
*
|
||||||
|
* var positionBuffer = gl.createBuffer();
|
||||||
|
* var texcoordBuffer = gl.createBuffer();
|
||||||
|
*
|
||||||
|
* var attribs = {
|
||||||
|
* a_position: {buffer: positionBuffer, numComponents: 3},
|
||||||
|
* a_texcoord: {buffer: texcoordBuffer, numComponents: 2},
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* gl.useProgram(program);
|
||||||
|
*
|
||||||
|
* This will automatically bind the buffers AND set the
|
||||||
|
* attributes.
|
||||||
|
*
|
||||||
|
* setAttributes(attribSetters, attribs);
|
||||||
|
*
|
||||||
|
* Properties of attribs. For each attrib you can add
|
||||||
|
* properties:
|
||||||
|
*
|
||||||
|
* type: the type of data in the buffer. Default = gl.FLOAT
|
||||||
|
* normalize: whether or not to normalize the data. Default =
|
||||||
|
* false
|
||||||
|
* stride: the stride. Default = 0
|
||||||
|
* offset: offset into the buffer. Default = 0
|
||||||
|
*
|
||||||
|
* For example if you had 3 value float positions, 2 value
|
||||||
|
* float texcoord and 4 value uint8 colors you'd setup your
|
||||||
|
* attribs like this
|
||||||
|
*
|
||||||
|
* var attribs = {
|
||||||
|
* a_position: {buffer: positionBuffer, numComponents: 3},
|
||||||
|
* a_texcoord: {buffer: texcoordBuffer, numComponents: 2},
|
||||||
|
* a_color: {
|
||||||
|
* buffer: colorBuffer,
|
||||||
|
* numComponents: 4,
|
||||||
|
* type: gl.UNSIGNED_BYTE,
|
||||||
|
* normalize: true,
|
||||||
|
* },
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var setAttributes = function(setters, buffers) {
|
||||||
|
Object.keys(buffers).forEach(function(name) {
|
||||||
|
var setter = setters[name];
|
||||||
|
if (setter) {
|
||||||
|
setter(buffers[name]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add your prefix here.
|
||||||
|
var browserPrefixes = [
|
||||||
|
"",
|
||||||
|
"MOZ_",
|
||||||
|
"OP_",
|
||||||
|
"WEBKIT_"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an extension name like WEBGL_compressed_texture_s3tc
|
||||||
|
* returns the supported version extension, like
|
||||||
|
* WEBKIT_WEBGL_compressed_teture_s3tc
|
||||||
|
* @param {string} name Name of extension to look for
|
||||||
|
* @return {WebGLExtension} The extension or undefined if not
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
var getExtensionWithKnownPrefixes = function(gl, name) {
|
||||||
|
for (var ii = 0; ii < browserPrefixes.length; ++ii) {
|
||||||
|
var prefixedName = browserPrefixes[ii] + name;
|
||||||
|
var ext = gl.getExtension(prefixedName);
|
||||||
|
if (ext) {
|
||||||
|
return ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize a canvas to match the size it's displayed.
|
||||||
|
* @param {HTMLCanvasElement} canvas The canvas to resize.
|
||||||
|
* @param {boolean} true if the canvas was resized.
|
||||||
|
*/
|
||||||
|
var resizeCanvasToDisplaySize = function(canvas) {
|
||||||
|
var width = canvas.clientWidth;
|
||||||
|
var height = canvas.clientHeight;
|
||||||
|
if (canvas.width != width ||
|
||||||
|
canvas.height != height) {
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* export functions */
|
||||||
|
window.createAttributeSetters = createAttributeSetters;
|
||||||
|
window.createProgram = loadProgram;
|
||||||
|
window.createProgramFromScripts = createProgramFromScripts;
|
||||||
|
window.createProgramFromSources = createProgramFromSources;
|
||||||
|
window.createShaderFromScriptElement = createShaderFromScript;
|
||||||
|
window.createUniformSetters = createUniformSetters;
|
||||||
|
window.getWebGLContext = getWebGLContext;
|
||||||
|
window.updateCSSIfInIFrame = updateCSSIfInIFrame;
|
||||||
|
window.getExtensionWithKnownPrefixes = getExtensionWithKnownPrefixes;
|
||||||
|
window.resizeCanvasToDisplaySize = resizeCanvasToDisplaySize;
|
||||||
|
window.setAttributes = setAttributes;
|
||||||
|
window.setUniforms = setUniforms;
|
||||||
|
window.setupWebGL = setupWebGL;
|
||||||
|
|
||||||
|
// All browsers that support WebGL support requestAnimationFrame
|
||||||
|
window.requestAnimFrame = window.requestAnimationFrame; // just to stay backward compatible.
|
||||||
|
window.cancelRequestAnimFrame = window.cancelAnimationFrame; // just to stay backward compatible.
|
||||||
|
|
||||||
|
//}());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function onLoad () {
|
||||||
|
var canvas = document.getElementById("canvas");
|
||||||
|
var gl = canvas.getContext("experimental-webgl");
|
||||||
|
|
||||||
|
var vertexShaderNode = createShaderFromScriptElement(gl, "node-vertex-shader");
|
||||||
|
var fragmentShaderNode = createShaderFromScriptElement(gl, "node-fragment-shader");
|
||||||
|
var programNode = createProgram(gl, [vertexShaderNode, fragmentShaderNode]);
|
||||||
|
gl.useProgram(programNode);
|
||||||
|
|
||||||
|
|
||||||
|
var ATTRIBUTES = 5;
|
||||||
|
var j = 0;
|
||||||
|
var data = [];
|
||||||
|
var circle = {x: 50, y: 50, r: 45};
|
||||||
|
|
||||||
|
data[j++] = (circle.x - circle.r);
|
||||||
|
data[j++] = (circle.y - circle.r);
|
||||||
|
data[j++] = circle.x;
|
||||||
|
data[j++] = circle.y;
|
||||||
|
data[j++] = circle.r;
|
||||||
|
|
||||||
|
data[j++] = (circle.x + (1 + Math.sqrt(2)) * circle.r);
|
||||||
|
data[j++] = circle.y - circle.r;
|
||||||
|
data[j++] = circle.x;
|
||||||
|
data[j++] = circle.y;
|
||||||
|
data[j++] = circle.r;
|
||||||
|
|
||||||
|
data[j++] = (circle.x - circle.r);
|
||||||
|
data[j++] = (circle.y + (1 + Math.sqrt(2)) * circle.r);
|
||||||
|
data[j++] = circle.x;
|
||||||
|
data[j++] = circle.y;
|
||||||
|
data[j++] = circle.r;
|
||||||
|
|
||||||
|
var dataBuffer = new Float32Array(data);
|
||||||
|
|
||||||
|
var buffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||||
|
gl.bufferData(
|
||||||
|
gl.ARRAY_BUFFER,
|
||||||
|
dataBuffer,
|
||||||
|
gl.STATIC_DRAW);
|
||||||
|
|
||||||
|
var resolutionLocation = gl.getUniformLocation(programNode, "u_resolution");
|
||||||
|
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
var positionLocation = gl.getAttribLocation(programNode, "a_position");
|
||||||
|
var centerLocation = gl.getAttribLocation(programNode, "a_center");
|
||||||
|
var radiusLocation = gl.getAttribLocation(programNode, "a_radius");
|
||||||
|
|
||||||
|
|
||||||
|
gl.enableVertexAttribArray(positionLocation);
|
||||||
|
gl.enableVertexAttribArray(centerLocation);
|
||||||
|
gl.enableVertexAttribArray(radiusLocation);
|
||||||
|
|
||||||
|
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 0);
|
||||||
|
gl.vertexAttribPointer(centerLocation, 2, gl.FLOAT, false, ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 8);
|
||||||
|
gl.vertexAttribPointer(radiusLocation, 1, gl.FLOAT, false, ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 16);
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, data.length/ATTRIBUTES);
|
||||||
|
}
|
||||||
|
onLoad();
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
layout: post-plain
|
||||||
|
title: "Shader fun"
|
||||||
|
date: 2020-12-28
|
||||||
|
categories: design
|
||||||
|
---
|
||||||
|
<canvas id="canvas" width="1080" height="1080" style="border:1px solid white;
|
||||||
|
width:100%;"></canvas>
|
||||||
|
|
||||||
|
<script id="node-vertex-shader" type="x-shader/x-vertex">
|
||||||
|
uniform vec2 u_resolution;
|
||||||
|
attribute vec2 a_position;
|
||||||
|
attribute vec2 a_center;
|
||||||
|
attribute float a_radius;
|
||||||
|
|
||||||
|
varying vec2 center;
|
||||||
|
varying vec2 resolution;
|
||||||
|
varying float radius;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 clipspace = a_position / u_resolution * 2.0 - 1.0;
|
||||||
|
gl_Position = vec4(clipspace * vec2(1, -1), 0, 1);
|
||||||
|
|
||||||
|
radius = a_radius;
|
||||||
|
center = a_center;
|
||||||
|
resolution = u_resolution;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="node-fragment-shader" type="x-shader/x-fragment">
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
varying vec2 center;
|
||||||
|
varying vec2 resolution;
|
||||||
|
varying float radius;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
float x = gl_FragCoord.x;
|
||||||
|
float y = resolution[1] - gl_FragCoord.y;
|
||||||
|
|
||||||
|
float dx = center[0] - x;
|
||||||
|
float dy = center[1] - y;
|
||||||
|
float distance = sqrt(dx*dx + dy*dy);
|
||||||
|
|
||||||
|
if ( distance < radius )
|
||||||
|
gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
|
||||||
|
else
|
||||||
|
gl_FragColor = color0;
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
{% asset shaderCanvas2.js %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
void main(void) {
|
||||||
|
gl_FragColor = vec4(0.5, 0.3, 0.0, 1.0);
|
||||||
|
}
|
Loading…
Reference in New Issue