Draw Multiple Shapes in WebGL - webgl

I am facing the same issue of creating multiple objects ( One rotating and One static). I want to draw a static rectangle in the following code (The rotating rectangle code is from Edward Angels WebGL examples). I try to follow the instructions that gman has said from the link Drawing many shapes in WebGL, but still not able to solve. It would be nice to get some help on this to create another static object such as rectangle along with this rotating rectangle in the code. Thanks.
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform float theta;
void
main()
{
float s = sin( theta );
float c = cos( theta );
gl_Position.x = -s * vPosition.x + c * vPosition.y;
gl_Position.y = s * vPosition.y + c * vPosition.x;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
void
main()
{
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
</script>
var canvas;
var gl;
var theta = 0.0;
var thetaLoc;
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
var vertices = [
vec2( 0, 1 ),
vec2( 1, 0 ),
vec2( -1, 0 ),
vec2( 0, -1 )
];
var bufferId = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufferId );
gl.bufferData( gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
thetaLoc = gl.getUniformLocation( program, "theta" );
render();
};
function render() {
gl.clear( gl.COLOR_BUFFER_BIT );
theta += 0.1;
gl.uniform1f( thetaLoc, theta );
gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 );
window.requestAnimFrame(render);
}

So, were you define your vertices for the rectangle, simply add on more vertices to create an additional rectangle at a different point on the canvas. This one you only need to draw once, so if you have say:
var render = function(){
//Insert rest of code
if(!not_First_Time)
{
gl.drawArrays(gl.TRIANGLE_STRIP , 4 , 8 );
}
gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 );
//Insert rest of code
But that's more or less the cheating way of doing it as you're still modifying the points to rotate, and if you ever re-drew them, they would rotate as the main square did.
I also notice you stripped out a few of the include commands from the HTML code. You're going to need those.

Here is what my solution...
SHADER CODE:
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform float theta;
void
main()
{
float s = sin( theta );
float c = cos( theta );
gl_Position.x = -s * vPosition.x + c * vPosition.y;
gl_Position.y = s * vPosition.y + c * vPosition.x;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
void
main()
{
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
</script>
JAVASCRIPT CODE:
var canvas;
var gl;
var theta = 0.0;
var thetaLoc;
var program;
var program1;
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
//
// Configure WebGL
//
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
// Load shaders and initialize attribute buffers
program = initShaders( gl, "vertex-shader", "fragment-shader" );
program1 = initShaders( gl, "vertex-shader", "fragment-shader" );
//Rotating Rectangle
var rr_vertices = [
vec2( 0, 0.25),
vec2( 0.25, 0),
vec2(-0.25, 0 ),
vec2( 0, -0.25)
];
// Load the data into the GPU
rr_bufferId = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, rr_bufferId );
gl.bufferData( gl.ARRAY_BUFFER, flatten(rr_vertices), gl.STATIC_DRAW );
// Associate out shader variables with our data buffer
rr_vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( rr_vPosition, 2, gl.FLOAT, false, 0, 0 );
//Static Rectangle
var sr_vertices = [
vec2( 0.5, 0.5),
vec2( 1.0, 0.5),
vec2( 0.5, 1.0 ),
vec2( 1.0, 1.0)
];
// Load the data into the GPU
sr_bufferId = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, sr_bufferId );
gl.bufferData( gl.ARRAY_BUFFER, flatten(sr_vertices), gl.STATIC_DRAW );
// Associate out shader variables with our data buffer
sr_vPosition = gl.getAttribLocation( program, "vPosition" );
render();
};
var rr_vPosition;
var sr_vPosition;
var rr_bufferId;
var sr_bufferId;
function render() {
gl.clear( gl.COLOR_BUFFER_BIT );
gl.useProgram( program1 );
gl.enableVertexAttribArray( sr_vPosition );
gl.bindBuffer( gl.ARRAY_BUFFER, sr_bufferId );
gl.vertexAttribPointer( sr_vPosition, 2, gl.FLOAT, false, 0, 0 );
gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 );
gl.useProgram( program );
thetaLoc = gl.getUniformLocation( program, "theta" );
gl.enableVertexAttribArray( rr_vPosition );
gl.bindBuffer( gl.ARRAY_BUFFER, rr_bufferId );
gl.vertexAttribPointer( rr_vPosition, 2, gl.FLOAT, false, 0, 0 );
theta += 0.1;
gl.uniform1f( thetaLoc, theta );
gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 );
window.requestAnimFrame(render);
}

Related

What am I doing wrong in the following WebGL code?

