<p>I have to add a spotlight to my rotating cube so this is my code:</p>

<p>HTML</p>

<pre><code>        &lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;button id = "ButtonX"&gt;Rotate X&lt;/button&gt;
&lt;button id = "ButtonY"&gt;Rotate Y&lt;/button&gt;
&lt;button id = "ButtonZ"&gt;Rotate Z&lt;/button&gt;
&lt;button id = "ButtonT"&gt;Toggle Rotation&lt;/button&gt;


&lt;script id="vertex-shader" type="x-shader/x-vertex"&gt;

attribute  vec4 vPosition;
attribute  vec4 vColor;
attribute  vec2 vTexCoord;
attribute  vec3 vNormal;

uniform float shininess;

uniform vec4 posLightPosition;
uniform vec4 posAmbientProduct, posDiffuseProduct,      posSpecularProduct;

uniform vec4 dirLightPosition;
uniform vec4 dirAmbientProduct, dirDiffuseProduct,      dirSpecularProduct;

uniform vec4 spotLightPosition;
uniform vec4 spotAmbientProduct, spotDiffuseProduct,spotSpecularProduct;
uniform vec4 spotLightDirection;
uniform float lCutOff;



varying vec4 fColor;
varying vec2 fTexCoord;

uniform vec3 theta;

void main()
{
    // Compute the sines and cosines of theta for each of
    //   the three axes in one computation.
    vec3 angles = radians( theta );
    vec3 c = cos( angles );
    vec3 s = sin( angles );

    // Remeber: thse matrices are column-major
    mat4 rx = mat4( 1.0,  0.0,  0.0, 0.0,
            0.0,  c.x,  s.x, 0.0,
            0.0, -s.x,  c.x, 0.0,
            0.0,  0.0,  0.0, 1.0 );

    mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
            0.0, 1.0,  0.0, 0.0,
            s.y, 0.0,  c.y, 0.0,
            0.0, 0.0,  0.0, 1.0 );


    mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
            -s.z,  c.z, 0.0, 0.0,
            0.0,  0.0, 1.0, 0.0,
            0.0,  0.0, 0.0, 1.0 );

    vec3 N=normalize((rz*ry*rx*vNormal).xyz);

    // positional light
    vec3 pos=-(rz*ry*rx*vPosition).xyz;
    vec3 posLight=posLightPosition.xyz;
    vec3 posL=normalize(posLight-pos);
    vec3 posE=normalize(-pos);
    vec3 posH=normalize(posL+posE);
    vec4 posAmbient=posAmbientProduct;
    float posKd=max(dot(posL,N),0.0);
    vec4 posDiffuse=posKd*posDiffuseProduct;
    float posKs=pow(max(dot(N,posH),0.0), shininess);
    vec4 posSpecular=posKs*posSpecularProduct;
    if(dot(posL,N)&lt;0.0){
    posSpecular=vec4(0.0,0.0,0.0,1.0);
    }

    // directional light
    vec3 dirLight=dirLightPosition.xyz;
    vec3 dirL=normalize(dirLight);
    vec3 dirE=normalize(-pos);
    vec3 dirH=normalize(dirL+dirE);
    vec4 dirAmbient=dirAmbientProduct;
    float dirKd=max(dot(dirL,N),0.0);
    vec4 dirDiffuse=dirKd*dirDiffuseProduct;
    float dirKs=pow(max(dot(N,dirH),0.0), shininess);
    vec4 dirSpecular=dirKs*dirSpecularProduct;
    if(dot(dirL,N)&lt;0.0){
    dirSpecular=vec4(0.0,0.0,0.0,1.0);
    }


    //spotlight
    vec3 spotLight=spotLightPosition.xyz;
    vec3 spotL=normalize(spotLight);
    vec3 spotE=normalize(-pos);
    vec3 spotH=normalize(spotL+spotE);
    vec3 spotD=spotLightDirection.xyz;
    vec4 spotAmbient=spotAmbientProduct;
    float spotKd=max(dot(spotL,N),0.0);
    vec4 spotDiffuse=spotKd*spotDiffuseProduct;
    float spotKs=pow(max(dot(N,spotH),0.0), shininess);
    vec4 spotSpecular=spotKs*spotSpecularProduct;
    if(dot(spotL,N)&lt;0.0){
    spotSpecular=vec4(0.0,0.0,0.0,1.0);
    }
    float lEffect= dot(normalize(spotD), -spotH);
    if(lEffect&gt;lCutOff)
    {
    vec4 ambient=posAmbient+dirAmbient+spotAmbient;
    vec4 diffuse=posDiffuse+dirDiffuse+spotDiffuse;
    vec4 specular=posSpecular+dirSpecular+spotSpecular;


    fColor = ambient+vColor*(diffuse+specular);
    fColor.a = 1.0;
    }
    else{
    vec4 ambient=posAmbient+dirAmbient;
    vec4 diffuse=posDiffuse+dirDiffuse;
    vec4 specular=posSpecular+dirSpecular;


    fColor = ambient+vColor*(diffuse+specular);
    fColor.a = 1.0;

        }

        fTexCoord = vTexCoord;
    gl_Position = rz * ry * rx * vPosition;
    gl_Position.z = -gl_Position.z;
}
&lt;/script&gt;

