OpenGL Światło

0

Witam. Od niedawnego czasu uczę się opengl'a. Napisałem prostego snake i chciałbym aby w kierunku jego poruszanie się padało światło (coś w stylu jak światła samochodu). Nie wiem jak obracać światłem. Wiem pytanie pewnie łatwe ale męczę się z tym od wczoraj :/ Aplikacja w załączniku Oto kod:

#include <GL/glut.h>
#include <stdlib.h>
#include <deque>
#include <ctime>
#include <cmath>
#include <StopWatch.h>
#include <OGLMaterials.h>
#include <OGLcolors.h>
#include <iostream>
using namespace std;

const unsigned int Width = 1024;
const unsigned int Height = 768;

const double ViewLeft = 10;
const double ViewRight = 10;
const double ViewBottom = 10;
const double ViewTop = 10;
const double ViewNear = 40;
const double ViewFar = 80;

const double FieldSize = 10;

enum KEYS{ UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4, PAUSE = 'P' };
KEYS LastKey = UP;

struct Wspolrzedne{ int x,z; };

std::deque <Wspolrzedne> Snake;
Wspolrzedne Award;

void GameReset();
void RenderScene();
void Keyboard( unsigned char key, int x, int y );
void KeyEvent(int key, int x, int y);
void ResizeWindow(int w, int h);
void SnakeDraw();
void GenerateFloorList();
void WallDraw();
void AwardDraw();
void setAward();
void moveSnake();
void checkCollisionSnake_Snake();
void checkCollisionSnake_Award();
void checkCollisionSnake_Wall();
void checkGame();
void cubeDraw();

bool bIsAward = false;
bool bGameIsGood = false;

static CStopWatch Timer;
float SnakeSpeed = 0.3;
float Scores = 0;

GLint Lista_Podlogi;

int main(int argc, char *argv[])
{
    ///inicjalizacja okna programu itp.
    glutInit(&argc, argv);
    glutInitWindowSize(Width,Height);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
    glutCreateWindow("3D Snake!");

    glutDisplayFunc(RenderScene);
    glutReshapeFunc(ResizeWindow);
    glutSpecialFunc(KeyEvent);
    glutKeyboardFunc(Keyboard);

    GenerateFloorList();

    glutMainLoop();

    return EXIT_SUCCESS;
}

void GameReset()
{
    setAward();
    Snake.clear();
    Wspolrzedne temporary;
    temporary.x = 0;
    temporary.z = 0;
    Snake.push_back(temporary);
    temporary.z = 1;
    Snake.push_back(temporary);
    temporary.z = 2;
    Snake.push_back(temporary);
    bGameIsGood = true;
    Scores = 0;
    SnakeSpeed = 0.3;
    LastKey = UP;
}

void checkGame()
{
    if (!bGameIsGood){
        GameReset();
    }

    if (!bIsAward){
        setAward();
    }

    if ( Timer.GetElapsedSeconds() >= SnakeSpeed ){
        checkCollisionSnake_Wall();
        checkCollisionSnake_Award();
        checkCollisionSnake_Snake();
        moveSnake();
        Timer.Reset();
    }

    glutPostRedisplay();
}

void setAward()
{
    srand(time(NULL));
    Award.x = (rand() % 20) - 10;
    Award.z = (rand() % 20) - 10;
    bIsAward = true;
}

void SnakeDraw()
{
    ///Glowa weza
    glColor3fv(CornflowerBlue);
    glPushMatrix();
    glTranslatef(Snake[0].x+0.5,0.5,Snake[0].z+0.5);
    glScalef(0.5,0.5,0.5);
    cubeDraw();
    glColor3fv(LimeGreen);
    glTranslatef(0.0,1.5,0.0);
    glutWireSphere(0.5,30,15);
    glPopMatrix();
    ///Cialo weza
    glColor3fv(PowderBlue);
    for (int i = 1; i < Snake.size(); ++i){
        if (i == Snake.size() - 1)
            glColor3fv(LightSkyBlue);
        glPushMatrix();
        glTranslatef(Snake[i].x+0.5,0.5,Snake[i].z+0.5);
        glScalef(0.5,0.5,0.5);
        cubeDraw();
        glPopMatrix();
    }
}