I started from an example WebGL program that shows a single cube on the page. The example code does not use classes.
I want to be able to draw multiple cubes that can move independently. So I added a "Cube" class. Each instance of this class uses its own "program". I create two objects, but I draw only the first one. Unfortunately the later instantiated object is shown instead. E.g. in the code below "ground" is shown instead of "cube1".
Relevant parts of the code is below. Can you see any problem with it? How can I fix it?
...
////
class Cube {
constructor(gl, color) {
this.gl = gl;
this.program = initShaders(gl, "vertex-shader", "fragment-shader");
//// Model buffers and attributes
[this.pointsArray, this.colorsArray] = cubePointsAndColors(color);
this.numVertices = 36;
this.initAttributeBuffers();
//// Camera Related Uniforms Matrices
this.modelViewMatrixLoc = gl.getUniformLocation(
this.program,
"modelViewMatrix"
);
this.projectionMatrixLoc = gl.getUniformLocation(
this.program,
"projectionMatrix"
);
}
draw() {
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.numVertices);
}
initAttributeBuffers() {
// arrange cube color data stuff
var cBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, cBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.colorsArray),
this.gl.STATIC_DRAW
);
var vColor = this.gl.getAttribLocation(this.program, "vColor");
this.gl.vertexAttribPointer(vColor, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vColor);
// arrange cube vertex data stuff
var vBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.pointsArray),
this.gl.STATIC_DRAW
);
var vPosition = this.gl.getAttribLocation(this.program, "vPosition");
this.gl.vertexAttribPointer(vPosition, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vPosition);
}
}
window.onload = function init() {
//// initialize WebGl System
const canvas = document.getElementById("gl-canvas");
const gl = WebGLUtils.setupWebGL(canvas);
if (!gl) {
alert("WebGL isn't available");
}
gl.viewport(0, 0, canvas.width, canvas.height);
aspect = canvas.width / canvas.height;
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.enable(gl.DEPTH_TEST);
//// Initialize game objects
var cube1 = new Cube(gl, vec4(1.0, 0.0, 0.0, 1.0));
var ground = new Cube(gl, vec4(0.0, 1.0, 0.0, 1.0));
let gameObjects = [cube1];
// sliders for viewing parameters
readGUI();
render(gl, gameObjects);
};
////
var render = function(gl, gameObjects) {
//// clear the background
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//// camera settings
eye = vec3(
radius * Math.sin(theta) * Math.cos(phi),
radius * Math.sin(theta) * Math.sin(phi),
radius * Math.cos(theta)
);
modelViewMatrix = lookAt(eye, at, up);
projectionMatrix = perspective(fovy, aspect, near, far);
//// draw all objects
for (let objectI = 0; objectI < gameObjects.length; objectI++) {
const gameObject = gameObjects[objectI];
gl.useProgram(gameObject.program);
gl.uniformMatrix4fv(
gameObject.modelViewMatrixLoc,
false,
flatten(modelViewMatrix)
);
gl.uniformMatrix4fv(
gameObject.projectionMatrixLoc,
false,
flatten(projectionMatrix)
);
gameObject.draw();
}
requestAnimFrame(() => render(gl, gameObjects));
};
...
In WebGL 1.0 drawArrays, uses the vertices which are currently specified by vertexAttribPointer and enabled by enableVertexAttribArray.
Use properties to store the buffer objects (this.cBuffer, this.vBuffer) and attribute indices (this.vColor, this.vPosition):
initAttributeBuffers() {
// arrange cube color data stuff
this.cBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.colorsArray),
this.gl.STATIC_DRAW
);
this.vColor = this.gl.getAttribLocation(this.program, "vColor");
// arrange cube vertex data stuff
this.vBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.pointsArray),
this.gl.STATIC_DRAW
);
this.vPosition = this.gl.getAttribLocation(this.program, "vPosition");
}
Specify and enable the arrays of generic vertex attribute data right before the draw call:
draw() {
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cBuffer);
this.gl.vertexAttribPointer(this.vColor, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(this.vColor);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vBuffer);
this.gl.vertexAttribPointer(this.vPosition, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(this.vPosition);
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.numVertices);
}
In WebGL 2.0 (or by the use of the extension OES_vertex_array_object), that can be simplified by the use of WebGLVertexArrayObjects.
The vertex specification is stated in the vertex array object:
initAttributeBuffers() {
// create vertex array object
this.vao = this.gl.createVertexArray();
this.gl.bindVertexArray(this.vao);
// arrange cube color data stuff
var cBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, cBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.colorsArray),
this.gl.STATIC_DRAW
);
var vColor = this.gl.getAttribLocation(this.program, "vColor");
this.gl.vertexAttribPointer(vColor, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vColor);
// arrange cube vertex data stuff
var vBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.pointsArray),
this.gl.STATIC_DRAW
);
var vPosition = this.gl.getAttribLocation(this.program, "vPosition");
this.gl.vertexAttribPointer(vPosition, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vPosition);
}
It is sufficient to bind the vertex array before the draw call:
draw() {
this.gl.bindVertexArray(this.vao);
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.numVertices);
}

adding pitch and yaw support to my shaders