&lt;script id="fragment-shader" type="x-shader/x-fragment"&gt;

precision mediump float;

varying vec4 fColor;
varying  vec2 fTexCoord;

uniform sampler2D Tex0;
uniform sampler2D Tex1;

void
main()
{
    gl_FragColor = fColor*(texture2D(Tex0, fTexCoord)*texture2D(Tex1, fTexCoord));

}
&lt;/script&gt;

&lt;script type="text/javascript" src="../Common/webgl-utils.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="../Common/initShaders.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="../Common/MV.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="Homework1.js"&gt;&lt;/script&gt;

&lt;body&gt;
&lt;canvas id="gl-canvas" width="1024" height="1024"&gt;
Oops ... your browser doesn't support the HTML5 canvas element
&lt;/canvas&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>JAVASCRIPT</p>

<pre><code>"use strict";

var canvas;
var gl;

var numVertices  = 36;

var texSize = 256;
var numChecks = 8;

var program;

var texture1, texture2;
var t1, t2;
var normalsArray = [];

var dirLightPosition = vec4(1.0, 1.0, 1.0, 0.0 );
var dirLightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var dirLightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var dirLightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );

var posLightPosition = vec4(1.0, 1.0, 1.0, 1.0 );
var posLightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var posLightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var posLightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );

var materialAmbient = vec4( 1.0, 0.0, 1.0, 1.0 );
var materialDiffuse = vec4( 1.0, 0.8, 0.0, 1.0 );
var materialSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );
var materialShininess = 20.0;

var spotLightPosition = vec4(1.0, 2.0, 3.0, 1.0 );
var spotLightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var spotLightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var spotLightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );
var spotLightDirection = vec4(-0.5,1.0,2.0,1.0);
var lCutOff=0.867;


var c;

var flag = true;

var image1 = new Uint8Array(4*texSize*texSize);

    for ( var i = 0; i &lt; texSize; i++ ) {
        for ( var j = 0; j &lt;texSize; j++ ) {
            var patchx = Math.floor(i/(texSize/numChecks));
            var patchy = Math.floor(j/(texSize/numChecks));
            if(patchx%2 ^ patchy%2) c = 255;
            else c = 0;
            //c = 255*(((i &amp; 0x8) == 0) ^ ((j &amp; 0x8)  == 0))
            image1[4*i*texSize+4*j] = c;
            image1[4*i*texSize+4*j+1] = c;
            image1[4*i*texSize+4*j+2] = c;
            image1[4*i*texSize+4*j+3] = 255;
        }
    }

var image2 = new Uint8Array(4*texSize*texSize);

    // Create a checkerboard pattern
    for ( var i = 0; i &lt; texSize; i++ ) {
        for ( var j = 0; j &lt;texSize; j++ ) {
            image2[4*i*texSize+4*j] = 127+127*Math.sin(0.1*i*j);
            image2[4*i*texSize+4*j+1] = 127+127*Math.sin(0.1*i*j);
            image2[4*i*texSize+4*j+2] = 127+127*Math.sin(0.1*i*j);
            image2[4*i*texSize+4*j+3] = 255;
           }
    }

