adding pitch and yaw support to my shaders - webgl

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 ?

Related

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>

OpenGL ES Texture Not Rendering

I am attempting to render a texture to a plane with OpenGL ES on an iPhone. I have worked with OpenGL before but I'm not sure why this isn't working.
When I run the code the plane is rendered as a black square and not a textured square. I believe the problem may be when loading the texture although I see no errors when I run the code.
Hopefully someone will spot a problem and be able to help. Thanks in advance.
Here is my code for the mesh.
// Mesh loading
- ( id ) init {
if ( self = [ super init ] ) {
glGenVertexArraysOES( 1, &m_vertexArray );
glBindVertexArrayOES( m_vertexArray );
glGenBuffers( 1, &m_vertexBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_vertexBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( g_vertices ), g_vertices, GL_STATIC_DRAW );
glGenBuffers( 1, &m_texCoordBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_texCoordBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( g_texCoords ), g_texCoords, GL_STATIC_DRAW );
}
return self;
}
- ( void ) render {
glBindBuffer( GL_ARRAY_BUFFER, m_vertexBuffer );
glVertexAttribPointer( GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, ( GLvoid* ) 0 );
glBindBuffer( GL_ARRAY_BUFFER, m_texCoordBuffer );
glVertexAttribPointer( GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, ( GLvoid* ) 0 );
glDrawArrays( GL_TRIANGLES, 0, sizeof( g_vertices ) / sizeof( g_vertices[ 0 ] ) );
}
const GLfloat g_vertices[] = {
-1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0
};
const GLfloat g_texCoords[] = {
0.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0
};
I only need a my vertices and tex coords right now so that is all I'm using.
Next is my texture loading.
- ( id ) init: ( NSString* ) filename {
if ( self = [ super init ] ) {
CGImageRef spriteImage = [ UIImage imageNamed: filename ].CGImage;
if ( !spriteImage ) {
NSLog( #"Failed to load image %#", filename );
exit( 1 );
}
size_t width = CGImageGetWidth( spriteImage );
size_t height = CGImageGetHeight( spriteImage );
GLubyte *spriteData = ( GLubyte* ) calloc( width * height * 4, sizeof( GLubyte ) );
CGContextRef spriteContext = CGBitmapContextCreate( spriteData, width, height, 8, 4 * width, CGImageGetColorSpace( spriteImage ), kCGImageAlphaPremultipliedLast );
CGContextDrawImage( spriteContext, CGRectMake( 0, 0, width, height ), spriteImage );
CGContextRelease( spriteContext );
glGenTextures( 1, &m_texture );
glBindTexture( GL_TEXTURE_2D, m_texture );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, ( GLuint ) width, ( GLuint ) height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData );
free( spriteData );
}
return self;
}
- ( void ) bind {
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, m_texture );
}
I used the texture loading code from this tutorial.
Then here is my rendering code.
- ( void ) glkView: ( GLKView* ) view drawInRect: ( CGRect ) rect {
glClearColor( 0.65f, 0.65f, 0.65f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram( m_shaderProgram );
[ m_texture bind ];
glUniform1i( uniforms[ UNIFORM_SAMPLER ], 0 );
GLKMatrix4 mvp = GLKMatrix4Multiply( GLKMatrix4Multiply( m_projectionMatrix, m_viewMatrix ), m_modelMatrix );
glUniformMatrix4fv( uniforms[ UNIFORM_MODELVIEWPROJECTION_MATRIX ], 1, 0, mvp.m );
glEnableVertexAttribArray( GLKVertexAttribPosition );
glEnableVertexAttribArray( GLKVertexAttribTexCoord0 );
[ m_plane render ];
glDisableVertexAttribArray( GLKVertexAttribTexCoord0 );
glDisableVertexAttribArray( GLKVertexAttribPosition );
}
Vertex shader.
attribute vec3 position;
attribute vec2 texCoord;
varying lowp vec2 texCoord0;
uniform mat4 modelViewProjectionMatrix;
void main()
{
texCoord0 = texCoord;
gl_Position = modelViewProjectionMatrix * vec4( position, 1.0 );
}
And lastly fragment shader.
varying lowp vec2 texCoord0;
uniform sampler2D sampler;
void main()
{
gl_FragColor = texture2D( sampler, texCoord0.st );
}
As mentioned in the comment, you can check with a Power of Two (POT) texture. In addition, there are extensions that enable support for NonPOT (NPOT) textures like GL_IMG_texture_npot, refer to the discussion in this thread (Non power of two textures in iOS), and this thread (http://aras-p.info/blog/2012/10/17/non-power-of-two-textures/).

Draw Multiple Shapes in 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);
}

Adding night lights to a WebGL / Three.js earth