I try to add depth, pitch and yaw support to my shaders.
Here is my code. It works, but the value of z has no effect. May it be 0 or 1 or anything in between, there is no visible change. So, no depth.
All examples I find use matrices to calculate rotations. I prefer calculating all vertices and textures coordinates myself.
m4 = twgl.m4;
_webgl.vertex_shader = `
attribute vec4 position;
attribute vec2 texcoord;
uniform vec4 u_resolution;
varying vec3 v_texcoord;
void main() {
gl_Position = position ;
v_texcoord = vec3(texcoord.xy, 1) ;
}
`;
_webgl.fragment_shader = `
precision mediump float ;
varying vec3 v_texcoord ;
uniform sampler2D tex ;
uniform float alpha ;
void main()
{
gl_FragColor = texture2DProj( tex , v_texcoord );
gl_FragColor.a *= alpha ;
gl_FragColor.rgb *= alpha ;
}
`;
gl_.programInfo = twgl.createProgramInfo( gl , [_webgl.vertex_shader,_webgl.fragment_shader] );
gl_.program = gl_.programInfo.program ;
gl.useProgram( gl_.program );
gl.disable( gl.DEPTH_TEST );
gl.blendFunc( gl.SRC_ALPHA , gl.ONE_MINUS_SRC_ALPHA );
gl.blendFunc( gl.ONE , gl.ONE_MINUS_SRC_ALPHA );
gl.enable( gl.BLEND ) ;
gl_.resolutionLocation = gl.getUniformLocation( gl_.program , "u_resolution" );
_webgl.webglalpha = gl.getUniformLocation( gl_.program , "alpha" );
gl.uniform1f( _webgl.webglalpha, 1 );
_webgl.current_opacity = 1 ;
gl_.positionLocation = gl.getAttribLocation( gl_.program , "position" );
gl_.texcoordLocation = gl.getAttribLocation( gl_.program , "texcoord" );
gl_.posBuffer = gl.createBuffer();
gl_.texcoordBuffer = gl.createBuffer();
gl.enableVertexAttribArray( gl_.positionLocation );
gl.bindBuffer( gl.ARRAY_BUFFER , gl_.posBuffer );
gl.vertexAttribPointer( gl_.positionLocation, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( gl_.texcoordLocation );
gl.bindBuffer( gl.ARRAY_BUFFER, gl_.texcoordBuffer );
gl.vertexAttribPointer( gl_.texcoordLocation , 2, gl.FLOAT, false, 0, 0 );
During rendering, for every picture visible onscreen, I push xyz coordinates for the vertices in a _webgl_draw__position array, and xy of the texture in a _webgl_draw__texcoord array.
To calculate coordinates, for each object "e", I do this :
( cam is current camera )
( I do not yet calculate z. I just set z manually to other values than 0 to try before I go on adding maths for yaw and pitch rotations. )
e.x_relative_to_camera = e.x - cam.x ;
e.y_relative_to_camera = e.y - cam.y ;
e.z_relative_to_camera = e.z - cam.z ;
e.distance = get_distance_between_points_3d( cam.x , cam.y , cam.z , e.x , e.y , e.z ) ;
e.angle_from_camera_on_xz = get_angle_from_points( cam.x , cam.z , e.x_relative_to_camera , e.z_relative_to_camera )-90 ;
e.angle_from_view_xz = _difference_between_angles_( cam.angle_left_right , e.angle_from_camera_on_xz );
e.x_on_screen = (e.angle_from_view_xz/(cam.FOV/2)) * half_of_game_width ;
e.angle_from_camera_on_yz = get_angle_from_points( cam.y , cam.z , e.y_relative_to_camera , e.z_relative_to_camera )-90 ;
e.angle_from_view_yz = _difference_entre_angles_( cam.angle_top_bottom , e.angle_from_camera_on_yz );
e.y_on_screen = (e.angle_from_view_yz/(cam.FOV/2)) * half_of_game_width ;
e.scaling_on_screen = cam.distance_at_which_scaling_is_1 / e.z_relative_to_camera ;
For example, it works with this quad :
-0.13199636340141296 , -0.21341681480407715 , 0
0.13605406880378723 , -0.21341681480407715 , 0
-0.13199636340141296 , -0.6469348073005676 , 0
-0.13199636340141296 , -0.6469348073005676 , 0
0.13605406880378723 , -0.21341681480407715 , 0
0.13605406880378723 , -0.6469348073005676 , 0
Then, at the end, it renders it all at once :
gl.bindBuffer( gl.ARRAY_BUFFER , gl_.posBuffer );
gl.bufferData( gl.ARRAY_BUFFER, _webgl_draw__position , gl.STATIC_DRAW );
gl.bindBuffer( gl.ARRAY_BUFFER, gl_.texcoordBuffer );
gl.bufferData( gl.ARRAY_BUFFER, _webgl_draw__texcoord , gl.STATIC_DRAW );
gl.drawArrays( gl.TRIANGLES, 0, _webgl_draw__position.length/3 );
What am I missing ?

How draw 2d array of points being every point a different color at one time with WebGl?

With this code i can draw pixel by pixel, but i want to send all array together for a performance issue.
function drawOneBlackPixel( gl, x, y ) {
// Fills the buffer with a single point?
r=numToFloat(_.random(1,255) );
g=numToFloat(_.random(1,255) );
b=numToFloat(_.random(1,255) );
gl.uniform4f( colorLocation, r , g, b, 1);
gl.bufferData( gl.ARRAY_BUFFER , new Float32Array([
x, y]), gl.STATIC_DRAW );
gl.drawArrays( gl.POINTS, 0, 1 );
// Draw one point.
}
function numToFloat(x){
return x/255;
}
for(i=0;i<500;i++){
for(j=0;j<500;j++){
drawOneBlackPixel( gl, i, j );
}
}
Thanks!
Just like XY data, you can pass color data in attributes
const vs = `
attribute vec2 aPosition;
attribute vec3 aColor;
varying vec3 vColor;
void main() {
gl_Position = vec4( aPosition, 1.0, 1.0 );
vColor = aColor;
gl_PointSize = 4.0;
}
`;
const fs = `
precision mediump float;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( vColor, 1.0 );
}
`;
const gl = document.querySelector("#glcanvas").getContext("webgl");
// Compile program
// ===================
var program = gl.createProgram();
var vShader = gl.createShader( gl.VERTEX_SHADER );
var fShader = gl.createShader( gl.FRAGMENT_SHADER );
gl.attachShader( program, vShader );
gl.attachShader( program, fShader );
gl.shaderSource( vShader, vs );
gl.compileShader( vShader );
gl.shaderSource( fShader, fs );
gl.compileShader( fShader );
gl.linkProgram( program );
gl.useProgram( program );
// Create points datas
// ===================
const NUM_POINTS = 0xFF;
var data = new Float32Array( NUM_POINTS * 5);
for (var i = 0; i < NUM_POINTS; i++) {
var j = i*5;
data[j+0] = Math.random()*2.0 - 1.0; // x
data[j+1] = Math.random()*2.0 - 1.0; // y
data[j+2] = Math.random(); // r
data[j+3] = Math.random(); // g
data[j+4] = Math.random(); // b
};
// Setup ArrayBuffer
// ===================
var buffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, this.buffer );
gl.bufferData( gl.ARRAY_BUFFER, data, gl.STATIC_DRAW );
var aPos = gl.getAttribLocation( program, 'aPosition' );
gl.enableVertexAttribArray( aPos );
gl.vertexAttribPointer( aPos, 2, gl.FLOAT, false, 5*4, 0 );
var aCol = gl.getAttribLocation( program, 'aColor' );
gl.enableVertexAttribArray( aCol );
gl.vertexAttribPointer( aCol, 3, gl.FLOAT, false, 5*4, 2*4 );
// Draw
// ===================
gl.drawArrays( gl.POINTS, 0, NUM_POINTS );
canvas { border: 1px solid black; margin: 2px; }
<canvas id="glcanvas"></canvas>

