OpenGL:Shading/Interpolation 不工作

OpenGL: Shading/Interpolation not working

这段代码的目的是生成一个'surface' 具有随机Y 变化,然后让光源照射它并生成亮度区域并在较暗区域执行阴影。问题是,这并没有真正发生。光要么照亮一侧,要么照亮另一侧,这些侧都均匀地亮或暗。我错过了什么?请记住,还有很多代码尚未删除,但这不是我的首要任务,此时我只是想让着色功能正常运行。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef MAC
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

//Camera variables
int xangle = -270;
int yangle = 0;

//Control Mode (Rotate mode by default)
int mode = 0;

//Player Position (Y offset so it would not be straddling the grid)
float cubeX = 0;
float cubeY = 0.5;

float cubeZ = 0;

//Vertex arrays for surface
float surfaceX [11][11];
float surfaceY [11][11];
float surfaceZ [11][11];

//Surface Normal arrays
float Nx[11][11];
float Ny[11][11];

float Nz[11][11];

//Color arrays
float R[11][11];
float G[11][11];
float B[11][11];

// Material properties
float Ka = 0.2;
float Kd = 0.4;
float Ks = 0.4;
float Kp = 0.5;

//Random number generator
float RandomNumber(float Min, float Max)
{
    return ((float(rand()) / float(RAND_MAX)) * (Max - Min)) + Min;
}

//---------------------------------------
// Initialize material properties
//---------------------------------------
void init_material(float Ka, float Kd, float Ks, float Kp,
                   float Mr, float Mg, float Mb)
{
   // Material variables
   float ambient[] = { Ka * Mr, Ka * Mg, Ka * Mb, 1.0 };
   float diffuse[] = { Kd * Mr, Kd * Mg, Kd * Mb, 1.0 };
   float specular[] = { Ks * Mr, Ks * Mg, Ks * Mb, 1.0 };

   // Initialize material
   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, Kp);
}

//---------------------------------------
// Initialize light source
//---------------------------------------
void init_light(int light_source, float Lx, float Ly, float Lz,
                float Lr, float Lg, float Lb)
{
   // Light variables
   float light_position[] = { Lx, Ly, Lz, 0.0 };
   float light_color[] = { Lr, Lg, Lb, 1.0 };

   // Initialize light source
   glEnable(GL_LIGHTING);
   glEnable(light_source);
   glLightfv(light_source, GL_POSITION, light_position);
   glLightfv(light_source, GL_AMBIENT, light_color);
   glLightfv(light_source, GL_DIFFUSE, light_color);
   glLightfv(light_source, GL_SPECULAR, light_color);
   glLightf(light_source, GL_CONSTANT_ATTENUATION, 1.0);
   glLightf(light_source, GL_LINEAR_ATTENUATION, 0.0);
   glLightf(light_source, GL_QUADRATIC_ATTENUATION, 0.0);
   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}

//---------------------------------------
// Initialize surface 
//---------------------------------------
void init_surface()
{
    //Initialize X, select column  
    for (int i = 0; i < 11; i++) 
    {
        //Select row        
        for (int j = 0; j < 11; j++)
        {   
            surfaceX[i][j] = i-5;
            surfaceY[i][j] = RandomNumber(5, 7) - 5;
            surfaceZ[i][j] = j-5;
            //std::cout << "Coordinate "<< i << "," << j << std::endl;
        }

        //std::cout << "Hello world "<< std::endl;
    }
    //std::cout << "Coordinate -5,-5" << surfaceX[-5][-5] << std::endl;

}

