I am trying to write a simple WebGL script to display a pyramid with a brick texture and Phong lighting. The lighting works fine but when I incorporate the texture, the pyramid turns black. I've checked and set my parameters to use with power-of-two textures since my texture is 512x512. This scene should be straight out of the the Mozilla WebGL examples but some reason it is not working. I am now desperate and cannot figure out why adding textures objects black. Below is my code.
<html>
<head>
<title>WebGL Simple Pyramid</
CanvasMatrix class
(c) Apple Inc
-->
<script src="CanvasMatrix.js" type="text/javascript"></script>
<!--
Vertex shader
-->
<script id="shader-vs" type="x-shader/x-vertex">
precision highp float;
attribute vec3 XYZ;
attribute vec3 RGB;
attribute vec3 NOR;
attribute vec2 TEX;
uniform mat4 ProjectionMatrix;
uniform mat4 ModelviewMatrix;
varying vec3 col;
varying vec2 tex;
vec3 ambient = vec3(0.3, 0.3, 0.3);
vec3 diffuse = vec3(1.0, 1.0, 1.0);
vec3 specular = vec3(1.0, 1.0, 1.0);
vec4 position = vec4(-2.0, 1.0, -2.0, 1.0);
void main(void)
{
// P is the vertex coordinate on body
vec3 P = vec3(ModelviewMatrix * vec4(XYZ, 1));
// N is the object normal at P
vec4 norm = normalize(ModelviewMatrix * vec4(NOR, 1));
vec3 N = vec3(norm.xyz);
// L is the light vector
vec3 L = normalize(vec3(ModelviewMatrix*position) - P);
// Emission and ambient color
vec3 color = ambient;
// Diffuse light intensity is cosine of light and normal vectors
float Id = dot(L,N);
if (Id>0.0)
{
// Add diffuse
color += Id*diffuse;
// R is the reflected light vector R = 2(L.N)N - L
vec3 R = reflect(-L, N);
// V is the view vector (eye at the origin)
vec3 V = normalize(-P);
// Specular is cosine of reflected and view vectors
float Is = dot(R,V);
if (Is>0.0) color += pow(Is,32.0)*specular;
}
// Pass color to fragment shader
col = color*RGB;
// Pass texture coordinates to fragment shader (will be interpolated)
tex = TEX;
// Set transformed vertex location
gl_Position = ProjectionMatrix * ModelviewMatrix * vec4(XYZ,1);
}
</script>
<!--
Fragment shader
-->
<script id="shader-fs" type="x-shader/x-fragment">
precision highp float;
varying vec3 col;
varying vec2 tex;
uniform sampler2D uSampler;
void main(void)
{
gl_FragColor = vec4(col,1) * texture2D(uSampler, tex);
}
</script>
<!--
WebGL program
-->
<script type="text/javascript">
//
// Compile a shader
//
function CompileShader(gl,id)
{
// Get shader by id
var src = document.getElementById(id);
// Create shader based on type setting
var shader;
if (src.type == "x-shader/x-fragment")
shader = gl.createShader(gl.FRAGMENT_SHADER);
else if (src.type == "x-shader/x-vertex")
shader = gl.createShader(gl.VERTEX_SHADER);
else
return null;
// Read source into str
var str = "";
var k = src.firstChild;
while (k)
{
if (k.nodeType == 3) str += k.textContent;
k = k.nextSibling;
}
gl.shaderSource(shader, str);
// Compile the shader
gl.compileShader(shader);
// Check for errors
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0)
alert(gl.getShaderInfoLog(shader));
// Return shader
return shader;
}
//
// Compile shader program
//
function CompileShaderProg(gl,vert,frag)
{
// Compile the program
var prog = gl.createProgram();
gl.attachShader(prog , CompileShader(gl,vert));
gl.attachShader(prog , CompileShader(gl,frag));
gl.linkProgram(prog);
// Check for errors
if (gl.getProgramParameter(prog, gl.LINK_STATUS) == 0)
alert(gl.getProgramInfoLog(prog));
// Return program
return prog;
}
var text;
var image;
function initTexture()
{
text = gl.createTexture();
image = new Image();
image.onload = function() {handleTextureLoaded(text, image)}
image.src = "wall.png";
}
function handleTextureLoaded(txt, img)
{
gl.bindTexture(gl.TEXTURE_2D, txt);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
var gl,canvas;
function webGLStart()
{
// Set canvas
canvas = document.getElementById("canvas");
// Select canvas size
var size = Math.min(window.innerWidth,window.innerHeight)-10;
canvas.width = size;
canvas.height = size;
// Start WebGL
if (!window.WebGLRenderingContext)
{
alert("Your browser does not support WebGL. See http://get.webgl.org");
return;
}
try
{
gl = canvas.getContext("experimental-webgl");
}
catch(e)
{}
if (!gl)
{
alert("Can't get WebGL");
return;
}
// Set viewport to entire canvas
gl.viewport(0,0,size,size);
// Initialize textures
initTexture();
// Load Shader
var prog = CompileShaderProg(gl,"shader-vs","shader-fs");
// Set program
gl.useProgram(prog);
// Set projection
var ProjectionMatrix = new CanvasMatrix4();
ProjectionMatrix.ortho(-2.5,+2.5,-2.5,+2.5,-2.5,+2.5);
// Vertex array count
var n = 18;
// Pyramid vertex coordinates
var xyz =
[
-1,-1,-1, 1,-1,-1, -1,-1,1,
1,-1,-1, -1,-1,1, 1,-1,1,
0,1,0, -1,-1,1, 1,-1,1,
0,1,0, 1,-1,-1, -1,-1,-1,
0,1,0, 1,-1,1, 1,-1,-1,
0,1,0, -1,-1,-1, -1,-1,1,
];
var verts = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,verts);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(xyz),gl.STATIC_DRAW);
// Pyramid colors
var rgb =
[
0.84,0.62,0.32, 0.84,0.62,0.32, 0.84,0.62,0.32,
0.84,0.62,0.32, 0.84,0.62,0.32, 0.84,0.62,0.32,
0.84,0.62,0.32, 0.84,0.62,0.32, 0.84,0.62,0.32,
0.84,0.62,0.32, 0.84,0.62,0.32, 0.84,0.62,0.32,
0.84,0.62,0.32, 0.84,0.62,0.32, 0.84,0.62,0.32,
0.84,0.62,0.32, 0.84,0.62,0.32, 0.84,0.62,0.32,
];
var color = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,color);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(rgb),gl.STATIC_DRAW);
// Pyramid texture coordinates
var tex =
[
0,0, 4,0, 0,4,
4,0, 0,4, 4,4,
2,4, 0,0, 4,0,
2,4, 0,0, 4,0,
2,4, 0,0, 4,0,
2,4, 0,0, 4,0,
];
var texture = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,texture);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(tex),gl.STATIC_DRAW);
// Cube normals
var nor =
[
0,-1, 0, 0,-1, 0, 0,-1, 0,
0,-1, 0, 0,-1, 0, 0,-1, 0,
0,0.4472136,0.89442719, 0,0.4472136,0.89442719, 0,0.4472136,0.89442719,
0,0.4472136,-0.89442719, 0,0.4472136,-0.89442719, 0,0.4472136,-0.89442719,
0.89442719,0.4472136,0, 0.89442719,0.4472136,0, 0.89442719,0.4472136,0,
-0.89442719,0.4472136,0, -0.89442719,0.4472136,0, -0.89442719,0.4472136,0,
];
var normals = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,normals);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(nor),gl.STATIC_DRAW);
// Set state to draw scene
gl.enable(gl.DEPTH_TEST);
gl.clearColor(0.8,0.8,0.8,1);
// Mouse control variables
var x0 = y0 = move = 0;
// Rotation angles
var th = ph = 15;
// Draw scene the first time
Display();
//
// Display the scene
//
function Display()
{
// Clear the screen and Z buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Compute modelview matrix
var ModelviewMatrix = new CanvasMatrix4();
ModelviewMatrix.makeIdentity();
ModelviewMatrix.rotate(ph,0,1,0);
ModelviewMatrix.rotate(th,1,0,0);
// Set shader
gl.useProgram(prog);
// Set projection and modelview matrixes
gl.uniformMatrix4fv(gl.getUniformLocation(prog,"ProjectionMatrix") , false , new Float32Array(ProjectionMatrix.getAsArray()));
gl.uniformMatrix4fv(gl.getUniformLocation(prog,"ModelviewMatrix") , false , new Float32Array(ModelviewMatrix.getAsArray()));
// Set up 3D vertex array
gl.bindBuffer(gl.ARRAY_BUFFER,verts);
var XYZ = gl.getAttribLocation(prog,"XYZ");
gl.enableVertexAttribArray(XYZ);
gl.vertexAttribPointer(XYZ,3,gl.FLOAT,false,0,0);
// Set up 3D color array
gl.bindBuffer(gl.ARRAY_BUFFER,color);
var RGB = gl.getAttribLocation(prog,"RGB");
gl.enableVertexAttribArray(RGB);
gl.vertexAttribPointer(RGB,3,gl.FLOAT,false,0,0);
// Set up 3D normal array
gl.bindBuffer(gl.ARRAY_BUFFER,normals);
var NOR = gl.getAttribLocation(prog,"NOR");
gl.enableVertexAttribArray(NOR);
gl.vertexAttribPointer(NOR,3,gl.FLOAT,false,0,0);
// Set up 2D texture array
gl.bindBuffer(gl.ARRAY_BUFFER,texture);
var TEX = gl.getAttribLocation(prog,"TEX");
gl.enableVertexAttribArray(TEX);
gl.vertexAttribPointer(TEX,2,gl.FLOAT,false,0,0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, text);
gl.uniform1i(gl.getUniformLocation(prog, "uSampler"), 0);
// Draw all vertexes
gl.drawArrays(gl.TRIANGLES,0,n);
// Disable vertex arrays
gl.disableVertexAttribArray(XYZ);
gl.disableVertexAttribArray(RGB);
gl.disableVertexAttribArray(NOR);
gl.disableVertexAttribArray(TEX);
// Flush
gl.flush();
}
//
// Resize canvas
//
canvas.resize = function ()
{
var size = Math.min(window.innerWidth, window.innerHeight)-10;
canvas.width = size;
canvas.height = size;
gl.viewport(0,0,size,size);
Display();
}
//
// Mouse button pressed
//
canvas.onmousedown = function (ev)
{
move = 1;
x0 = ev.clientX;
y0 = ev.clientY;
}
//
// Mouse button released
//
canvas.onmouseup = function (ev)
{
move = 0;
}
//
// Mouse movement
//
canvas.onmousemove = function (ev)
{
if (move==0) return;
// Update angles
ph -= ev.clientX-x0;
th += ev.clientY-y0;
// Store location
x0 = ev.clientX;
y0 = ev.clientY;
// Redisplay
Display();
}
}
</script>
<!--
Web page
-->
</head>
<body onload="webGLStart();" onresize="canvas.resize();">
<H1>WebGL Simple Pyramid</H1>
<canvas id="canvas" width="500" height="500"></canvas>
</body>
</html>