glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
ifstream myFile("Coordinates.txt");
if (!myFile.is_open())
{
cout << "Unable to open file";
exit(1); // terminate with error
}
// Light values and coordinates
float ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };
float diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
float specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};
float lightPos[] = { 0.0f, -150.0f, -150.0f, 1.0f };
glEnable(GL_CULL_FACE); // Do not calculate inside of jet
glFrontFace(GL_CCW); // Co unter clock-wise polygons face
// Enable lighting
glEnable(GL_LIGHTING);
// Setup and enable light 0
glLightfv(GL_LIGHT0,GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);
// Light values and coordinates
float specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
// Enable color tracking
glEnable(GL_COLOR_MATERIAL);
// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// All materials hereafter have full specular reflectivity
// with a high shine
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,specref);
glMateriali(GL_FRONT_AND_BACK,GL_SHININESS,128);
while (! myFile.eof())
{
glPushMatrix();
myFile>>plot[0];
myFile>>plot[1];
myFile>>plot[2];
myFile>>plot[3]; //this data will not be used
glColor3f(0.60f/1.5,0.80f/1.5,0.90f/1.5);
glTranslatef((plot[0]-1.15)*26, (plot[2]-0.51)*45, (plot[1]-1)*30);
glutSolidSphere(2, 12, 12);
glLoadIdentity();
glPopMatrix();
axes += 0.00005f;
}
glRotatef(axes, 0.0f, 1.0f, 0.0f);
myFile.close();
glFlush();
glutSwapBuffers();
This is my 1st time playing with lighting.
My problem is that after i place all the light effect code from a tutorial the objects seem only exist in one plane which is the xy-plane thought my data have coordinated in all xyz and the reflection seems a bit off..
can anyone tell me why and how to fix it?
Have a look-see here: Avoiding 16 Common OpenGL Pitfalls
You haven't given enough information. What values are in your file? Why are you loading plot[3] when it goes unused? Do you mean that the glutSphere is rendering as a flat 2d object in the xy plane?
I'd recommend you familiarise yourself with the core OpenGL functionality before using the in-built lighting, this problem probably has nothing to do with lighting. I also wouldn't recommend using GL's inbuilt lighting for any thing other than testing and tiny projects anyway... its not very flexible and has lots of limitations too.
Related
I was wondering if anyone could help me figure out how to add a light source to my 3D objects. I have four objects that are rotating and I want the light source to be at a fixed position, and I want to be able to see lighting on the object.
I tried doing this (********):
//*******Initializing the light position
GLfloat pos[] = {-2,4,5,1};
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
//*******adding the light to the display method
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, pos);
// rectangle
glPushMatrix();
glTranslatef(0.0f, 2.5f, -8.0f);
glRotatef(angleRectangle, 0.0f, 1.0f, 0.0f);
drawRectangle();
glPopMatrix();
//small cylinder
glPushMatrix();
glTranslatef(0.0f, 2.0f, -8.0f);
glRotatef(90, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 0.0f, 1.0f);
drawCylinder(0.2, 0.7);
glPopMatrix();
//big cylinder
glPushMatrix();
glTranslatef(0.0f, 1.5f, -8.0f);
glRotatef(90, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 0.0f, 1.0f);
drawCylinder(0.7, 2.7);
glPopMatrix();
//pyramid
glPushMatrix();
glTranslatef(0.0f, -2.2f, -8.0f);
glRotatef(180, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 1.0f, 0.0f);
drawPyramid();
glPopMatrix();
glutSwapBuffers();
anglePyramid += k * 0.2f; //- is CW, + is CCW
angleRectangle += -k * 0.2f;
}
//******* Then i added these to the main method
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
However when I do this and I run the entire program, my objects turn gray, and at certain points in the rotation they turn white. And this isnt what I want. I want to keep my colorful objects, but I want to be able to see the light source on them.
Any help would be greatly appreciated. Also let me know if you need to see more of my code to figure out the issue. Thanks
When lighting (GL_LIGHTING) is enabled, then the color is taken from the material parameters (glMaterial).
If you still want to use the current color, the you have to enable GL_COLOR_MATERIAL
and to set the color material paramters (glColorMaterial):
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
See also Basic OpenGL Lighting.
But note, that drawing by glBegin/glEnd sequences, the fixed function pipeline matrix stack and fixed function pipeline per vertex light model, is deprecated since decades.
Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.
I'm new to openGL and I drew a cube, then I place a camera inside the cube.
What I'm trying to achieve now is lighting the cube.
This is how I tried:
void draw(GLFWwindow* window)
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
// Create light components
GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f };
GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat position[] = { -1.5f, 1.0f, -1.0f, 1.0f };
// Assign created components to GL_LIGHT0
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
glLightfv(GL_LIGHT0, GL_POSITION, position);
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 projection = glm::perspective(PI / 4, 1.f / 1.f, 1.0f, 10.0f);
glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, -1.3f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 model = glm::rotate(glm::mat4(1.f), PI, glm::vec3(0.0f, 1.0f, 0.0f));
....
....
}
But I don't see any lightings
But I don't see any lightings
Welcome to the world of the old-and-busted fixed function pipeline. You're using OpenGL as it was done 20 years ago. The mode of illumination you're using is doing the lighting calculations only at the vertex locations and then simply blends the resulting color over the triangles (or quads). Obviously that won't work if there's a lot of change in illumination over the span of a single triangle.
In your case the light source is very close to your cube, so that's not going to work. You should address this by ditching the fixed function pipeline (FFP) and use shaders. Seriously, the FFP has been out of fashion for some 13 years (first GLSL capable GPUs arrived on the market in 2003). FFP has been emulated with shaders created in-situ ever since.
Also (judging from your other questions related to drawing a cube) you don't supply face normals. Normals are essential to doing illumination calculations, so you'll have to supply those as well.
I am attempting to draw a quadrilateral (square) on the screen. I inserted this into a pre-existing program that drew a cylinder. This is in an orthographic modelview matrix, and I am almost positive the clipping volume is correct (It's 200 in any direction from the origin). In the display function I'm using, I pushed a matrix, translated forward (0.0,0.0,-20.0), called quadriliteral, and then popped the matrix. Are the any common openGL settings people use that I'm unaware of that may make this not visible? Is there a way to get the current clipping volume and print it out in the console?
void quadrilateral()
{
glLoadIdentity();
glColor3f(0.5f,0.0f,0.8f);
glBegin(GL_QUADS);
glVertex3f(-10.0f,-10.0f,0.0f);
glVertex3f(-10.0f,10.0f,0.0f);
glVertex3f(10.0f,10.0f,0.0f);
glVertex3f(10.0f,-10.0f,0.0f);
glEnd();
}
//This is called from a main function elsewhere
void draw(void)
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Cylinder");
glutReshapeFunc(CChangeSize);
glutSpecialFunc(CSpecialKeys);
glutKeyboardFunc(Ckeyboard);
glutDisplayFunc(CRenderScene);
CSetupRC();
glPopMatrix();
}
void CSetupRC()
{
// Light values and coordinates
GLfloat ambientLight[] = {0.4f, 0.4f, 0.4f, 1.0f };
GLfloat diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f };
GLfloat specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
GLfloat lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
GLfloat specref[] = { 0.6f, 0.6f, 0.6f, 1.0f };
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glEnable(GL_CULL_FACE); // Do not calculate inside of solid object
glFrontFace(GL_CCW);
// Enable lighting
glEnable(GL_LIGHTING);
// Setup light 0
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
// Position and turn on the light
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);
// Enable color tracking
glEnable(GL_COLOR_MATERIAL);
// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// All materials hereafter have full specular reflectivity
// with a moderate shine
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,64);
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
}
// Called to draw scene
void CRenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Save the matrix state
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Rotate about x and y axes
glRotatef(CxRot, 1.0f, 0.0f, 0.0f);
glRotatef(CyRot, 0.0f, 1.0f, 0.0f);
// Draw the cylinder
cylinder();
glPopMatrix();
// CylinderTwo
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Rotate about x and y axes
glRotatef(CxRot, 1.0f, 0.0f, 0.0f);
glRotatef(CyRot, 0.0f, 1.0f, 0.0f);
// Draw the cylinder
glRotatef(120.0f, 1.0f, 1.0f, 1.0f);
cylinderTwo();
glPopMatrix();
// Random square
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(-30.0f,20.0f,10.0f);
quadrilateral();
glPopMatrix();
// Swap buffers
glutSwapBuffers();
}
It looks like your winding order is incorrect:
glEnable(GL_CULL_FACE);
this line means it will cull back faces.
glFrontFace(GL_CCW);
and this sets the front face to counter clockwise.
glVertex3f(-10.0f,-10.0f,0.0f);
glVertex3f(-10.0f,10.0f,0.0f);
glVertex3f(10.0f,10.0f,0.0f);
glVertex3f(10.0f,-10.0f,0.0f);
Here you have clockwise ordering of your vertices meaning you are drawing with the back to camera. either disable culling:
glDisable(GL_CULL_FACE);
make the front face clockwise:
glFrontFace(GL_CW);
or change the order of your vertices to a counter clockwise order.
Looks to me that your quad is wound backwards. You've enabled GL_CULL_FACE, which throws out any clockwise wound polygons, and your quad has a clockwise winding.
Either disable backface culling, or switch the order of your vertices to counter-clockwise.
I am using GL_TRIANGLE_STRIP to draw my terrain to the screen, however when I compile and run the program I get nothing. When I change GL_TRIANGLE_STRIP to GL_LINES it shows up and works. What can I do to get it working with GL_TRIANGLE_STRIP?
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -10.0f);
glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
glRotatef(-_angle, 0.0f, 1.0f, 0.0f);
GLfloat ambientColor[] = {.5, .5, .5, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
float scale = 5.0f / max(63.0,63.0);
glScalef(scale, scale*10, scale);
glTranslatef(-(float)(63.0) / 2, 0.0f, -(float)(63.0) / 2);
/*GLfloat lightColor0[] = {0.6f, 0.6f, 0.6f, 1.0f};
GLfloat lightPos0[] = {-0.5f, 4, 32, 0.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);*/
glColor3f(0.3f, 0.9f, 0.0f);
for(int x = 0;x<64;x++){
glBegin(GL_LINES);
for(int z = 0;z<63;z++){
glNormal3f(0,1,0);
Vertex(x,map[x][z],z);
Vertex(x,map[x][z+1],z+1);
}
glEnd();
}
for(int z = 0;z<64;z++){
glBegin(GL_LINES);
for(int x = 0;x<63;x++){
Vertex(x,map[x][z],z);
Vertex(x+1,map[x+1][z],z);
}
glEnd();
}
I'm not sure this is important but for my terrain I have code that makes it a 3d Gaussian distribution.
An explanation of TRIANGLE_STRIP is found by a Google search. There is an illustration on Wikipedia.
My advice is to print out the first five vertices of your vertex data, and draw it by hand on paper. The fact that GL_LINES work suggest that the right vertices are there, you might just drawing them in the wrong order.
Another piece of advice is to disable backface culling.
glDisable(GL_CULL_FACE);
As a random stab in the dark, do you have culling turned on? It may be that it's not drawing any triangles because the back of the triangles are invisible. Try adding:
glDisable(GL_CULL_FACE);
To you init code, or simply removing:
glEnable(GL_CULL_FACE);
From your init code.
I heard that I should use normals instead of colors, because colors are deprecated. (Is that true?) Normals have something to do with the reflection of light, but I can't find a clear and intuitive explanation. What is a normal?
A normal in general is a unit vector whose direction is perpendicular to a surface at a specific point. Therefore it tells you in which direction a surface is facing. The main use case for normals are lighting calculations, where you have to determine the angle (or practically often its cosine) between the normal at a given surface point and the direction towards a lightsource or a camera.
glNormal minimal example
glNormal is a deprecated OpenGL 2 method, but it is simple to understand, so let's look into it. The modern shader alternative is discussed below.
This example illustrates some details of how glNormal works with diffuse lightning.
The comments of the display function explain what each triangle means.
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
/* Triangle on the x-y plane. */
static void draw_triangle() {
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
}
/* A triangle tilted 45 degrees manually. */
static void draw_triangle_45() {
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
}
static void display(void) {
glColor3f(1.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
/*
Triangle perpendicular to the light.
0,0,1 also happens to be the default normal if we hadn't specified one.
*/
glNormal3f(0.0f, 0.0f, 1.0f);
draw_triangle();
/*
This triangle is as bright as the previous one.
This is not photorealistic, where it should be less bright.
*/
glTranslatef(2.0f, 0.0f, 0.0f);
draw_triangle_45();
/*
Same as previous triangle, but with the normal set
to the photorealistic value of 45, making it less bright.
Note that the norm of this normal vector is not 1,
but we are fine since we are using `glEnable(GL_NORMALIZE)`.
*/
glTranslatef(2.0f, 0.0f, 0.0f);
glNormal3f(0.0f, 1.0f, 1.0f);
draw_triangle_45();
/*
This triangle is rotated 45 degrees with a glRotate.
It should be as bright as the previous one,
even though we set the normal to 0,0,1.
So glRotate also affects the normal!
*/
glTranslatef(2.0f, 0.0f, 0.0f);
glNormal3f(0.0, 0.0, 1.0);
glRotatef(45.0, -1.0, 0.0, 0.0);
draw_triangle();
glPopMatrix();
glFlush();
}
static void init(void) {
GLfloat light0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
/* Plane wave coming from +z infinity. */
GLfloat light0_position[] = {0.0, 0.0, 1.0, 0.0};
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
}
static void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 7.0, -1.0, 1.0, -1.5, 1.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800, 200);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}
Theory
In OpenGL 2 each vertex has its own associated normal vector.
The normal vector determines how bright the vertex is, which is then used to determine how bright the triangle is.
OpenGL 2 used the Phong reflection model, in which light is separated into three components: ambient, diffuse and specular. Of those, diffuse and specular components are affected by the normal:
if the diffuse light is perpendicular to the surface, it makes is brighter, no matter where the observer is
if the specular light hits the surface, and bounces off right into the eye of the observer, that point becomes brigher
glNormal sets the current normal vector, which is used for all following vertexes.
The initial value for the normal before we all glNormal is 0,0,1.
Normal vectors must have norm 1, or else colors change! glScale also alters the length of normals! glEnable(GL_NORMALIZE); makes OpenGL automatically set their norm to 1 for us. This GIF illustrates that beautifully.
Why it is useful to have normals per vertexes instead of per faces
Both spheres below have the same number of polygons. The one with normals on the vertexes looks much smoother.
OpenGL 4 fragment shaders
In newer OpenGL API's, you pass the normal direction data to the GPU as an arbitrary chunk of data: the GPU does not know that it represents the normals.
Then you write a hand-written fragment shader, which is an arbitrary program that runs in the GPU, which reads the normal data you pass to it, and implements whatever lightning algorithm you want. You can implement Phong efficiently if you feel like it, by manually calculating some dot products.
This gives you full flexibility to change the algorithm design, which is a major features of modern GPUs. See: https://stackoverflow.com/a/36211337/895245
Examples of this can be found in any of the "modern" OpenGL 4 tutorials, e.g. https://github.com/opengl-tutorials/ogl/blob/a9fe43fedef827240ce17c1c0f07e83e2680909a/tutorial08_basic_shading/StandardShading.fragmentshader#L42
Bibliography
https://gamedev.stackexchange.com/questions/50653/opengl-why-do-i-have-to-set-a-normal-with-glnormal
https://www.opengl.org/sdk/docs/man2/xhtml/glNormal.xml
http://www.tomdalling.com/blog/modern-opengl/06-diffuse-point-lighting/
http://learnopengl.com/#!Advanced-Lighting/Normal-Mapping
Many things are now deprecated, including normals and colors. That just means that you have to implement them yourself. With normals you can shade your objects. It's up to you to make the calculations but there are a lot of tutorials on e.g. Gouraud/Phong shading.
Edit: There are two types of normals: face normals and vertex normals. Face normals point away from the triangle, vertex normals point away from the vertex. With vertex normals you can achieve better quality, but there are many uses also for face normals, e.g. they can be used in collision detection and shadow volumes.