OpenGL: затенение / интерполяция не работает - PullRequest
1 голос
/ 13 марта 2019

Цель этого кода - сгенерировать «поверхность» со случайным изменением 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;
}

Генерируются как поверхность, так и нормали, а также цвет для данной вершины, я просто не понимаю, почему она не работает.

1 Ответ

1 голос
/ 13 марта 2019

Свет или яркость поверхности зависит от вектора падающего света, направления обзора и вектора нормали поверхности. Вы пропустили установку атрибутов нормального вектора при рендеринге плоскости. Установите атрибут вектора нормали 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();
    }
}  

Но учтите, что качество света будет низким из-за затенения Гуро стандартной модели освещения Legacy OpenGL .
См. Также OpenGL Освещение на текстурной плоскости не работает .


Кроме того, нормальные векторы инвертированы. Вы можете изменить направление, меняя векторы в перекрестном произведении:

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

Примечание:

Обратите внимание, что рисование с помощью glBegin / glEnd последовательностей, стека с фиксированной матрицей функций и фиксированной функции для каждой модели освещения вершины считается устаревшим с десятилетий. См. конвейер с фиксированными функциями и Legacy OpenGL . Прочитайте о Vertex Specification и Shader , чтобы узнать о современном способе рендеринга.

...