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