Using sample2D as position in vertex shader

I'm learning how to manipulate particles with FBO in webGL, I tried to store the position with a texture and use it a position reference, but nothing came up on the stage.
Fragment Shaders
precision mediump float;
void main() {
gl_FragColor = vec4(vec3(1.0), 1.0);
}
</script>
Vertex Render Shader script
attribute vec2 aTextureUV;
uniform sampler2D uTexture;
void main() {
vec4 texture = texture2D( uTexture, aTextureUV );
gl_Position = vec4( texture.rgb, 1.0 );
gl_PointSize = 3;
}
</script>
JS Script
// Determine the UVs
var uvs = new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
1.0, 1.0
])
var uvBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, uvBuffer );
gl.bufferData( gl.ARRAY_BUFFER, uvs, gl.STATIC_DRAW );
gl.enableVertexAttribArray( defaultProgram.aTextureUVLoc );
gl.vertexAttribPointer( defaultProgram.aTextureUVLoc, 2, gl.FLOAT, false, 0, 0);
// Texture initialization
for(var i = 0; i < particleCount; i++) {
initialData.push(
Math.random(),
Math.random(),
Math.random(),
0
);
}
var texture = gl.createTexture();
gl.activeTexture( gl.TEXTURE0 );
gl.bindTexture( gl.TEXTURE_2D, texture );
gl.pixelStorei( gl.UNPACK_ALIGNMENT, 1 );
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGBA, fboWidth, fboWidth, 0,
gl.RGBA, gl.FLOAT, new Float32Array(initialData)
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
.....
function draw() {
requestAnimationFrame( draw );
gl.viewport( 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays( gl.POINTS, 0, particleCount );
}
Can't comment yet, but just as a desktop GL remark, I can see that 1) there are no actual draw calls in your script i.e. glDrawElements/glDrawArrays (unless you've left some parts of it out), and 2) you're missing a fragment shader. Refer to e.g. this.

How to get a "Glow" shader effect in OpenGL ES 2.0?