void GenerateFloorList()
{
    Lista_Podlogi = glGenLists( 1 );

    glNewList(Lista_Podlogi, GL_COMPILE);

    glBegin(GL_QUADS);
    glNormal3f(1.0,0.0,0.0);

    for (float x = -FieldSize; x <FieldSize; x += 1.0f){
        for (float z = -FieldSize; z <FieldSize; z +=1.0f){
            glColor4f( Blue[ 0 ], Blue[ 1 ], Blue[ 2 ], 0.5 );
            glVertex3f( x + 0.0, 0.0, z + 0.0 );
            glVertex3f( x + 0.0, 0.0, z + 0.5 );
            glVertex3f( x + 0.5, 0.0, z + 0.5 );
            glVertex3f( x + 0.5, 0.0, z + 0.0 );
            glColor4f( Silver[ 0 ], Silver[ 1 ], Silver[ 2 ], 0.7 );
            glVertex3f( x + 0.5, 0.0, z + 0.0 );
            glVertex3f( x + 0.5, 0.0, z + 0.5 );
            glVertex3f( x + 1.0, 0.0, z + 0.5 );
            glVertex3f( x + 1.0, 0.0, z + 0.0 );
            glColor4f( Blue[ 0 ], Blue[ 1 ], Blue[ 2 ], 0.5 );
            glVertex3f( x + 0.5, 0.0, z + 0.5 );
            glVertex3f( x + 0.5, 0.0, z + 1.0 );
            glVertex3f( x + 1.0, 0.0, z + 1.0 );
            glVertex3f( x + 1.0, 0.0, z + 0.5 );
            glColor4f( Silver[ 0 ], Silver[ 1 ], Silver[ 2 ], 0.7 );
            glVertex3f( x + 0.0, 0.0, z + 0.5 );
            glVertex3f( x + 0.0, 0.0, z + 1.0 );
            glVertex3f( x + 0.5, 0.0, z + 1.0 );
            glVertex3f( x + 0.5, 0.0, z + 0.5 );
        }
    }
    glEnd();

    glEndList();
}

void WallDraw()
{
    glColor3fv(Sienna);

    glPushMatrix();
    ///tyl
    for (int x = -FieldSize; x <= FieldSize + 1; ++x ){
        for (int y = 0; y < 10; ++y){
            glPushMatrix();

            glTranslatef(x - 0.5, y+0.5,-FieldSize -0.5 );
            glScalef(0.5,0.5,0.5);

            glBegin(GL_TRIANGLES);
            cubeDraw();
            glEnd();
            glPopMatrix();
        }
    }
    ///lewa i prawa
    for (int z = -FieldSize; z <= FieldSize; ++z ){
        for (int y = 0; y < 10; ++y){
            glPushMatrix(); ///lewa
            glTranslatef(-FieldSize-0.5, y+0.5, z-0.5 );
            glScalef(0.5,0.5,0.5);
            glBegin(GL_TRIANGLES);
            cubeDraw();
            glEnd();
            glPopMatrix();
            glPushMatrix(); ///prawa
            glTranslatef(FieldSize+0.5, y+0.5, z - 0.5);
            glScalef(0.5,0.5,0.5);
            glBegin(GL_TRIANGLES);
            cubeDraw();
            glEnd();
            glPopMatrix();
        }
    }
}

void AwardDraw()
{
    static float rot = 0;
    rot += Timer.GetElapsedSeconds();

    glPushMatrix();

    glColor3fv(GreenYellow);

    glPushMatrix();
    glTranslatef(Award.x+0.5,0.5,Award.z+0.5);
    glRotatef(rot*20,1,1,1);
    glutWireSphere(0.5,16,8);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(Award.x+0.5,0.5,Award.z+0.5);
    glTranslatef(0.0,2.0,0.0);
    glRotatef(rot*20,0,1,0);
    glRotatef(90,1,0,0);
    glColor3fv(Red);
    glutWireCone(0.5,1.0,16,8);
    glPopMatrix();

    glPopMatrix();
}

void RenderScene()
{
    GLfloat light_direction[3] =
    {
        0.0,0.0,-1.0
    };

    glClearColor(0.0,0.1,0.1,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glPushMatrix();
    glLoadIdentity();

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );

    glTranslatef( 0, 0, -( ViewNear + ViewFar ) / 2 );

    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glLightf( GL_LIGHT0, GL_SPOT_CUTOFF, 90.0);
    glLightf( GL_LIGHT0, GL_SPOT_EXPONENT, 0);
    glLightf( GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.5);
    glLightf( GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.4);
    glLightf( GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0);
    glLightfv( GL_LIGHT0, GL_SPOT_DIRECTION, light_direction );

    glPushMatrix();
    glScalef(1,1,1);
    GLfloat light_position[ 4 ] = { Snake[0].x,0,Snake[0].z, 1 };
    glLightfv( GL_LIGHT0, GL_POSITION, light_position );
    glPopMatrix();

    glEnable(GL_LIGHT0);

    glRotated(25,1,0,0);

    glCallList(Lista_Podlogi);

    WallDraw();
    AwardDraw();
    SnakeDraw();

    glPopMatrix();

    glFlush();
    glutSwapBuffers();

    checkGame();
}

void Keyboard( unsigned char key, int x, int y )
{
    switch( key )
    {
    }
}

void KeyEvent(int key, int x, int y)
{
    switch(key)
    {
    case GLUT_KEY_UP:
        LastKey = UP;
        break;
    case GLUT_KEY_DOWN:
        LastKey = DOWN;
        break;
    case GLUT_KEY_LEFT:
        LastKey = LEFT;
        break;
    case GLUT_KEY_RIGHT:
        LastKey = RIGHT;
        break;
    default:
        break;
    }
}

