Search code examples
htmlwebgllightshading

Switching Gouraud and Phong Shading


I'm writing an application where I need to switch these two shading techniques.

The program starts applying the Gouraud shading , and there are no problem.

When I click the button to switch the shading my object (a rotating cube) became all violet , like there is no light. Does anyone see the problem ?

Gouraud Shading Phong Shading

Here is the code :

JavaScript

"use strict";

var canvas;
var gl;

var numVertices  = 36;

var numChecks = 8;

var program;
var program2;

var c;

var flag = true;

var direction = true;

var rx;
var ry;
var rz;
var traslation_loc;
var tx = 0 ;
var ty = 0;
var tz = 0;
var scaling_loc;
var sx = 1.0;
var sy = 1.0;
var sz = 1.0;

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





//Point 4
// cambia eventualmente near e far per vedere gli effetti
var near = 0.3;
var far = 3.0;


var phi    = 0.0;
var radius = 1.5;
var left = -1.0;
var right = 1.0;
var ytop = 1.0;
var bottom = -1.0;

var mvMatrix, pMatrix;
var modelView, projection;
var eye;

const at = vec3(0.0, 0.0, 0.0);
const up = vec3(0.0, 1.0, 0.0);

//var eye = vec3(1, 1, 1);
//var eye = vec3(0.02, 0.02, 0.02);
//

//Point 5
var fovy = 45.0;
var aspect;
var orthoBool = true;
var aspect = 1.0;
//


//Poinit 6
var lightAmbient = vec4(0.2, 0.2, 0.2, 1.0);
var lightDiffuse = vec4(1.0, 1.0, 1.0, 1.0);
var lightSpecular = vec4(1.0, 1.0, 1.0, 1.0);
var lightPosition = vec4(0.3, 0.2, 0.8,0.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, 0.8, 0.0, 1.0);
var materialShininess = 100.0;

var normalsArray = [];

// Point 7
var changeShading = true;



//


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