I'm writing a 3D app for iOS. I'm new to OpenGL ES 2.0, so I'm still getting myself around writing basic shaders.
I really need to implement a "Glow" effect on some of my models, based on the texturing.
Here's a sample:
.
I'm looking for code examples for OpenGL ES 2.0. Most code I find on the internet is either for desktop OpenGL or D3D.
Any ideas?
First of all there are tons of algorithms and techniques to generate a glow effect.
I just want to present one possibility.
Create a Material that is luminescent.
For this I use a modified Blinn-Phong light model, where the direction to the light source is always the inverse direction of the normal vector of the fragment.
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
uniform float u_glow;
void main()
{
vec3 color = vertCol;
float shininess = 10.0;
vec3 normalV = normalize( vertNV );
vec3 eyeV = normalize( -vertPos );
vec3 halfV = normalize( eyeV + normalV );
float NdotH = max( 0.0, dot( normalV, halfV ) );
float glowFac = ( shininess + 2.0 ) * pow( NdotH, shininess ) / ( 2.0 * 3.14159265 );
gl_FragColor = vec4( u_glow * (0.1 + color.rgb * glowFac * 0.5), 1.0 );
}
In a second step a gaussian blur algorithm is performed on the output. The scene is written to frame buffer with a texture bound to the color plane. A screen space pass uses the texture as the input to blur the output.
For performance reasons, the blur algorithm is first performed along the X-axis of the viewport and in a further step along the Y-axis of the viewport.
varying vec2 vertPos;
uniform sampler2D u_textureCol;
uniform vec2 u_textureSize;
uniform float u_sigma;
uniform int u_width;
float CalcGauss( float x, float sigma )
{
float coeff = 1.0 / (2.0 * 3.14157 * sigma);
float expon = -(x*x) / (2.0 * sigma);
return (coeff*exp(expon));
}
void main()
{
vec2 texC = vertPos.st * 0.5 + 0.5;
vec4 texCol = texture( u_textureCol, texC );
vec4 gaussCol = vec4( texCol.rgb, 1.0 );
vec2 step = 1.0 / u_textureSize;
for ( int i = 1; i <= u_width; ++ i )
{
vec2 actStep = vec2( float(i) * step.x, 0.0 ); // this is for the X-axis
// vec2 actStep = vec2( 0.0, float(i) * step.y ); this would be for the Y-axis
float weight = CalcGauss( float(i) / float(u_width), u_sigma );
texCol = texture2D( u_textureCol, texC + actStep );
gaussCol += vec4( texCol.rgb * weight, weight );
texCol = texture2D( u_textureCol, texC - actStep );
gaussCol += vec4( texCol.rgb * weight, weight );
}
gaussCol.rgb /= gaussCol.w;
gl_FragColor = vec4( gaussCol.rgb, 1.0 );
}
For the implementation of a blur algorithm see also the answer to the questions:
OpenGL es 2.0 Gaussian blur on triangle
What kind of blurs can be implemented in pixel shaders?
See the following similar WebGL example which puts all together:
var readInput = true;
function changeEventHandler(event){
readInput = true;
}
(function loadscene() {
var resize, gl, progDraw, progBlurX, progPost, vp_size, blurFB;
var bufCube = {};
var bufQuad = {};
var shininess = 10.0;
var glow = 10.0;
var sigma = 0.8;
function render(delteMS){
//if ( readInput ) {
readInput = false;
var sliderScale = 100;
shininess = document.getElementById( "shine" ).value;
glow = document.getElementById( "glow" ).value / sliderScale;
sigma = document.getElementById( "sigma" ).value / sliderScale;
//}
Camera.create();
Camera.vp = vp_size;
gl.enable( gl.DEPTH_TEST );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
// set up framebuffer
gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[0] );
gl.viewport( 0, 0, blurFB[0].width, blurFB[0].height );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
// set up draw shader
ShaderProgram.Use( progDraw.prog );
ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() );
ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() );
var modelMat = IdentityMat44()
modelMat = RotateAxis( modelMat, CalcAng( delteMS, 13.0 ), 0 );
modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 );
ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );
ShaderProgram.SetUniformF1( progDraw.prog, "u_shininess", shininess );
ShaderProgram.SetUniformF1( progDraw.prog, "u_glow", glow );
// draw scene
VertexBuffer.Draw( bufCube );
// set blur-X framebuffer and bind frambuffer texture
gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[1] );
gl.viewport( 0, 0, blurFB[1].width, blurFB[1].height );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
var texUnit = 1;
gl.activeTexture( gl.TEXTURE0 + texUnit );
gl.bindTexture( gl.TEXTURE_2D, blurFB[0].color0_texture );
// set up blur-X shader
ShaderProgram.Use( progBlurX.prog );
ShaderProgram.SetUniformI1( progBlurX.prog , "u_texture", texUnit )
ShaderProgram.SetUniformF2( progBlurX.prog , "u_textureSize", vp_size );
ShaderProgram.SetUniformF1( progBlurX.prog , "u_sigma", sigma )
// draw full screen space
gl.enableVertexAttribArray( progBlurX.inPos );
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.vertexAttribPointer( progBlurX.inPos, 2, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
gl.disableVertexAttribArray( progBlurX.inPos );
// reset framebuffer and bind frambuffer texture
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
gl.viewport( 0, 0, vp_size[0], vp_size[1] );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
texUnit = 2;
gl.activeTexture( gl.TEXTURE0 + texUnit );
gl.bindTexture( gl.TEXTURE_2D, blurFB[1].color0_texture );
// set up pst process shader
ShaderProgram.Use( progPost.prog );
ShaderProgram.SetUniformI1( progPost.prog, "u_texture", texUnit )
ShaderProgram.SetUniformF2( progPost.prog, "u_textureSize", vp_size );
ShaderProgram.SetUniformF1( progPost.prog, "u_sigma", sigma );
// draw full screen space
gl.enableVertexAttribArray( progPost.inPos );
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.vertexAttribPointer( progPost.inPos, 2, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
gl.disableVertexAttribArray( progPost.inPos );
requestAnimationFrame(render);
}
function resize() {
//vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
vp_size = [window.innerWidth, window.innerHeight]
canvas.width = vp_size[0];
canvas.height = vp_size[1];
var fbsize = Math.max(vp_size[0], vp_size[1])-1;
fbsize = 1 << 31 - Math.clz32(fbsize); // nearest power of 2
fbsize = fbsize * 2
blurFB = [];
for ( var i = 0; i < 2; ++ i ) {
fb = gl.createFramebuffer();
fb.width = fbsize;
fb.height = fbsize;
gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
fb.color0_texture = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
fb.renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
gl.bindTexture( gl.TEXTURE_2D, null );
gl.bindRenderbuffer( gl.RENDERBUFFER, null );
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
blurFB.push( fb );
}
}
function initScene() {
canvas = document.getElementById( "canvas");
gl = canvas.getContext( "experimental-webgl" );
if ( !gl )
return null;
progDraw = {}
progDraw.prog = ShaderProgram.Create(
[ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
if ( !progDraw.prog )
return null;
progDraw.inPos = gl.getAttribLocation( progDraw.prog, "inPos" );
progDraw.inNV = gl.getAttribLocation( progDraw.prog, "inNV" );
progDraw.inCol = gl.getAttribLocation( progDraw.prog, "inCol" );
progBlurX = {}
progBlurX.prog = ShaderProgram.Create(
[ { source : "post-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "blurX-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
progBlurX.inPos = gl.getAttribLocation( progBlurX.prog, "inPos" );
if ( !progBlurX.prog )
return;
progPost = {}
progPost.prog = ShaderProgram.Create(
[ { source : "post-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "blurY-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
progPost.inPos = gl.getAttribLocation( progPost.prog, "inPos" );
if ( !progPost.prog )
return;
// create cube
var cubePos = [
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0 ];
var cubeCol = [ 1.0, 0.0, 0.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ];
var cubeHlpInx = [ 0, 1, 2, 3, 1, 5, 6, 2, 5, 4, 7, 6, 4, 0, 3, 7, 3, 2, 6, 7, 1, 0, 4, 5 ];
var cubePosData = [];
for ( var i = 0; i < cubeHlpInx.length; ++ i ) {
cubePosData.push( cubePos[cubeHlpInx[i]*3], cubePos[cubeHlpInx[i]*3+1], cubePos[cubeHlpInx[i]*3+2] );
}
var cubeNVData = [];
for ( var i1 = 0; i1 < cubeHlpInx.length; i1 += 4 ) {
var nv = [0, 0, 0];
for ( i2 = 0; i2 < 4; ++ i2 ) {
var i = i1 + i2;
nv[0] += cubePosData[i*3]; nv[1] += cubePosData[i*3+1]; nv[2] += cubePosData[i*3+2];
}
for ( i2 = 0; i2 < 4; ++ i2 )
cubeNVData.push( nv[0], nv[1], nv[2] );
}
var cubeColData = [];
for ( var is = 0; is < 6; ++ is ) {
for ( var ip = 0; ip < 4; ++ ip ) {
cubeColData.push( cubeCol[is*3], cubeCol[is*3+1], cubeCol[is*3+2] );
}
}
var cubeInxData = [];
for ( var i = 0; i < cubeHlpInx.length; i += 4 ) {
cubeInxData.push( i, i+1, i+2, i, i+2, i+3 );
}
bufCube = VertexBuffer.Create(
[ { data : cubePosData, attrSize : 3, attrLoc : progDraw.inPos },
{ data : cubeNVData, attrSize : 3, attrLoc : progDraw.inNV },
{ data : cubeColData, attrSize : 3, attrLoc : progDraw.inCol } ],
cubeInxData );
bufQuad.pos = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW );
bufQuad.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW );
window.onresize = resize;
resize();
requestAnimationFrame(render);
}
function Fract( val ) {
return val - Math.trunc( val );
}
function CalcAng( deltaTime, intervall ) {
return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI;
}
function CalcMove( deltaTime, intervall, range ) {
var pos = self.Fract( deltaTime / (1000*intervall) ) * 2.0
var pos = pos < 1.0 ? pos : (2.0-pos)
return range[0] + (range[1] - range[0]) * pos;
}
function EllipticalPosition( a, b, angRag ) {
var a_b = a * a - b * b
var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b );
var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b );
return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];
}
glArrayType = typeof Float32Array !="undefined" ? Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );
function IdentityMat44() {
var m = new glArrayType(16);
m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0;
m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
return m;
};
function RotateAxis(matA, angRad, axis) {
var aMap = [ [1, 2], [2, 0], [0, 1] ];
var a0 = aMap[axis][0], a1 = aMap[axis][1];
var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
var matB = new glArrayType(16);
for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i];
for ( var i = 0; i < 3; ++ i ) {
matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
}
return matB;
}
function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
return [ v[0] / len, v[1] / len, v[2] / len ];
}
var Camera = {};
Camera.create = function() {
this.pos = [0, 3, 0.0];
this.target = [0, 0, 0];
this.up = [0, 0, 1];
this.fov_y = 90;
this.vp = [800, 600];
this.near = 0.5;
this.far = 100.0;
}
Camera.Perspective = function() {
var fn = this.far + this.near;
var f_n = this.far - this.near;
var r = this.vp[0] / this.vp[1];
var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
var m = IdentityMat44();
m[0] = t/r; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = t; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = -fn / f_n; m[11] = -1;
m[12] = 0; m[13] = 0; m[14] = -2 * this.far * this.near / f_n; m[15] = 0;
return m;
}
Camera.LookAt = function() {
var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
var mx = Normalize( Cross( this.up, mz ) );
var my = Normalize( Cross( mz, mx ) );
var tx = Dot( mx, this.pos );
var ty = Dot( my, this.pos );
var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos );
var m = IdentityMat44();
m[0] = mx[0]; m[1] = my[0]; m[2] = mz[0]; m[3] = 0;
m[4] = mx[1]; m[5] = my[1]; m[6] = mz[1]; m[7] = 0;
m[8] = mx[2]; m[9] = my[2]; m[10] = mz[2]; m[11] = 0;
m[12] = tx; m[13] = ty; m[14] = tz; m[15] = 1;
return m;
}
var ShaderProgram = {};
ShaderProgram.Create = function( shaderList ) {
var shaderObjs = [];
for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
if ( shderObj == 0 )
return 0;
shaderObjs.push( shderObj );
}
var progObj = this.LinkProgram( shaderObjs )
if ( progObj != 0 ) {
progObj.attribIndex = {};
var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
var name = gl.getActiveAttrib( progObj, i_n ).name;
progObj.attribIndex[name] = gl.getAttribLocation( progObj, name );
}
progObj.unifomLocation = {};
var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
var name = gl.getActiveUniform( progObj, i_n ).name;
progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
}
}
return progObj;
}
ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; }
ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; }
ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); }
ShaderProgram.SetUniformI1 = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF1 = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF2 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF3 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF4 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.CompileShader = function( source, shaderStage ) {
var shaderScript = document.getElementById(source);
if (shaderScript)
source = shaderScript.text;
var shaderObj = gl.createShader( shaderStage );
gl.shaderSource( shaderObj, source );
gl.compileShader( shaderObj );
var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
return status ? shaderObj : null;
}
ShaderProgram.LinkProgram = function( shaderObjs ) {
var prog = gl.createProgram();
for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
gl.attachShader( prog, shaderObjs[i_sh] );
gl.linkProgram( prog );
status = gl.getProgramParameter( prog, gl.LINK_STATUS );
if ( !status ) alert("Could not initialise shaders");
gl.useProgram( null );
return status ? prog : null;
}
var VertexBuffer = {};
VertexBuffer.Create = function( attributes, indices ) {
var buffer = {};
buffer.buf = [];
buffer.attr = []
for ( var i = 0; i < attributes.length; ++ i ) {
buffer.buf.push( gl.createBuffer() );
buffer.attr.push( { size : attributes[i].attrSize, loc : attributes[i].attrLoc } );
gl.bindBuffer( gl.ARRAY_BUFFER, buffer.buf[i] );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( attributes[i].data ), gl.STATIC_DRAW );
}
buffer.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW );
buffer.inxLen = indices.length;
gl.bindBuffer( gl.ARRAY_BUFFER, null );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
return buffer;
}
VertexBuffer.Draw = function( bufObj ) {
for ( var i = 0; i < bufObj.buf.length; ++ i ) {
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.buf[i] );
gl.vertexAttribPointer( bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( bufObj.attr[i].loc );
}
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
for ( var i = 0; i < bufObj.buf.length; ++ i )
gl.disableVertexAttribArray( bufObj.attr[i].loc );
gl.bindBuffer( gl.ARRAY_BUFFER, null );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
}
initScene();
})();
html,body {
height: 100%;
width: 100%;
margin: 0;
overflow: hidden;
}
#gui {
position : absolute;
top : 0;
left : 0;
}
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision highp float;
attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
void main()
{
mat4 mv = u_viewMat44 * u_modelMat44;
vertCol = inCol;
vertNV = normalize(mat3(mv) * inNV);
vec4 viewPos = mv * vec4( inPos, 1.0 );
vertPos = viewPos.xyz;
gl_Position = u_projectionMat44 * viewPos;
}
</script>
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
uniform float u_shininess;
uniform float u_glow;
void main()
{
vec3 color = vertCol;
vec3 normalV = normalize( vertNV );
vec3 eyeV = normalize( -vertPos );
vec3 halfV = normalize( eyeV + normalV );
float NdotH = max( 0.0, dot( normalV, halfV ) );
float shineFac = ( u_shininess + 2.0 ) * pow( NdotH, u_shininess ) / ( 2.0 * 3.14159265 );
gl_FragColor = vec4( u_glow*0.1 + color.rgb * u_glow * shineFac * 0.5, 1.0 );
}
</script>
<script id="post-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 inPos;
varying vec2 pos;
void main()
{
pos = inPos;
gl_Position = vec4( inPos, 0.0, 1.0 );
}
</script>
<script id="blurX-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 pos;
uniform sampler2D u_texture;
uniform vec2 u_textureSize;
uniform float u_sigma;
float CalcGauss( float x, float sigma )
{
float coeff = 1.0 / (2.0 * 3.14157 * sigma);
float expon = -(x*x) / (2.0 * sigma);
return (coeff*exp(expon));
}
void main()
{
vec2 texC = pos.st * 0.5 + 0.5;
vec4 texCol = texture2D( u_texture, texC );
vec4 gaussCol = vec4( texCol.rgb, 1.0 );
float stepX = 1.0 / u_textureSize.x;
for ( int i = 1; i <= 20; ++ i )
{
float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
texCol = texture2D( u_texture, texC + vec2( float(i) * stepX, 0.0 ) );
gaussCol += vec4( texCol.rgb * weight, weight );
texCol = texture2D( u_texture, texC - vec2( float(i) * stepX, 0.0 ) );
gaussCol += vec4( texCol.rgb * weight, weight );
}
gaussCol.rgb /= gaussCol.w;
gl_FragColor = vec4( gaussCol.rgb, 1.0 );
}
</script>
<script id="blurY-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 pos;
uniform sampler2D u_texture;
uniform vec2 u_textureSize;
uniform float u_sigma;
float CalcGauss( float x, float sigma )
{
float coeff = 1.0 / (2.0 * 3.14157 * sigma);
float expon = -(x*x) / (2.0 * sigma);
return (coeff*exp(expon));
}
void main()
{
vec2 texC = pos.st * 0.5 + 0.5;
vec4 texCol = texture2D( u_texture, texC );
vec4 gaussCol = vec4( texCol.rgb, 1.0 );
float stepY = 1.0 / u_textureSize.y;
for ( int i = 1; i <= 20; ++ i )
{
float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
texCol = texture2D( u_texture, texC + vec2( 0.0, float(i) * stepY ) );
gaussCol += vec4( texCol.rgb * weight, weight );
texCol = texture2D( u_texture, texC - vec2( 0.0, float(i) * stepY ) );
gaussCol += vec4( texCol.rgb * weight, weight );
}
vec3 hdrCol = 2.0 * gaussCol.xyz / gaussCol.w;
vec3 mappedCol = vec3( 1.0 ) - exp( -hdrCol.rgb * 3.0 );
gl_FragColor = vec4( clamp( mappedCol.rgb, 0.0, 1.0 ), 1.0 );
}
</script>
<div>
<form id="gui" name="inputs">
<table>
<tr> <td> <font color= #CCF>shininess</font> </td>
<td> <input type="range" id="shine" min="0" max="50" value="10" onchange="changeEventHandler(event);"/></td> </tr>
<tr> <td> <font color= #CCF>glow</font> </td>
<td> <input type="range" id="glow" min="100" max="400" value="250" onchange="changeEventHandler(event);"/></td> </tr>
<tr> <td> <font color= #CCF>blur</font> </td>
<td> <input type="range" id="sigma" min="1" max="100" value="60" onchange="changeEventHandler(event);"/></td> </tr>
</table>
</form>
</div>
<canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>
The website GLSL Sandbox has a collection of shader examples. This one has the glow and appears to be able to compile for ES.
You should be able to modify these to pull uv's from your texture.
Here is some code directly from this site:
#ifdef GL_ES
precision mediump float;
#endif
#extension GL_OES_standard_derivatives : enable
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
void main(void){
vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
vec3 color1 = vec3(0.0, 0.3, 0.5);
vec3 color2 = vec3(0.5, 0.0, 0.3);
float f = 0.0;
float g = 0.0;
float h = 0.0;
float PI = 3.14159265;
for(float i = 0.0; i < 40.0; i++){
if (floor(mouse.x * 41.0) < i)
break;
float s = sin(time + i * PI / 20.0) * 0.8;
float c = cos(time + i * PI / 20.0) * 0.8;
float d = abs(p.x + c);
float e = abs(p.y + s);
f += 0.001 / d;
g += 0.001 / e;
h += 0.00003 / (d * e);
}
gl_FragColor = vec4(f * color1 + g * color2 + vec3(h), 1.0);
}

Resources