void moveSnake()
{
    Wspolrzedne temp;
    Snake.pop_back();

    switch(LastKey)
    {
    case UP:
        temp.x = Snake[0].x;
        temp.z = Snake[0].z-1;
        break;
    case DOWN:
        temp.x = Snake[0].x;
        temp.z = Snake[0].z+1;
        break;
    case LEFT:
        temp.x = Snake[0].x-1;
        temp.z = Snake[0].z;
        break;
    case RIGHT:
        temp.x = Snake[0].x+1;
        temp.z = Snake[0].z;
        break;
    }

    Snake.push_front(temp);
}

void ResizeWindow(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum( -ViewLeft, ViewRight, -ViewBottom, ViewTop, ViewNear, ViewFar );
}

void checkCollisionSnake_Award()
{
    if (Snake[0].x == Award.x && Snake[0].z == Award.z){
        bIsAward = false;
        Snake.push_back(Snake[Snake.size()-1]);
        Scores += 25;
        if (SnakeSpeed > 0.08f)
            SnakeSpeed -= 0.01;
    }
}

void checkCollisionSnake_Wall()
{
    if ( Snake[0].x >= FieldSize ||
        Snake[0].x < -FieldSize ||
        Snake[0].z >= FieldSize ||
        Snake[0].z < - FieldSize){
            GameReset();
        }
}

void checkCollisionSnake_Snake()
{
    for (int i = 1; i < Snake.size(); ++i){
        if (Snake[0].x == Snake[i].x && Snake[0].z == Snake[i].z && i > 2){
            for (int j = Snake.size(); j >= i; --j){
                Snake.pop_back();
            }
            return;
        }
    }
}

void cubeDraw()
{
    glBegin(GL_TRIANGLES);
    glVertex3f( - 1.0, - 1.0, 1.0 );
    glVertex3f( 1.0, - 1.0, 1.0 );
    glVertex3f( 1.0, 1.0, 1.0 );

    glVertex3f( - 1.0, - 1.0, 1.0 );
    glVertex3f( 1.0, 1.0, 1.0 );
    glVertex3f( - 1.0, 1.0, 1.0 );

    glVertex3f( - 1.0, 1.0, 1.0 );
    glVertex3f( 1.0, 1.0, 1.0 );
    glVertex3f( - 1.0, 1.0, - 1.0 );

    glVertex3f( - 1.0, 1.0, - 1.0 );
    glVertex3f( 1.0, 1.0, 1.0 );
    glVertex3f( 1.0, 1.0, - 1.0 );

    glVertex3f( 1.0, 1.0, - 1.0 );
    glVertex3f( 1.0, 1.0, 1.0 );
    glVertex3f( 1.0, - 1.0, 1.0 );

    glVertex3f( 1.0, 1.0, - 1.0 );
    glVertex3f( 1.0, - 1.0, 1.0 );
    glVertex3f( 1.0, - 1.0, - 1.0 );

    glVertex3f( 1.0, - 1.0, - 1.0 );
    glVertex3f( 1.0, - 1.0, 1.0 );
    glVertex3f( - 1.0, - 1.0, - 1.0 );

    glVertex3f( - 1.0, - 1.0, - 1.0 );
    glVertex3f( 1.0, - 1.0, 1.0 );
    glVertex3f( - 1.0, - 1.0, 1.0 );

    glVertex3f( - 1.0, - 1.0, - 1.0 );
    glVertex3f( - 1.0, - 1.0, 1.0 );
    glVertex3f( - 1.0, 1.0, - 1.0 );

    glVertex3f( - 1.0, 1.0, - 1.0 );
    glVertex3f( - 1.0, - 1.0, 1.0 );
    glVertex3f( - 1.0, 1.0, 1.0 );

    glVertex3f( - 1.0, - 1.0, - 1.0 );
    glVertex3f( - 1.0, 1.0, - 1.0 );
    glVertex3f( 1.0, 1.0, - 1.0 );

    glVertex3f( 1.0, - 1.0, - 1.0 );
    glVertex3f( - 1.0, - 1.0, - 1.0 );
    glVertex3f( 1.0, 1.0, - 1.0 );
    glEnd();
}

Z góry dziękuje :)

1

Tak na szybko, obracasz sobie wektorem light_direction według odpowiednich wzorów:
https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/2drota.htm

BTW. jak używasz glVertex3f to używaj również literałów typu float, a nie double.

np. 1.0f zamiast 1.0.

0

Może źle się wyraziłem o co mi chodzi ;/ Mam w programie takie światło
02fb7fc85e.png
Jak zrobić aby to światło padało w przeciwnym kierunku?

1

podejrzewam, że powinieneś odwrócić kierunek padania światła (light_direction). W Twoim przypadku zmień z minusa na plus ;)

Tak powinno to wyglądać:

    GLfloat light_direction[3] =
    {
        0.0,0.0,1.0
    };

1 użytkowników online, w tym zalogowanych: 0, gości: 1