I am using Three.js as a framework for developing a space simulator and I am trying, but failing to get night lights working.
The simulator can be accessed here:
orbitingeden.com
and a page running the code snippet below can be found here:
orbitingeden.com/orrery/soloearth.html
The code for the sample page is here. I don't even know where to begin. I tried rendering two globes a few units apart, one closer to the sun (daytime version) and one further(nighttime version) but there are many problems, not the least of which is that they begin to overlap each other in strange dodecahedron kind of ways. I adopted the tDiffuse2 idea from this orrery, but couldn't get it working.
<!doctype html>
<html lang="en">
<head>
<title>three.js webgl - earth</title>
<meta charset="utf-8">
<script src="three.js/Detector.js"></script>
<script src="three.js/Three.js"></script>
</head>
<body>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var radius = 6371;
var tilt = 0.41;
var rotationSpeed = 0.02;
var cloudsScale = 1.005;
var SCREEN_HEIGHT = window.innerHeight;
var SCREEN_WIDTH = window.innerWidth;
var container, camera, scene, renderer;
var meshPlanet, meshClouds, dirLight, ambientLight;
var clock = new THREE.Clock();
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0x000000, 0.00000025 );
camera = new THREE.PerspectiveCamera( 25, SCREEN_WIDTH / SCREEN_HEIGHT, 50, 1e7 );
camera.position.z = radius * 5;
scene.add( camera );
dirLight = new THREE.DirectionalLight( 0xffffff );
dirLight.position.set( -20, 0, 2 ).normalize();
scene.add( dirLight );
ambientLight = new THREE.AmbientLight( 0x000000 );
scene.add( ambientLight );
//initialize the earth
var planetTexture = THREE.ImageUtils.loadTexture( "textures/earth-day.jpg" ),
nightTexture = THREE.ImageUtils.loadTexture( "textures/earthNight.gif" ),
cloudsTexture = THREE.ImageUtils.loadTexture( "textures/clouds.gif" ),
normalTexture = THREE.ImageUtils.loadTexture( "textures/earth-map.jpg" ),
specularTexture = THREE.ImageUtils.loadTexture( "textures/earth-specular.jpg" );
var shader = THREE.ShaderUtils.lib[ "normal" ];
var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
uniforms[ "tNormal" ].texture = normalTexture;
uniforms[ "uNormalScale" ].value = 0.85;
uniforms[ "tDiffuse" ].texture = planetTexture;
uniforms[ "tDiffuse2" ].texture = nightTexture;
uniforms[ "tSpecular" ].texture = specularTexture;
uniforms[ "enableAO" ].value = false;
uniforms[ "enableDiffuse" ].value = true;
uniforms[ "enableSpecular" ].value = true;
uniforms[ "uDiffuseColor" ].value.setHex( 0xffffff );
uniforms[ "uSpecularColor" ].value.setHex( 0x333333 );
uniforms[ "uAmbientColor" ].value.setHex( 0x000000 );
uniforms[ "uShininess" ].value = 15;
var parameters = {
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: uniforms,
lights: true,
fog: true
};
var materialNormalMap = new THREE.ShaderMaterial( parameters );
geometry = new THREE.SphereGeometry( radius, 100, 50 );
geometry.computeTangents();
meshPlanet = new THREE.Mesh( geometry, materialNormalMap );
meshPlanet.rotation.y = 0;
meshPlanet.rotation.z = tilt;
scene.add( meshPlanet );
// clouds
var materialClouds = new THREE.MeshLambertMaterial( { color: 0xffffff, map: cloudsTexture, transparent: true } );
meshClouds = new THREE.Mesh( geometry, materialClouds );
meshClouds.scale.set( cloudsScale, cloudsScale, cloudsScale );
meshClouds.rotation.z = tilt;
scene.add( meshClouds );
renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } );
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
renderer.sortObjects = false;
renderer.autoClear = false;
container.appendChild( renderer.domElement );
};
function animate() {
requestAnimationFrame( animate );
render();
};
function render() {
// rotate the planet and clouds
var delta = clock.getDelta();
meshPlanet.rotation.y += rotationSpeed * delta;
meshClouds.rotation.y += 1.25 * rotationSpeed * delta;
//render the scene
renderer.clear();
renderer.render( scene, camera );
};
</script>
</body>
</html>
If I understand your question....
I don't know three.js but in general I'd do this by having a shader that has gets passed both the day and night time textures and then selecting one or the other in the shader. For example
uniform sampler2D dayTexture;
uniform sampler2D nightTexture;
varying vec3 v_surfaceToLight; // assumes this gets passed in from vertex shader
varying vec4 v_normal; // assumes this gets passed in from vertex shader
varying vec2 v_texCoord; // assumes this gets passed in from vertex shader
void main () {
vec3 normal = normalize(v_normal);
vec3 surfaceToLight = normalize(v_surfaceToLight);
float angle = dot(normal, surfaceToLight);
vec4 dayColor = texture2D(dayTexture, v_texCoords);
vec4 nightColor = texture2D(nightTexture, v_texCoord);
vec4 color = angle < 0.0 ? dayColor : nightColor;
...
gl_FragColor = color * ...;
}
Basically you take the lighting calculation and instead of using it for lighting you use it to select the texture. A lighting calculation usually uses a dot product between the normal of the surface and the direction of the light (the sun) from the surface. That gives you the cosine of the angle between those to vectors. Cosine goes from -1 to 1 so if the value is from -1 to 0 it's facing away from the sun, if it's 0 to +1 it's facing toward the sun.
The line
vec4 color = angle < 0.0 ? dayColor : nightColor;
selects the day or night. That's going to be a harsh cutoff. You might experiment with something more fuzzy like
// convert from -1 <-> +1 to 0 <-> +1
float lerp0To1 = angle * 0.5 + 0.5;
// mix between night and day
vec4 color = mix(nightColor, dayColor, lerp0to1);
That would give you 100% day on the spot directly facing the sun and 100% night on the spot directly opposite the sun and a mix in-between. Probably not what you want but you can futs with the numbers. For example
// sharpen the mix
angle = clamp(angle * 10.0, -1.0, 1.0);
// convert from -1 <-> +1 to 0 <-> +1
float lerp0To1 = angle * 0.5 + 0.5;
// mix between night and day
vec4 color = mix(nightColor, dayColor, lerp0to1);
Hopefully that made sense.
So I spent a little time working up a Three.js example, partly to learn Three.js. The sample is here.
const vs = `
varying vec2 vUv;
varying vec3 vNormal;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
vNormal = normalMatrix * normal;
gl_Position = projectionMatrix * mvPosition;
}
`;
const fs = `
uniform sampler2D dayTexture;
uniform sampler2D nightTexture;
uniform vec3 sunDirection;
varying vec2 vUv;
varying vec3 vNormal;
void main( void ) {
vec3 dayColor = texture2D( dayTexture, vUv ).rgb;
vec3 nightColor = texture2D( nightTexture, vUv ).rgb;
// compute cosine sun to normal so -1 is away from sun and +1 is toward sun.
float cosineAngleSunToNormal = dot(normalize(vNormal), sunDirection);
// sharpen the edge beween the transition
cosineAngleSunToNormal = clamp( cosineAngleSunToNormal * 10.0, -1.0, 1.0);
// convert to 0 to 1 for mixing
float mixAmount = cosineAngleSunToNormal * 0.5 + 0.5;
// Select day or night texture based on mix.
vec3 color = mix( nightColor, dayColor, mixAmount );
gl_FragColor = vec4( color, 1.0 );
}
`;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, 1, 1, 3000);
camera.position.z = 4;
scene.add( camera );
const directionalLight = new THREE.DirectionalLight( 0xaaff33, 0 );
directionalLight.position.set(-1, 1, 0.5).normalize();
scene.add( directionalLight );
const textureLoader = new THREE.TextureLoader();
const uniforms = {
sunDirection: {value: new THREE.Vector3(0,1,0) },
dayTexture: { value: textureLoader.load( "https://i.imgur.com/dfLCd19.jpg" ) },
nightTexture: { value: textureLoader.load( "https://i.imgur.com/MeKgLts.jpg" ) }
};
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vs,
fragmentShader: fs,
});
const mesh = new THREE.Mesh( new THREE.SphereGeometry( 0.75, 32, 16 ), material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
resize(true);
requestAnimationFrame(render);
function resize(force) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
if (force || canvas.width !== width || canvas.height !== height) {
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function render(time) {
time *= 0.001; // seconds
resize();
uniforms.sunDirection.value.x = Math.sin(time);
uniforms.sunDirection.value.y = Math.cos(time);
// Note: Since the earth is at 0,0,0 you can set the normal for the sun
// with
//
// uniforms.sunDirection.value.copy(sunPosition);
// uniforms.sunDirection.value.normalize();
mesh.rotation.y = time * .3
mesh.rotation.x = time * .7;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
The shader I used is this
uniform sampler2D dayTexture;
uniform sampler2D nightTexture;
uniform vec3 sunDirection;
varying vec2 vUv;
varying vec3 vNormal;
void main( void ) {
vec3 dayColor = texture2D( dayTexture, vUv ).rgb;
vec3 nightColor = texture2D( nightTexture, vUv ).rgb;
// compute cosine sun to normal so -1 is away from sun and +1 is toward sun.
float cosineAngleSunToNormal = dot(normalize(vNormal), sunDirection);
// sharpen the edge beween the transition
cosineAngleSunToNormal = clamp( cosineAngleSunToNormal * 10.0, -1.0, 1.0);
// convert to 0 to 1 for mixing
float mixAmount = cosineAngleSunToNormal * 0.5 + 0.5;
// Select day or night texture based on mixAmount.
vec3 color = mix( nightColor, dayColor, mixAmount );
gl_FragColor = vec4( color, 1.0 );
// comment in the next line to see the mixAmount
//gl_FragColor = vec4( mixAmount, mixAmount, mixAmount, 1.0 );
}
The big difference from the one above is that since the sun is generally considered a directional light since it is so far away then all you need is it's direction. In other words, which way it's pointing relative to the earth.
Thank you for sharing - very useful. Although I am now sure why shadow does not face away from sun when camera rotates (it stays static in relation to camera) . This is the code I am using to set the sunDirection uniform:
this.uniforms.sunDirection.value.copy(this.sunPosition);
this.uniforms.sunDirection.value.normalize();
Not sure why...

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