/* rimossi per il punto 6
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 quad(a, b, c, d) {

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

    //*** Abbiamo rimpizzato i colori on queli del materiale per svolgere il punto 6

     pointsArray.push(vertices[a]);
     //colorsArray.push(vertexColors[a]);
     normalsArray.push(normal);

     pointsArray.push(vertices[b]);
     //colorsArray.push(vertexColors[a]);
     normalsArray.push(normal);

     pointsArray.push(vertices[c]);
     //colorsArray.push(vertexColors[a]);
     normalsArray.push(normal);

     pointsArray.push(vertices[a]);
     //colorsArray.push(vertexColors[a]);
     normalsArray.push(normal);

     pointsArray.push(vertices[c]);
     //colorsArray.push(vertexColors[a]);
     normalsArray.push(normal);

     pointsArray.push(vertices[d]);
     //colorsArray.push(vertexColors[a]);
     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 );

    // Point 5 -> define aspect
    aspect = 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();


    //Point 6

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


    //*************
    // RIMPIAZZATI I COLORI PER IL PUNTO 6
    //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 );

    // Possiamo commentare quello che riguarda il theta per il punto 2
    //thetaLoc = gl.getUniformLocation(program, "theta");

    // Point 2 - Rotation

    //X AXIS

    rx = gl.getUniformLocation(program, "rx");


    //Y AXIS

    ry = gl.getUniformLocation(program, "ry");



    //Z AXIS

     rz = gl.getUniformLocation(program, "rz");


    // Traslation Matrix

    traslation_loc = gl.getUniformLocation(program , "traslation");

    // Scaling Matrix

    scaling_loc = gl.getUniformLocation(program , "scaling");

    // Projection and Model matrix
    modelView = gl.getUniformLocation( program, "modelView" );
    projection = gl.getUniformLocation( program, "projection" );


    //**************


 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;};
 document.getElementById("Direction").onclick = function() { direction = !direction;};
 document.getElementById( "slideX" ).oninput = function(){ tx = parseFloat(event.target.value,10); };
 document.getElementById( "slideY" ).oninput = function(){ ty = parseFloat(event.target.value,10); };
 document.getElementById( "slideZ" ).oninput = function(){ tz = parseFloat(event.target.value,10); };
 document.getElementById( "ScalingX" ).oninput = function(){ sx = parseFloat(event.target.value,10); };
 document.getElementById( "ScalingY" ).oninput = function(){ sy = parseFloat(event.target.value,10); };
 document.getElementById( "ScalingZ" ).oninput = function(){ sz = parseFloat(event.target.value,10); };

 // Point 5
 document.getElementById("OrthoPersp").onclick = function(){orthoBool = !orthoBool;};

 // Point 4

    // per documentazine leggi la parte sotto il codice a pag 244 con spiegazione sul clip out
    // cambiato inserito due sliders // perspective -> ortho -> + lontano


    document.getElementById("zFarSlider").onchange = function() {
        far = event.srcElement.value;
    };

    document.getElementById("zNearSlider").onchange = function() {
        near = event.srcElement.value;
    };

    // POINT 7

    document.getElementById("ShadingButton").onclick = function(){changeShading = !changeShading;};

    //Point 6

    var ambientProduct = mult(lightAmbient, materialAmbient);
    var diffuseProduct = mult(lightDiffuse, materialDiffuse);
    var specularProduct = mult(lightSpecular, materialSpecular);

    gl.uniform4fv(gl.getUniformLocation(program, "ambientProduct"),
                  flatten(ambientProduct));
    gl.uniform4fv(gl.getUniformLocation(program, "diffuseProduct"),
                  flatten(diffuseProduct) );
    gl.uniform4fv(gl.getUniformLocation(program, "specularProduct"),
                  flatten(specularProduct) );
    gl.uniform4fv(gl.getUniformLocation(program, "lightPosition"),
                  flatten(lightPosition) );
    gl.uniform1f(gl.getUniformLocation(program, "shininess"),materialShininess);

    //*************************************









    render();
}








var render = function() {
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);


    // Point 4
    //*************************************
    //eye = vec3(radius*Math.sin(phi), radius*Math.sin(theta),
              // radius*Math.cos(phi)); RIMANE COMMENTATO

    //mvMatrix = lookAt(eye, at , up);
    //pMatrix = ortho(left, right, bottom, ytop, near, far);

    //gl.uniformMatrix4fv( modelView, false, flatten(mvMatrix) );
    //gl.uniformMatrix4fv( projection, false, flatten(pMatrix) );


    //*************************************


    //Point 7
    gl.uniform1f(gl.getUniformLocation(program, "changeShading"),changeShading);





    // Point 3 -> Scaling

    var scaling = [sx , 0.0 , 0.0 , 0.0,
                   0.0  , sy, 0.0 , 0.0,
                   0.0 , 0.0 , sz , 0.0,
                   0.0 , 0.0 , 0.0 , 1];
    gl.uniformMatrix4fv(scaling_loc,false,scaling);


    // ****************************************
    //X AXIS - Point 2
    var theta_x_degree  = theta[0];
    var theta_x_radians = theta_x_degree * Math.PI / 180;
    var s_x = Math.sin(theta_x_radians);
    var c_x = Math.cos(theta_x_radians);
    var rx_loc = [ 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 ];
    gl.uniformMatrix4fv(rx, false, rx_loc);

    //Y AXIS - Point 2
    var theta_y_degree  = theta[1];
    var theta_y_radians = theta_y_degree * Math.PI / 180;
    var s_y = Math.sin(theta_y_radians);
    var c_y = Math.cos(theta_y_radians);
    var ry_loc = [ 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 ];
    gl.uniformMatrix4fv(ry, false, ry_loc);


    //Z AXIS - Point 2
    var theta_z_degree  = theta[2];
    var theta_z_radians = theta_z_degree * Math.PI / 180;
    var s_z = Math.sin(theta_z_radians);
    var c_z = Math.cos(theta_z_radians);
    var rz_loc = [ 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  ];
    gl.uniformMatrix4fv(rz, false, rz_loc);

    // ****************************************

    // Point 3 -> Traslation

    var traslation = [1.0 , 0.0 , 0.0 , 0.0,
                      0.0 , 1.0 , 0.0 , 0.0,
                      0.0 , 0.0 , 1.0 , 0.0,
                       tx , ty , tz , 1.0];

    gl.uniformMatrix4fv(traslation_loc,false,traslation);


    // ****************************************

    //Point 4-5
    //*************************************
    //eye = vec3(0.02, 0.02, 0.02); // se lasciassi questo , non mi si sposterebbero le normali per la luce
    eye = vec3(radius*Math.sin(theta_x_radians)*Math.cos(phi),
               radius*Math.sin(theta_y_radians)*Math.sin(phi), radius*Math.cos(theta_z_radians));

    mvMatrix = lookAt(eye, at , up);

    if (orthoBool) {
        pMatrix = ortho(left, right, bottom, ytop, near, far); }
    else {
        pMatrix=perspective(fovy , aspect , near , far); }

    gl.uniformMatrix4fv( modelView, false, flatten(mvMatrix) );
    gl.uniformMatrix4fv( projection, false, flatten(pMatrix) );


    //*************************************


    // ****************************************

    // Point 1 --> Change and Toggle Rotation
    if((direction)&&(!flag)) theta[axis] += -1.0;
    if((!direction)&&(!flag)) theta[axis] += +1.0;

    if(!direction) {theta[axis] += -1.0; }
    if(direction) {theta[axis] += 1.0 ; }

    // ****************************************

    //gl.uniform3fv(thetaLoc, theta);
    gl.drawArrays( gl.TRIANGLES, 0, numVertices );
    requestAnimFrame(render);
}

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>
    <button id="Direction">Change Direction</button>
    <button id="OrthoPersp">Change Parall/Persp</button>
    <button id="ShadingButton">Change Shading</button>


    <div>Traslation on X  <input id="slideX" type="range"
        min="-1" max="1" step="0.1" value="0" />
    </div>

    <div>Traslation on Y  <input id="slideY" type="range"
        min="-1" max="1" step="0.1" value="0" />
    </div>

    <div>Traslation on Z  <input id="slideZ" type="range"
        min="-1" max="1" step="0.1" value="0" />
    </div>

    <div>Scaling on X  <input id="ScalingX" type="range"
        min="0" max="1" step="0.1" value="0" />
    </div>
    <div>Scaling on Y <input id="ScalingY" type="range"
        min="0" max="1" step="0.1" value="0" />
    </div>
    <div>Scaling on Z  <input id="ScalingZ" type="range"
        min="0" max="1" step="0.1" value="0" />
    </div>

    <div>
        zNear Min<input id="zNearSlider" type="range" min="0.00" max="2.8" step="0.1" value="0.3">
            Max
            </div>

    <div>
        zFar Min<input id="zFarSlider" type="range" min="3" max="10" step="3.0" value="3">
            Max
            </div>







    <script id="vertex-shader" type="x-shader/x-vertex">
        precision mediump float;
        attribute  vec4 vPosition;
        attribute  vec4 vColor;

        varying vec4 fColor;

        //uniform vec3 theta;

        // Point 2 -> Move the matrices
        // Per spostare le matrici le abbiamo dovuto dichiarare nel file GLSL come uniform
        // le matrici rx ry e rz sono rispettivamente le matrici di rotazione sugli assi
        uniform mat4 rx;
        uniform mat4 ry;
        uniform mat4 rz;

        // Points 3 -> Traslation Matrix
        uniform mat4 traslation;
        // Points 3 -> Scaling Matrix
        uniform mat4 scaling;

        //Point 4 -> MV and P matrices
        uniform mat4 modelView;
        uniform mat4 projection;

        //Poinit 6 -> Light Source

        attribute vec4 vNormal;
        uniform vec4 ambientProduct, diffuseProduct, specularProduct;
        uniform vec4 lightPosition;
        uniform float shininess;
        varying vec3 N,L,E;
        uniform bool changeShading;

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

            // Remember: the 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 );
             */

            //fColor = vColor;
            // ORDINE : scaling -> rotazione -> traslation

            //gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
            //gl_Position.z = -gl_Position.z;

            //Point 6
            vec3 pos = -(modelView * vPosition).xyz;
            if(changeShading) {
                vec3 light = lightPosition.xyz;
                vec3 L = normalize( light - pos );
                vec3 E = normalize( -pos );
                vec3 H = normalize( L + E );
                vec3 N = normalize( (modelView*vNormal).xyz);

                vec4 ambient = ambientProduct;

                float Kd = max( dot(L, N), 0.0 );
                vec4 diffuse = Kd*diffuseProduct;

                float Ks = pow( max(dot(N, H), 0.0), shininess );
                vec4 specular = Ks * specularProduct;

                if( dot(L, N) < 0.0 ) {
                    specular = vec4(0.0, 0.0, 0.0, 1.0);
                }

                fColor = ambient + diffuse + specular;
                fColor.a = 1.0;


                gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
                gl_Position.z = -gl_Position.z;
            }
            else {
                vec3 light = lightPosition.xyz;
                vec3 L = normalize( light - pos );
                vec3 E = normalize( -pos );
                vec3 H = normalize( L + E );
                vec3 N = normalize( (modelView*vNormal).xyz);
                gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
                gl_Position.z = -gl_Position.z;
            }



            // *******************

        }
    </script>

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

        precision mediump float;
        varying  vec4 vPosition;
        varying  vec4 vColor;

        varying vec4 fColor;
        uniform mat4 rx;
        uniform mat4 ry;
        uniform mat4 rz;


        uniform mat4 traslation;

        uniform mat4 scaling;


        uniform mat4 modelView;
        uniform mat4 projection;



        varying vec4 vNormal;
        uniform vec4 ambientProduct, diffuseProduct, specularProduct;
        uniform vec4 lightPosition;
        uniform float shininess;
        varying vec3 N,L,E;
        uniform bool changeShading;

        void main()
        {
            if(changeShading) {gl_FragColor = fColor;}
            else {vec4 fColor;
                vec3 H = normalize( L + E );
                vec4 ambient = ambientProduct;
                float Kd = max( dot(L, N), 0.0 );
                vec4 diffuse = Kd*diffuseProduct;
                float Ks = pow( max(dot(N, H), 0.0), shininess );
                vec4 specular = Ks * specularProduct;
                if( dot(L, N) < 0.0 ) specular = vec4(0.0, 0.0, 0.0, 1.0);
                fColor = ambient + diffuse +specular;
                fColor.a = 1.0;
                gl_FragColor = fColor;}

        }
    </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>

Solution

  • In the vertex shader are declared the varying (output) variables N, L, E. But they are never set, because there are identically named local variables which are set. This causes that the values of the varying (input) variables N, L, E in the fragment shader are always (0, 0, 0).

    The issue can be fixed by removing the declaration of the local variables and setting the varying outputs:

    L = normalize( light - pos );
    E = normalize( -pos );
    N = normalize( (modelView*vNormal).xyz);