void define_normals()
{
    //Define surface normals
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            //Get two tangent vectors
            float Ix = surfaceX[i+1][j] - surfaceX[i][j];
            float Iy = surfaceY[i+1][j] - surfaceY[i][j];
            float Iz = surfaceZ[i+1][j] - surfaceZ[i][j];
            float Jx = surfaceX[i][j+1] - surfaceX[i][j];
            float Jy = surfaceY[i][j+1] - surfaceY[i][j];
            float Jz = surfaceZ[i][j+1] - surfaceZ[i][j];

      //Get two tangent vectors
      //float Ix = Px[i+1][j] - Px[i][j];
      //float Iy = Py[i+1][j] - Py[i][j];
      //float Iz = Pz[i+1][j] - Pz[i][j];
      //float Jx = Px[i][j+1] - Px[i][j];
      //float Jy = Py[i][j+1] - Py[i][j];
      //float Jz = Pz[i][j+1] - Pz[i][j];

            //Do cross product
            Nx[i][j] = Iy * Jz - Iz * Jy;
            Ny[i][j] = Iz * Jx - Ix * Jz;
            Nz[i][j] = Ix * Jy - Iy * Jx;

            //Nx[i][j] = Nx[i][j] * -1;
            //Ny[i][j] = Ny[i][j] * -1;
            //Nz[i][j] = Nz[i][j] * -1;
            float length = sqrt( 
                Nx[i][j] * Nx[i][j] + 
                Ny[i][j] * Ny[i][j] + 
                Nz[i][j] * Nz[i][j]);
            if (length > 0)
            {
                Nx[i][j] /= length;
                Ny[j][j] /= length;
                Nz[i][j] /= length;
            }
        }   
    } 

    //std::cout << "Surface normal for 0,0: "<< Nx[0][0] << "," << Ny[0][0] << "," << Nz[0][0] << std::endl;

}

void calc_color()
{
    for (int i = 0; i < 10; i++)
    {           
        for (int j = 0; j < 10; j++)
        {
            //Calculate light vector
            //Light position, hardcoded for now 0,1,1
            float Lx = -1 - surfaceX[i][j]; 
            float Ly = -1 - surfaceY[i][j];
            float Lz = -1 - surfaceZ[i][j];
            std::cout << "Lx: " << Lx << std::endl; 
            std::cout << "Ly: " << Ly << std::endl;
            std::cout << "Lz: " << Lz << std::endl;

            //Grab surface normals
            //These are Nx,Ny,Nz due to compiler issues
            float Na = Nx[i][j];
            float Nb = Ny[i][j];
            float Nc = Nz[i][j];

            std::cout << "Na: " << Na << std::endl; 
            std::cout << "Nb: " << Nb << std::endl; 
            std::cout << "Nc: " << Nc << std::endl; 
            //Do cross product
            float Color = (Na * Lx) + (Nb * Ly) + (Nc * Lz);
            std::cout << "Color: " << Color << std::endl;

            //Color = Color * -1;
            R[i][j] = Color;
            G[i][j] = Color;
            B[i][j] = Color;

            //std::cout << "Color Value: " << std::endl;
            ////std::cout << "R: " << R[i][j] << std::endl;
            //std::cout << "G: " << G[i][j] << std::endl;
            //std::cout << "B: " << B[i][j] << std::endl;
        }

    }
}