var pointsArray = [];
var colorsArray = [];
var texCoordsArray = [];

var texCoord = [
    vec2(0, 0),
    vec2(0, 1),
    vec2(1, 1),
    vec2(1, 0)
];

var vertices = [
    vec4( -0.5, -0.5,  0.5, 1.0 ),
    vec4( -0.5,  0.5,  0.5, 1.0 ),
    vec4( 0.5,  0.5,  0.5, 1.0 ),
    vec4( 0.5, -0.5,  0.5, 1.0 ),
    vec4( -0.5, -0.5, -0.5, 1.0 ),
    vec4( -0.5,  0.5, -0.5, 1.0 ),
    vec4( 0.5,  0.5, -0.5, 1.0 ),
    vec4( 0.5, -0.5, -0.5, 1.0 )
];

var vertexColors = [
    vec4( 0.0, 0.0, 0.0, 1.0 ),  // black
    vec4( 1.0, 0.0, 0.0, 1.0 ),  // red
    vec4( 1.0, 1.0, 0.0, 1.0 ),  // yellow
    vec4( 0.0, 1.0, 0.0, 1.0 ),  // green
    vec4( 0.0, 0.0, 1.0, 1.0 ),  // blue
    vec4( 1.0, 0.0, 1.0, 1.0 ),  // magenta
    vec4( 0.0, 1.0, 1.0, 1.0 ),  // white
    vec4( 0.0, 1.0, 1.0, 1.0 )   // cyan
];

var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = xAxis;

var theta = [45.0, 45.0, 45.0];

var thetaLoc;

function configureTexture() {
    texture1 = gl.createTexture();
    gl.bindTexture( gl.TEXTURE_2D, texture1 );
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, image1);
    gl.generateMipmap( gl.TEXTURE_2D );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
                      gl.NEAREST_MIPMAP_LINEAR );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

    texture2 = gl.createTexture();
    gl.bindTexture( gl.TEXTURE_2D, texture2 );
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, image2);
    gl.generateMipmap( gl.TEXTURE_2D );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
                      gl.NEAREST_MIPMAP_LINEAR );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
}

function quad(a, b, c, d) {

     var t1 = subtract(vertices[b], vertices[a]);
     var t2 = subtract(vertices[c], vertices[b]);
     var normal = cross(t1, t2);
     var normal = vec3(normal);

     pointsArray.push(vertices[a]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[0]);
     normalsArray.push(normal);

     pointsArray.push(vertices[b]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[1]);
     normalsArray.push(normal);

     pointsArray.push(vertices[c]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[2]);
     normalsArray.push(normal);

     pointsArray.push(vertices[a]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[0]);
     normalsArray.push(normal);

     pointsArray.push(vertices[c]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[2]);
     normalsArray.push(normal);

     pointsArray.push(vertices[d]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[3]);
     normalsArray.push(normal);
}

