I have written a C++ program where I draw a teapot and apply lighting. It is itself simple, but I also use shaders. Simple I'm new with GLSL I just tried a simple fragment shader, but the screen output is inexplicable.
In this file I initialize glew in the init method, where I also compile the vertex and fragment shader. They're in the "vertex_shader" and "fragment_shader" files.
The thing you may not recognize is what's Light and Material. They're just some structs containing all info about the lights. I've tested these struct so I'm sure the work as expected. When I declare material=BlackPlastic I just set it to a default value defined with the define directive. I may also post this code if you think that the problem is there.
#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
#include <fstream>
#include <vector>
#include "utility.hpp"
#define MAX_DIM 1000
GLfloat width=600, height=800;
GLuint vertex_shader, fragment_shader;
GLuint program;
const char* vertex_shader_filename= "vertex_shader";
const char* fragment_shader_filename= "fragment_shader";
Light light;
Material material;
void init()
{
// Inizializzazione di GLEW
glewInit();
if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
{
cout << "Supporto GLSL" << endl;
}
// Lettura e compilazione del vertex shader
GLchar* buffer= new GLchar[MAX_DIM];
ifstream stream;
streamsize count;
stream.open(vertex_shader_filename);
stream.read(buffer,MAX_DIM);
count= stream.gcount();
stream.close();
vertex_shader= glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, (const GLchar**)&buffer, &count);
glCompileShader(vertex_shader);
// Lettura, inizializzazione ed esecuzione del fragment shader
stream.open(fragment_shader_filename);
stream.read(buffer,MAX_DIM);
count= stream.gcount();
stream.close();
fragment_shader= glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, (const GLchar**)&buffer, &count);
glCompileShader(fragment_shader);
delete[] buffer;
// Creazione del programma
program= glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glUseProgram(program);
// Inizializzazione materiale e luce
material= BlackPlastic;
light= {vector<GLfloat>{-2,2,2,1} ,vector<GLfloat>{1,1,1,1},vector<GLfloat>{1,1,1,1},vector<GLfloat>{1,1,1,1} };
}
void display()
{
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,width/height,1,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,-100,0,0,0,0,1,0);
// Illuminazione
glShadeModel(GL_SMOOTH);
material.apply(); // This just causes glMaterialfv to be called for the ambient, diffuse, specular and shininess values.
light.apply(); // This just causes glLightfv to be called for the ambient, diffuse and specular values
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// Rendering
glClearColor(0.8,0.8,0.8,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidTeapot(10);
glutSwapBuffers();
}
void reshape(int w, int h)
{
width=w;
height=h;
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(500,500);
glutCreateWindow("test");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
init();
glutMainLoop();
return 0;
}
I don't think that the vertex shader is causing any problem, it just assigns the color and calculate the position, correctly. Also the fragment shader is apparently correct, this is the only instruction executed:
gl_FragColor = gl_Color;
If I do this I just see a white teapot. If instead I change this value to a whatever color:
gl_FragColor = vec4{0,0,1,1};
I get the teapot with the right color: black plastic. And I don't know why, I don't apply lighting here, I should calculate it.
I precisate that I executed the same identical program but without applying the shaders, and I got the teapot to have the right color.
First off all you are mixing the fixed function pipeline with "the newer stuff". This is a real bad practice because it could couse a lot of issues because you don't really know what is going on in background.
If you want to have real lighting with diffuse shaders you have to calculate the diffuse color on your own. It's a long time ago i used the ffp the last time so i searched for some shaders wich use it:
Vertex-Shader
varying vec3 normal;
varying vec3 v;
varying vec3 lightvec;
void main(void)
{
normal = normalize(gl_NormalMatrix * gl_Normal);
v = vec3(gl_ModelViewMatrix * gl_Vertex);
lightvec = normalize(gl_LightSource[0].position.xyz - v);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Fragment-Shader
varying vec3 normal;
varying vec3 v;
varying vec3 lightvec;
void main(void)
{
vec3 Eye = normalize(-v);
vec3 Reflected = normalize( reflect( -lightvec, normal ));
vec4 IAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
vec4 IDiffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * max(dot(normal, lightvec), 0.0);
vec4 ISpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular * pow(max(dot(Reflected, Eye), 0.0), gl_FrontMaterial.shininess);
gl_FragColor = gl_FrontLightModelProduct.sceneColor + IAmbient + IDiffuse + ISpecular;
}
来源:https://stackoverflow.com/questions/14573079/fragment-shader-inexplicable-bahaviour