//---------------------------------------
// Init function for OpenGL
//---------------------------------------
void init()
{
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //Viewing Window Modified
    glOrtho(-7.0, 7.0, -7.0, 7.0, -7.0, 7.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    //Rotates camera
    //glRotatef(30.0, 1.0, 1.0, 1.0);
    glEnable(GL_DEPTH_TEST);

    //Project 3 code
    init_surface();
    define_normals();

    //Shading code
    glShadeModel(GL_SMOOTH);
    glEnable(GL_NORMALIZE);
    init_light(GL_LIGHT0, 0, 1, 1, 0.5, 0.5, 0.5);
    //init_light(GL_LIGHT1, 0, 0, 1, 0.5, 0.5, 0.5);
    //init_light(GL_LIGHT2, 0, 1, 0, 0.5, 0.5, 0.5);


}

void keyboard(unsigned char key, int x, int y)
{
    //Controls
    //Toggle Mode  
    if (key == 'q')
    {
        if(mode == 0)
        {       
            mode = 1;
            std::cout << "Switched to Move mode (" << mode << ")" << std::endl; 
        }
        else if(mode == 1)
        {   
            mode = 0;
            std::cout << "Switched to Rotate mode (" << mode << ")" << std::endl;
        }
    }

    ////Rotate Camera (mode 0)
    //Up & Down
    else if (key == 's' && mode == 0)
        xangle += 5;
    else if (key == 'w' && mode == 0)
    xangle -= 5;

    //Left & Right
    else if (key == 'a' && mode == 0) 
    yangle -= 5;
    else if (key == 'd' && mode == 0) 
    yangle += 5;

    ////Move Cube (mode 1)
    //Forward & Back
    else if (key == 'w' && mode == 1) 
    {
        if (cubeZ > -5)
        cubeZ = cubeZ - 1;
        else
        std::cout << "You have struck an invisible wall! (Min Z bounds)" << std::endl;
    }

    else if (key == 's' && mode == 1)
    {
        if (cubeZ < 5)
        cubeZ = cubeZ + 1;
        else
        std::cout << "You have struck an invisible wall! (Max Z bounds)" << std::endl;
    }

    //Strafe
    else if (key == 'd' && mode == 1)
    {
        if (cubeX < 5)      
        cubeX = cubeX + 1;
        else
        std::cout << "You have struck an invisible wall! (Max X bounds)" << std::endl;  
    }
    else if (key == 'a' && mode == 1)
    {
        if (cubeX > -5)     
        cubeX = cubeX - 1;
        else
        std::cout << "You have struck an invisible wall! (Min X bounds)" << std::endl;  
    }   

    //Up & Down (Cube offset by +0.5 in Y)
    else if (key == 'z' && mode == 1)
    {
        if (cubeY < 5)
        cubeY = cubeY + 1;
        else
        std::cout << "You've gone too high! Come back! (Max Y bounds)" << std::endl;
    }
    else if (key == 'x' && mode == 1)
    {
        if (cubeY > 0.5)
        cubeY = cubeY - 1;
        else
        std::cout << "You've reached bedrock! (Min Y bounds)" << std::endl;
    }
    //Place/Remove block
    else if (key == 'e' && mode == 1)
    {
        //Occupied(cubeX,cubeY,cubeZ);
    }

    //Redraw objects
    glutPostRedisplay();
}


//---------------------------------------
// Display callback for OpenGL
//---------------------------------------
void display()
{       
        // Clear the screen
    //std::cout << "xangle: " << xangle << std::endl;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //Rotation Code
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRotatef(xangle, 1.0, 0.0, 0.0);
    glRotatef(yangle, 0.0, 1.0, 0.0);

    //Light Code
    init_material(Ka, Kd, Ks, 100 * Kp, 0.8, 0.6, 0.4); 

    calc_color();




    //Draw the squares, select column  
    for (int i = 0; i <= 9; i++)
    {
        //Select row        
        for (int j = 0; j <= 9; j++)
        {   
            glBegin(GL_POLYGON); 
            //Surface starts at top left
            //Counter clockwise

// CALCULATE COLOR HERE
// - calculate direction from surface to light
// - calculate dot product of normal and light direction vector
// - call glColor function





            //Calculate light vector
            //Light position, hardcoded for now 0,1,1
            ///float Lx = 0 - surfaceX[i][j]; 
            //float Ly = 1 - surfaceY[i][j];
            //float Lz = 1 - surfaceZ[i][j];

            //Grab surface normals
            //These are Nx,Ny,Nz due to compiler issues
            //float Na = Nx[i][j];
            //float Nb = Ny[i][j];
            //float Nc = Nz[i][j];

            //Do cross product
            //float Color = (Na * Lx) + (Nb * Ly) + (Nc * Lz);

            //???           
            //glColor3fv(Color);
            //glColor3f(0.5*Color,0.5*Color,0.5*Color);

            glColor3f(R[i][j], G[i][j], B[i][j]);
            glVertex3f(surfaceX[i][j], surfaceY[i][j], surfaceZ[i][j]);

            glColor3f(R[i][j+1], G[i][j+1], B[i][j+1]);
            glVertex3f(surfaceX[i][j+1], surfaceY[i][j+1], surfaceZ[i][j+1]);

            glColor3f(R[i+1][j+1], G[i+1][j+1], B[i+1][j+1]);
            glVertex3f(surfaceX[i+1][j+1], surfaceY[i+1][j+1], surfaceZ[i+1][j+1]);

            glColor3f(R[i+1][j], G[i+1][j], B[i+1][j]);
            glVertex3f(surfaceX[i+1][j], surfaceY[i+1][j], surfaceZ[i+1][j]);

            glEnd();
        }
    }

    //Draw the normals
    for (int i = 0; i <= 10; i++)
    {
        for (int j = 0; j <= 10; j++)
        {

            glBegin(GL_LINES);
            //glColor3f(0.0, 1.0, 1.0);
            float length = 1;
            glVertex3f(surfaceX[i][j], surfaceY[i][j], surfaceZ[i][j]);
                glVertex3f(surfaceX[i][j]+length*Nx[i][j], 
                surfaceY[i][j]+length*Ny[i][j], 
                surfaceZ[i][j]+length*Nz[i][j]);
            glEnd();
        }
    }
    glEnd();
    glFlush();


    //Player Cube
    //Cube: midx, midy, midz, size
    //+Z = Moving TOWARD camera in opengl

    //Origin point for reference
    glPointSize(10);
    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_POINTS);
    glVertex3f(0, 0, 0);        
    glEnd();

    //Assign Color of Lines
    float R = 1;
    float G = 1;
    float B = 1;
    glBegin(GL_LINES);
    glColor3f(R, G, B);

    ////Drawing the grid
    //Vertical lines
    for (int i = 0; i < 11; i++)
    {
        int b = -5 + i;

        glVertex3f(b, 0, -5);
        glVertex3f(b, 0, 5);
    }

    //Horizontal lines
    for (int i = 0; i < 11; i++)
    {
        int b = -5 + i;
        glVertex3f(-5,0,b);
        glVertex3f(5,0,b);

    }
    glEnd();


    glEnd();
    glFlush();  
}