function colorCube()
{
    quad( 1, 0, 3, 2 );
    quad( 2, 3, 7, 6 );
    quad( 3, 0, 4, 7 );
    quad( 6, 5, 1, 2 );
    quad( 4, 5, 6, 7 );
    quad( 5, 4, 0, 1 );
}


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 );

    gl.enable(gl.DEPTH_TEST);

    //
    //  Load shaders and initialize attribute buffers
    //
    program = initShaders( gl, "vertex-shader", "fragment-shader" );
    gl.useProgram( program );

    colorCube();

    var nBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );

    var vNormal = gl.getAttribLocation( program, "vNormal" );
    gl.vertexAttribPointer( vNormal, 3, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vNormal );


    var cBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );

    var vColor = gl.getAttribLocation( program, "vColor" );
    gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vColor );

    var vBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer);
    gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );

    var vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vPosition );

    var tBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, tBuffer);
    gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoordsArray), gl.STATIC_DRAW );

    var vTexCoord = gl.getAttribLocation( program, "vTexCoord" );
    gl.vertexAttribPointer( vTexCoord, 2, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vTexCoord );

    var dirAmbientProduct = mult(dirLightAmbient, materialAmbient);
    var dirDiffuseProduct = mult(dirLightDiffuse, materialDiffuse);
    var dirSpecularProduct = mult(dirLightSpecular, materialSpecular);

    var posAmbientProduct = mult(posLightAmbient, materialAmbient);
    var posDiffuseProduct = mult(posLightDiffuse, materialDiffuse);
    var posSpecularProduct = mult(posLightSpecular, materialSpecular);


    var spotAmbientProduct = mult(spotLightAmbient, materialAmbient);
    var spotDiffuseProduct = mult(spotLightDiffuse, materialDiffuse);
    var spotSpecularProduct = mult(spotLightSpecular, materialSpecular);




    configureTexture();

    gl.activeTexture( gl.TEXTURE0 );
    gl.bindTexture( gl.TEXTURE_2D, texture1 );
    gl.uniform1i(gl.getUniformLocation( program, "Tex0"), 0);

    gl.activeTexture( gl.TEXTURE1 );
    gl.bindTexture( gl.TEXTURE_2D, texture2 );
    gl.uniform1i(gl.getUniformLocation( program, "Tex1"), 1);

    thetaLoc = gl.getUniformLocation(program, "theta");

    gl.uniform4fv( gl.getUniformLocation(program,
       "dirAmbientProduct"),flatten(dirAmbientProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posAmbientProduct"),flatten(posAmbientProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotAmbientProduct"),flatten(spotAmbientProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "dirDiffuseProduct"),flatten(dirDiffuseProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posDiffuseProduct"),flatten(posDiffuseProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotDiffuseProduct"),flatten(spotDiffuseProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "dirSpecularProduct"),flatten(dirSpecularProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posSpecularProduct"),flatten(posSpecularProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotSpecularProduct"),flatten(spotSpecularProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posLightPosition"),flatten(posLightPosition) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "dirLightPosition"),flatten(dirLightPosition) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotLightPosition"),flatten(spotLightPosition) );
    gl.uniform1f( gl.getUniformLocation(program,
       "shininess"),materialShininess );
    gl.uniform1f( gl.getUniformLocation(program,
       "lCutOff"),lCutOff );
    gl.uniform1f( gl.getUniformLocation(program,
       "spotLightDirection"),spotLightDirection );




 document.getElementById("ButtonX").onclick = function(){axis = xAxis;};
 document.getElementById("ButtonY").onclick = function(){axis = yAxis;};
 document.getElementById("ButtonZ").onclick = function(){axis = zAxis;};
 document.getElementById("ButtonT").onclick = function(){flag = !flag;};

    render();
}

var render = function() {
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    if(flag) theta[axis] += 2.0;
    gl.uniform3fv(thetaLoc, theta);
    gl.drawArrays( gl.TRIANGLES, 0, numVertices );
    requestAnimFrame(render);
}
</code></pre>

<p>So I computed tha angle between the spotlight direction and the vector to light source from vertex and if this angle is greater than the cutoff angle defined by the spotlight I compute the three products for the Phong lighting model.</p>

<p>Where am I wrong?</p>

CC BY-SA 3.0
2017-04-20T14:24:06.153Z
What happens when you run it? Can you provide a screenshot as a visual reference?
Dan
CC BY-SA 3.0
2017-04-20T14:56:01.290Z
@Dan I tried with the directional and positional lights turned off and only with the spotlight turned on and the cube appears to be all black, so a scene without lights, so I assumed that the spotlight doesn't work
B.junior
CC BY-SA 3.0
2017-04-20T17:10:14.440Z
Unfortunately I don't have the time to debug your shader for you, but I would start by removing things from the shader code incrementally until it works and backtrack from there to find the problem. Bugs that cause nothing to render at all are the worst ones to find!
Dan
CC BY-SA 3.0
2017-04-20T17:55:31.783Z
I've tried to remove the other two lights but I can't find the bug!
B.junior
CC BY-SA 3.0
2017-04-20T21:04:53.473Z
Keep removing features (e.g. texturing), one at a time. Maybe try a very simple shader that just makes everything white, then start adding features back once you have something that renders.
Dan
CC BY-SA 3.0
2017-04-20T21:40:42.403Z
Yeah I did it, maybe I just need a good reference in order to understand better the use of a spotlight, it's not really clear in the online material that I've found.
B.junior
CC BY-SA 3.0
2017-04-24T11:19:49.717Z
UPDATE: if i delete the "if(lEffect>lCutOff)", the spotlight works as a positional light so I assume that with the "if" construct the code runs always the "else" part and it doesn't compute the part within the "if". By the way, I can't still find what's wrong with the code :_(
B.junior
<lighting><webgl>
WebGL Spotlight
B.junior
# WebGL Spotlight

