Я написал программу на C ++, где я рисую чайник и применяю освещение. Это само по себе просто, но я также использую шейдеры. Простой Я новичок в GLSL Я только что попробовал простой фрагментный шейдер, но вывод на экран необъясним.
В этом файле я инициализирую glew в методе init, где я также компилирую вершинный и фрагментный шейдеры. Они находятся в файлах «vertex_shader» и «frag_shader».
То, что вы можете не узнать, это что такое Свет и Материал. Это всего лишь некоторые структуры, содержащие всю информацию о огнях. Я проверил эти структуры, поэтому я уверен, что работа, как ожидалось. Когда я объявляю material = BlackPlastic, я просто устанавливаю значение по умолчанию, определенное с помощью директивы define. Я также могу опубликовать этот код, если вы думаете, что проблема есть.
#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;
}
Я не думаю, что вершинный шейдер вызывает какие-либо проблемы, он просто назначает цвет и правильно рассчитывает положение. Также фрагментный шейдер, по-видимому, корректен, это единственная выполняемая инструкция:
gl_FragColor = gl_Color;
Если я сделаю это, я просто увижу белый чайник. Если вместо этого я изменю это значение на любой другой цвет:
gl_FragColor = vec4{0,0,1,1};
Я получаю чайник с нужным цветом: черный пластик. И я не знаю почему, я не применяю освещение здесь, я должен рассчитать его.
Я уточнил, что я выполнил ту же самую программу, но без применения шейдеров, и я получил чайник, чтобы иметь правильный цвет.
Прежде всего, вы смешиваете конвейер с фиксированной функцией с «более новыми вещами». Это очень плохая практика, потому что она может вызвать много проблем, потому что вы не знаете, что происходит в фоновом режиме.
Если вы хотите иметь настоящее освещение с диффузными шейдерами, вам нужно рассчитать диффузный цвет самостоятельно. Давным-давно я использовал ffp в последний раз, поэтому я искал несколько шейдеров, которые его используют:
Vertex-шейдеры
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;
}
Фрагмент-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;
}
Других решений пока нет …