//---------------------------------------
// Main program
//---------------------------------------
int main(int argc, char *argv[])
{

    srand(time(NULL));

    //Print Instructions
    std::cout << "Project 3 Controls: " << std::endl;
    std::cout << "q switches control mode" << std::endl;
    std::cout << "w,a,s,d for camera rotation" << std::endl;


    //Required
    glutInit(&argc, argv);
    //Window will default to a different size without
    glutInitWindowSize(500, 500);
    //Window will default to a different position without
    glutInitWindowPosition(250, 250);
    //
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
    //Required
    glutCreateWindow("Project 3");
    //Required, calls display function
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);

    //Required
    init();
    glutMainLoop();



   return 0;
}

正在生成表面和法线以及给定顶点的颜色,我只是不明白为什么它不起作用。

表面的光线或亮度是入射光矢量、观察方向和表面法线矢量的函数。 您在渲染平面时错过了设置法线矢量属性。通过glNormal设置法向量属性,在指定顶点坐标之前:

for (int i = 0; i <= 9; i++)
{
    for (int j = 0; j <= 9; j++)
    {   
        glBegin(GL_POLYGON); 

        glColor3f(R[i][j], G[i][j], B[i][j]);
        glNormal3f(Nx[i][j], Ny[i][j], Nz[i][j]);
        glVertex3f(surfaceX[i][j], surfaceY[i][j], surfaceZ[i][j]);

        glColor3f(R[i][j+1], G[i][j+1], B[i][j+1]);
        glNormal3f(Nx[i][j+1], Ny[i][j+1], Nz[i][j+1]);
        glVertex3f(surfaceX[i][j+1], surfaceY[i][j+1], surfaceZ[i][j+1]);

        glColor3f(R[i+1][j+1], G[i+1][j+1], B[i+1][j+1]);
        glNormal3f(Nx[i+1][j+1], Ny[i+1][j+1], Nz[i+1][j+1]);
        glVertex3f(surfaceX[i+1][j+1], surfaceY[i+1][j+1], surfaceZ[i+1][j+1]);

        glColor3f(R[i+1][j], G[i+1][j], B[i+1][j]);
        glNormal3f(Nx[i+1][j], Ny[i+1][j], Nz[i+1][j]);
        glVertex3f(surfaceX[i+1][j], surfaceY[i+1][j], surfaceZ[i+1][j]);

        glEnd();
    }
}  

但请注意,由于 Gouraud shading of the Legacy OpenGL 标准灯光模型,灯光质量会很低。
另见 .


此外,法向量是反转的。您可以通过交换叉积中的向量来改变方向:

Nx[i][j] = Iz * Jy - Iy * Jz;
Ny[i][j] = Ix * Jz - Iz * Jx;
Nz[i][j] = Iy * Jx - Ix * Jy; 

旁注:

请注意,glBegin/glEnd sequences, the fixed function matrix stack and fixed function, per vertex light model, is deprecated since decades. See Fixed Function Pipeline and Legacy OpenGL 绘制的那幅画。 阅读 Vertex Specification and Shader 了解最先进的渲染方式。