(Asked by: username_0 on 2017-04-20)

I have to add a spotlight to my rotating cube so this is my code:

HTML

```
        <!DOCTYPE html>
<html>

<button id = "ButtonX">Rotate X</button>
<button id = "ButtonY">Rotate Y</button>
<button id = "ButtonZ">Rotate Z</button>
<button id = "ButtonT">Toggle Rotation</button>

<script id="vertex-shader" type="x-shader/x-vertex">

attribute  vec4 vPosition;
attribute  vec4 vColor;
attribute  vec2 vTexCoord;
attribute  vec3 vNormal;

uniform float shininess;

uniform vec4 posLightPosition;
uniform vec4 posAmbientProduct, posDiffuseProduct,      posSpecularProduct;

uniform vec4 dirLightPosition;
uniform vec4 dirAmbientProduct, dirDiffuseProduct,      dirSpecularProduct;

uniform vec4 spotLightPosition;
uniform vec4 spotAmbientProduct, spotDiffuseProduct,spotSpecularProduct;
uniform vec4 spotLightDirection;
uniform float lCutOff;

varying vec4 fColor;
varying vec2 fTexCoord;

uniform vec3 theta;

void main()
{
    // Compute the sines and cosines of theta for each of
    //   the three axes in one computation.
    vec3 angles = radians( theta );
    vec3 c = cos( angles );
    vec3 s = sin( angles );

    // Remeber: thse matrices are column-major
    mat4 rx = mat4( 1.0,  0.0,  0.0, 0.0,
            0.0,  c.x,  s.x, 0.0,
            0.0, -s.x,  c.x, 0.0,
            0.0,  0.0,  0.0, 1.0 );

    mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
            0.0, 1.0,  0.0, 0.0,
            s.y, 0.0,  c.y, 0.0,
            0.0, 0.0,  0.0, 1.0 );

    mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
            -s.z,  c.z, 0.0, 0.0,
            0.0,  0.0, 1.0, 0.0,
            0.0,  0.0, 0.0, 1.0 );

    vec3 N=normalize((rz*ry*rx*vNormal).xyz);

    // positional light
    vec3 pos=-(rz*ry*rx*vPosition).xyz;
    vec3 posLight=posLightPosition.xyz;
    vec3 posL=normalize(posLight-pos);
    vec3 posE=normalize(-pos);
    vec3 posH=normalize(posL+posE);
    vec4 posAmbient=posAmbientProduct;
    float posKd=max(dot(posL,N),0.0);
    vec4 posDiffuse=posKd*posDiffuseProduct;
    float posKs=pow(max(dot(N,posH),0.0), shininess);
    vec4 posSpecular=posKs*posSpecularProduct;
    if(dot(posL,N)<0.0){
    posSpecular=vec4(0.0,0.0,0.0,1.0);
    }

    // directional light
    vec3 dirLight=dirLightPosition.xyz;
    vec3 dirL=normalize(dirLight);
    vec3 dirE=normalize(-pos);
    vec3 dirH=normalize(dirL+dirE);
    vec4 dirAmbient=dirAmbientProduct;
    float dirKd=max(dot(dirL,N),0.0);
    vec4 dirDiffuse=dirKd*dirDiffuseProduct;
    float dirKs=pow(max(dot(N,dirH),0.0), shininess);
    vec4 dirSpecular=dirKs*dirSpecularProduct;
    if(dot(dirL,N)<0.0){
    dirSpecular=vec4(0.0,0.0,0.0,1.0);
    }

    //spotlight
    vec3 spotLight=spotLightPosition.xyz;
    vec3 spotL=normalize(spotLight);
    vec3 spotE=normalize(-pos);
    vec3 spotH=normalize(spotL+spotE);
    vec3 spotD=spotLightDirection.xyz;
    vec4 spotAmbient=spotAmbientProduct;
    float spotKd=max(dot(spotL,N),0.0);
    vec4 spotDiffuse=spotKd*spotDiffuseProduct;
    float spotKs=pow(max(dot(N,spotH),0.0), shininess);
    vec4 spotSpecular=spotKs*spotSpecularProduct;
    if(dot(spotL,N)<0.0){
    spotSpecular=vec4(0.0,0.0,0.0,1.0);
    }
    float lEffect= dot(normalize(spotD), -spotH);
    if(lEffect>lCutOff)
    {
    vec4 ambient=posAmbient+dirAmbient+spotAmbient;
    vec4 diffuse=posDiffuse+dirDiffuse+spotDiffuse;
    vec4 specular=posSpecular+dirSpecular+spotSpecular;

    fColor = ambient+vColor*(diffuse+specular);
    fColor.a = 1.0;
    }
    else{
    vec4 ambient=posAmbient+dirAmbient;
    vec4 diffuse=posDiffuse+dirDiffuse;
    vec4 specular=posSpecular+dirSpecular;

    fColor = ambient+vColor*(diffuse+specular);
    fColor.a = 1.0;

        }

        fTexCoord = vTexCoord;
    gl_Position = rz * ry * rx * vPosition;
    gl_Position.z = -gl_Position.z;
}
</script>

<script id="fragment-shader" type="x-shader/x-fragment">

precision mediump float;

varying vec4 fColor;
varying  vec2 fTexCoord;

uniform sampler2D Tex0;
uniform sampler2D Tex1;

void
main()
{
    gl_FragColor = fColor*(texture2D(Tex0, fTexCoord)*texture2D(Tex1, fTexCoord));

}
</script>

<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="Homework1.js"></script>

<body>
<canvas id="gl-canvas" width="1024" height="1024">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>

```

