画面の中央に回転する立方体 (テクスチャ付き)を描画し、続いて立方体の周りを周回する小さな黄色の球体を描画するプログラムを作成しています。アイデアは、立方体を照らすスポット光源として球体を作ることです。
ここに問題があります。下の画像でわかるように、スポット ライト効果を実現できません。立方体全体が照らされているようです。
GL_SPOT_DIRECTION
立方体の位置になるように設定しています。立方体の法線を計算する方法を理解するのに苦労しているため、サーフェス法線を設定しませんでした。また、このような単純なグラフィック アプリケーションで実際に法線が必要かどうかもわかりません。
以下のコードを共有しています。
main.cpp :
#include <QApplication>
#include "glwidget.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
GLWidget gl_widget;
gl_widget.show();
return app.exec();
}
GLWidget.h :
#pragma once
#include <QGLWidget>
#include <QImage>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget* parent = 0);
virtual ~GLWidget();
void _draw_texture_cube(int w, int h);
void _draw_light();
/* OpenGL initialization, viewport resizing, and painting */
void initializeGL();
void paintGL();
void resizeGL( int width, int height);
/* enable the user to interact directly with the scene using the keyboard */
void keyPressEvent(QKeyEvent *e);
private:
int _width;
int _height;
QImage* _img;
GLuint _texture;
float xrot;
float yrot;
float zrot;
bool _light_on;
bool _must_rotate;
bool _pause_light;
GLfloat _light_pos[3];
GLfloat _cube_pos[3];
GLUquadricObj* _quadratic;
protected slots:
void _tick();
};
GLWidget.cpp :
#include "GLWidget.h"
#include <iostream>
#include <QKeyEvent>
#include <QTimer>
#include <cmath>
#define LIGHT_MOVEMENT_SPEED 20.0f // Degrees per second
#define pi 3.141592654f
GLWidget::GLWidget(QWidget *parent)
: QGLWidget(parent), _img(NULL), _light_on(true), _must_rotate(true),
_pause_light(false), _quadratic(NULL)
{
_width = 0;
_height = 0;
_texture = 0;
xrot = 0.f;
yrot = 0.f;
zrot = 0.f;
// Set central cube position
_cube_pos[0] = 0.0f;
_cube_pos[1] = 0.0f;
_cube_pos[2] = -7.0f;
// Set light position
_light_pos[0] = 0.5f;
_light_pos[1] = 0.5f;
_light_pos[2] = -7.0f;
}
GLWidget::~GLWidget()
{
if (_img)
delete _img;
glDeleteTextures(1, &_texture);
}
void GLWidget::_tick()
{
update(); // triggers paintGL()
QTimer::singleShot(33, this, SLOT(_tick()));
}
void GLWidget::initializeGL()
{
std::cout << "GLWidget::initializeGL" << std::endl;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black Background
glEnable(GL_CULL_FACE);
/* Load bitmap */
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
if (!_img)
{
std::cout << "GLWidget::paintGL: loading image" << std::endl;
QImage tmp(":/crate.jpg");
if (tmp.isNull())
{
std::cout << "GLWidget::paintGL: !!! Failed QImage #1" << std::endl;
return;
}
_img = new QImage(QGLWidget::convertToGLFormat(tmp));
}
/* Convert bitmap into texture */
// Create The Texture
glGenTextures(1, &_texture);
// Typical Texture Generation Using Data From The Bitmap
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture);
// Generate The Texture
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
GL_RGBA, _img->width(), _img->height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, _img->bits());
if (glGetError() != GL_NO_ERROR)
{
std::cout << "GLWidget::paintGL: !!! Failed glTexImage2D" << std::endl;
return;
}
/* Setup lighting */
glShadeModel(GL_SMOOTH); //Smooth color shading
// Light properties
GLfloat AmbientLight[4] = {0.2, 0.2, 0.2, 1.0};
GLfloat DiffuseLight[4] = {0.8, 0.8, 0.8, 1.0}; // color
GLfloat SpecularLight[4] = {1.0, 1.0, 1.0, 1.0}; // bright
GLfloat SpecRef[] = {0.7f, 0.7f, 0.7f, 1.0f};
GLubyte Shine = 60.0;
//glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, AmbientLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularLight);
glLightfv(GL_LIGHT0, GL_POSITION, _light_pos);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR, SpecRef); // refletância do material
glMaterialf(GL_FRONT, GL_SHININESS, Shine); // concentração do brilho
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
//glColorMaterial(GL_FRONT,GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
// Sphere
_quadratic = gluNewQuadric(); // Create A Pointer To The Quadric Object
gluQuadricNormals(_quadratic, GLU_SMOOTH); // Create Smooth Normals
gluQuadricTexture(_quadratic, GL_TRUE); // Create Texture Coords
/* Start the timer */
_tick();
}
/* Draw the central cube with texture
*/
void GLWidget::_draw_texture_cube(int w, int h)
{
glPushMatrix();
glTranslatef(_cube_pos[0], _cube_pos[1], _cube_pos[2]);
glRotatef ( xrot, 1.0, 0.0, 0.0 );
glRotatef ( yrot, 0.0, 1.0, 0.0 );
glRotatef ( zrot, 0.0, 0.0, 1.0 );
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS); // Draw A Cube
// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(w, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(w, h); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, h); glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
glTexCoord2f(w, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(w, h); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, h); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Face
glTexCoord2f(0.0f, h); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(w, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(w, h); glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face
glTexCoord2f(w, h); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, h); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(w, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
glTexCoord2f(w, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(w, h); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, _img->height()); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(w, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(w, h); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, h); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glPopMatrix();
if (_must_rotate)
{
xrot += 0.6f;
yrot += 0.4f;
zrot += 0.8f;
}
}
/* Draw light source and light model (sphere)
*/
void GLWidget::_draw_light()
{
if (_light_on)
{
glEnable(GL_LIGHT0); // enable lights that we use
}
else
{
glDisable(GL_LIGHT0);
}
static float light_angle = 25.0f;
if (!_pause_light) // stop moving the light source
{
light_angle += LIGHT_MOVEMENT_SPEED * 0.1;
if (light_angle > 360.0f)
light_angle -= 360.0f;
}
/* Set light source position */
_light_pos[0] = 4.0f * (float) cos(light_angle * pi / 180.0f);
_light_pos[1] = 4.0f * (float) sin(light_angle * pi / 180.0f);
_light_pos[2] = -7;
glLightfv(GL_LIGHT0, GL_POSITION, _light_pos);
GLfloat SpotDir[] = {_cube_pos[0], _cube_pos[1], _cube_pos[2], 0.0 };
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, SpotDir);
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 150.0);
glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 15.0);
/* Set the light model position to be the same as the light source */
glPushMatrix();
glTranslatef(_light_pos[0], _light_pos[1], _light_pos[2]);
glColor3ub(255, 255, 0); // yellow
gluSphere(_quadratic, 0.2f, 32, 32); // draw sphere
glPopMatrix();
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix
glLoadIdentity(); // Reset The Current Modelview Matrix
/* Draw central cube */
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture); // Select Our Texture
_draw_texture_cube(_img->width(), _img->height());
glDisable(GL_TEXTURE_RECTANGLE_ARB);
/* Draw light source and light model*/
_draw_light();
}
void GLWidget::resizeGL( int w, int h)
{
_width = w;
_height = h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
if (h == 0) // Calculate The Aspect Ratio Of The Window
gluPerspective ( 60, ( float ) w, 0.4, 500.0 );
else
gluPerspective ( 60, ( float ) w / ( float ) h, 0.4, 500.0 );
glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix
glLoadIdentity ( ); // Reset The Model View Matrix
gluLookAt(0.0, 0.0, 2.0, // eye
0.0, 0.0, 0.0, // center
0.0, 1.0, 0.0); // up
}
void GLWidget::keyPressEvent(QKeyEvent *e)
{
switch (e->key())
{
case Qt::Key_L:
if (_light_on)
_light_on = false;
else
_light_on = true;
break;
case Qt::Key_P:
if (_pause_light)
_pause_light = false;
else
_pause_light = true;
break;
case Qt::Key_R:
if (_must_rotate)
_must_rotate = false;
else
_must_rotate = true;
break;
default:
break;
}
}
Lighting.pro :
QT += core gui opengl
SOURCES += \
GLWidget.cpp \
main.cpp
HEADERS += \
GLWidget.h
RESOURCES += \
resource.qrc
目的の効果を得るために、このアプリケーションで何を変更する必要がありますか?