JAVASCRIPT

```
"use strict";

var canvas;
var gl;

var numVertices  = 36;

var texSize = 256;
var numChecks = 8;

var program;

var texture1, texture2;
var t1, t2;
var normalsArray = [];

var dirLightPosition = vec4(1.0, 1.0, 1.0, 0.0 );
var dirLightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var dirLightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var dirLightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );

var posLightPosition = vec4(1.0, 1.0, 1.0, 1.0 );
var posLightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var posLightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var posLightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );

var materialAmbient = vec4( 1.0, 0.0, 1.0, 1.0 );
var materialDiffuse = vec4( 1.0, 0.8, 0.0, 1.0 );
var materialSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );
var materialShininess = 20.0;

var spotLightPosition = vec4(1.0, 2.0, 3.0, 1.0 );
var spotLightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var spotLightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var spotLightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );
var spotLightDirection = vec4(-0.5,1.0,2.0,1.0);
var lCutOff=0.867;

var c;

var flag = true;

var image1 = new Uint8Array(4*texSize*texSize);

    for ( var i = 0; i < texSize; i++ ) {
        for ( var j = 0; j <texSize; j++ ) {
            var patchx = Math.floor(i/(texSize/numChecks));
            var patchy = Math.floor(j/(texSize/numChecks));
            if(patchx%2 ^ patchy%2) c = 255;
            else c = 0;
            //c = 255*(((i & 0x8) == 0) ^ ((j & 0x8)  == 0))
            image1[4*i*texSize+4*j] = c;
            image1[4*i*texSize+4*j+1] = c;
            image1[4*i*texSize+4*j+2] = c;
            image1[4*i*texSize+4*j+3] = 255;
        }
    }

var image2 = new Uint8Array(4*texSize*texSize);

    // Create a checkerboard pattern
    for ( var i = 0; i < texSize; i++ ) {
        for ( var j = 0; j <texSize; j++ ) {
            image2[4*i*texSize+4*j] = 127+127*Math.sin(0.1*i*j);
            image2[4*i*texSize+4*j+1] = 127+127*Math.sin(0.1*i*j);
            image2[4*i*texSize+4*j+2] = 127+127*Math.sin(0.1*i*j);
            image2[4*i*texSize+4*j+3] = 255;
           }
    }

var pointsArray = [];
var colorsArray = [];
var texCoordsArray = [];

var texCoord = [
    vec2(0, 0),
    vec2(0, 1),
    vec2(1, 1),
    vec2(1, 0)
];

var vertices = [
    vec4( -0.5, -0.5,  0.5, 1.0 ),
    vec4( -0.5,  0.5,  0.5, 1.0 ),
    vec4( 0.5,  0.5,  0.5, 1.0 ),
    vec4( 0.5, -0.5,  0.5, 1.0 ),
    vec4( -0.5, -0.5, -0.5, 1.0 ),
    vec4( -0.5,  0.5, -0.5, 1.0 ),
    vec4( 0.5,  0.5, -0.5, 1.0 ),
    vec4( 0.5, -0.5, -0.5, 1.0 )
];

var vertexColors = [
    vec4( 0.0, 0.0, 0.0, 1.0 ),  // black
    vec4( 1.0, 0.0, 0.0, 1.0 ),  // red
    vec4( 1.0, 1.0, 0.0, 1.0 ),  // yellow
    vec4( 0.0, 1.0, 0.0, 1.0 ),  // green
    vec4( 0.0, 0.0, 1.0, 1.0 ),  // blue
    vec4( 1.0, 0.0, 1.0, 1.0 ),  // magenta
    vec4( 0.0, 1.0, 1.0, 1.0 ),  // white
    vec4( 0.0, 1.0, 1.0, 1.0 )   // cyan
];

var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = xAxis;

var theta = [45.0, 45.0, 45.0];

var thetaLoc;

function configureTexture() {
    texture1 = gl.createTexture();
    gl.bindTexture( gl.TEXTURE_2D, texture1 );
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, image1);
    gl.generateMipmap( gl.TEXTURE_2D );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
                      gl.NEAREST_MIPMAP_LINEAR );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

    texture2 = gl.createTexture();
    gl.bindTexture( gl.TEXTURE_2D, texture2 );
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, image2);
    gl.generateMipmap( gl.TEXTURE_2D );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
                      gl.NEAREST_MIPMAP_LINEAR );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
}

function quad(a, b, c, d) {

     var t1 = subtract(vertices[b], vertices[a]);
     var t2 = subtract(vertices[c], vertices[b]);
     var normal = cross(t1, t2);
     var normal = vec3(normal);

     pointsArray.push(vertices[a]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[0]);
     normalsArray.push(normal);

     pointsArray.push(vertices[b]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[1]);
     normalsArray.push(normal);

     pointsArray.push(vertices[c]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[2]);
     normalsArray.push(normal);

     pointsArray.push(vertices[a]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[0]);
     normalsArray.push(normal);

     pointsArray.push(vertices[c]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[2]);
     normalsArray.push(normal);

     pointsArray.push(vertices[d]);
     colorsArray.push(vertexColors[a]);
     texCoordsArray.push(texCoord[3]);
     normalsArray.push(normal);
}

function colorCube()
{
    quad( 1, 0, 3, 2 );
    quad( 2, 3, 7, 6 );
    quad( 3, 0, 4, 7 );
    quad( 6, 5, 1, 2 );
    quad( 4, 5, 6, 7 );
    quad( 5, 4, 0, 1 );
}

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 );

    gl.enable(gl.DEPTH_TEST);

    //
    //  Load shaders and initialize attribute buffers
    //
    program = initShaders( gl, "vertex-shader", "fragment-shader" );
    gl.useProgram( program );

    colorCube();

    var nBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );

    var vNormal = gl.getAttribLocation( program, "vNormal" );
    gl.vertexAttribPointer( vNormal, 3, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vNormal );

    var cBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );

    var vColor = gl.getAttribLocation( program, "vColor" );
    gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vColor );

    var vBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer);
    gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );

    var vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vPosition );

    var tBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, tBuffer);
    gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoordsArray), gl.STATIC_DRAW );

    var vTexCoord = gl.getAttribLocation( program, "vTexCoord" );
    gl.vertexAttribPointer( vTexCoord, 2, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vTexCoord );

    var dirAmbientProduct = mult(dirLightAmbient, materialAmbient);
    var dirDiffuseProduct = mult(dirLightDiffuse, materialDiffuse);
    var dirSpecularProduct = mult(dirLightSpecular, materialSpecular);

    var posAmbientProduct = mult(posLightAmbient, materialAmbient);
    var posDiffuseProduct = mult(posLightDiffuse, materialDiffuse);
    var posSpecularProduct = mult(posLightSpecular, materialSpecular);

    var spotAmbientProduct = mult(spotLightAmbient, materialAmbient);
    var spotDiffuseProduct = mult(spotLightDiffuse, materialDiffuse);
    var spotSpecularProduct = mult(spotLightSpecular, materialSpecular);

    configureTexture();

    gl.activeTexture( gl.TEXTURE0 );
    gl.bindTexture( gl.TEXTURE_2D, texture1 );
    gl.uniform1i(gl.getUniformLocation( program, "Tex0"), 0);

    gl.activeTexture( gl.TEXTURE1 );
    gl.bindTexture( gl.TEXTURE_2D, texture2 );
    gl.uniform1i(gl.getUniformLocation( program, "Tex1"), 1);

    thetaLoc = gl.getUniformLocation(program, "theta");

    gl.uniform4fv( gl.getUniformLocation(program,
       "dirAmbientProduct"),flatten(dirAmbientProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posAmbientProduct"),flatten(posAmbientProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotAmbientProduct"),flatten(spotAmbientProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "dirDiffuseProduct"),flatten(dirDiffuseProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posDiffuseProduct"),flatten(posDiffuseProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotDiffuseProduct"),flatten(spotDiffuseProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "dirSpecularProduct"),flatten(dirSpecularProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posSpecularProduct"),flatten(posSpecularProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotSpecularProduct"),flatten(spotSpecularProduct) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "posLightPosition"),flatten(posLightPosition) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "dirLightPosition"),flatten(dirLightPosition) );
    gl.uniform4fv( gl.getUniformLocation(program,
       "spotLightPosition"),flatten(spotLightPosition) );
    gl.uniform1f( gl.getUniformLocation(program,
       "shininess"),materialShininess );
    gl.uniform1f( gl.getUniformLocation(program,
       "lCutOff"),lCutOff );
    gl.uniform1f( gl.getUniformLocation(program,
       "spotLightDirection"),spotLightDirection );

 document.getElementById("ButtonX").onclick = function(){axis = xAxis;};
 document.getElementById("ButtonY").onclick = function(){axis = yAxis;};
 document.getElementById("ButtonZ").onclick = function(){axis = zAxis;};
 document.getElementById("ButtonT").onclick = function(){flag = !flag;};

    render();
}

var render = function() {
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    if(flag) theta[axis] += 2.0;
    gl.uniform3fv(thetaLoc, theta);
    gl.drawArrays( gl.TRIANGLES, 0, numVertices );
    requestAnimFrame(render);
}

```

So I computed tha angle between the spotlight direction and the vector to light source from vertex and if this angle is greater than the cutoff angle defined by the spotlight I compute the three products for the Phong lighting model.

Where am I wrong?

**Tags:** lighting, webgl

> **Comments:**
> **username_1**: What happens when you run it? Can you provide a screenshot as a visual reference?  
> **username_0**: @username_1 I tried with the directional and positional lights turned off and only with the spotlight turned on and the cube appears to be all black, so a scene without lights, so I assumed that the spotlight doesn't work  
> **username_1**: Unfortunately I don't have the time to debug your shader for you, but I would start by removing things from the shader code incrementally until it works and backtrack from there to find the problem. Bugs that cause nothing to render at all are the worst ones to find!  
> **username_0**: I've tried to remove the other two lights but I can't find the bug!  
> **username_1**: Keep removing features (e.g. texturing), one at a time. Maybe try a very simple shader that just makes everything white, then start adding features back once you have something that renders.  
> **username_0**: Yeah I did it, maybe I just need a good reference in order to understand better the use of a spotlight, it's not really clear in the online material that I've found.  
> **username_0**: UPDATE: if i delete the "if(lEffect>lCutOff)", the spotlight works as a positional light so I assume that with the "if" construct the code runs always the "else" part and it doesn't compute the part within the "if". By the way, I can't still find what's wrong with the code :_(  

---

## 0 answers

