Я пытаюсь обнаружить края силуэта и визуализировать некоторые текстуры (зависит от диффузного термина) на этих краях с помощью OpenGL и шейдеров. Я создаю квад, используя геометрический шейдер, а также назначаю здесь координаты текстуры. В шейдере фрагмента я пытаюсь использовать диффузный термин, рассчитанный в вершинном шейдере, для визуализации различных текстур на основе значения diffTerm. В моем коде есть две проблемы.Текстуры не работают (черные текстуры) - OpenGL + GLSL
1) Диффузный член должен отличаться от (-1,1), но он, кажется, застревает в 0, когда я поворачиваю модель, и она достигает отрицательных значений в определенных положениях.
2) Текстуры всегда черные, и я не могу понять, что вызывает эту проблему.
"MeshViewer.cpp" - Основной файл
Mesh* mesh;
GLuint* texID = new GLuint[5];
float rotn_x = 0.0, rotn_y = 0.0, fov;
GLuint matrixLoc1, matrixLoc2, matrixLoc3,texLoc1, texLoc2, texLoc3, texLoc4, texLoc5;
float cam_near, cam_far; //Near and far planes of the camera
const float PI = 3.14159265f;
glm::mat4 view; //View and projection matrices
void loadTextures()
{
glGenTextures(5, texID); //Generate 1 texture ID
glActiveTexture(GL_TEXTURE0); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[0]);
loadTGA("Pencil0.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE1); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[1]);
loadTGA("Pencil1.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE2); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[2]);
loadTGA("Pencil2.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE3); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[3]);
loadTGA("Brick.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE4); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[4]);
loadTGA("Brick.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void initialise()
{
// --- Mesh object ---
GLuint lgtLoc;
mesh = new Mesh();
if(!mesh->loadMeshOFF("Camel.off")) cout << "Error reading mesh data file." << endl;
// --- Camera parameters ---
float win_width = (mesh->_xmax - mesh->_xmin) * 1.5f;
float win_height = (mesh->_ymax - mesh->_ymin) * 1.5f;
if(win_width > win_height) win_height = win_width; //Maintain aspect ratio = 1
cam_near = 2*(mesh->_zmax) - mesh->_zmin;
cam_far = 2*(mesh->_zmin) - mesh->_zmax;
float cam_posx = (mesh->_xmax + mesh->_xmin) * 0.5f;
float cam_posy = (mesh->_ymax + mesh->_ymin) * 0.5f;
float cam_posz = cam_near + win_height;
fov = 27.0f; //Approx. atan(0.5)
// --- Uniform locations ---
GLuint program = createShaderProg("MeshViewer.vert", "MeshViewer.frag", "MeshViewer.geom");
matrixLoc1 = glGetUniformLocation(program, "mvMatrix");
matrixLoc2 = glGetUniformLocation(program, "mvpMatrix");
matrixLoc3 = glGetUniformLocation(program, "norMatrix");
lgtLoc = glGetUniformLocation(program, "lightPos");
GLint lineWidth = glGetUniformLocation(program, "HalfWidth");
if (lineWidth > -1)
glUniform1f(lineWidth, 0.005f);
GLint overhangLength = glGetUniformLocation(program, "OverhangLength");
if (overhangLength > -1)
glUniform1f(overhangLength, 0.15f);
texLoc1 = glGetUniformLocation (program, "tex1");
glUniform1i(texLoc1, 0);
texLoc2 = glGetUniformLocation (program, "tex2");
glUniform1i(texLoc2, 1);
texLoc3 = glGetUniformLocation (program, "tex3");
glUniform1i(texLoc3, 2);
texLoc4 = glGetUniformLocation (program, "tex4");
glUniform1i(texLoc4, 3);
texLoc5 = glGetUniformLocation (program, "tex5");
glUniform1i(texLoc5, 4);
view = glm::lookAt(glm::vec3(cam_posx, cam_posy, cam_posz), glm::vec3(cam_posx, cam_posy, 0.0), glm::vec3(0.0, 1.0, 0.0)); //view matrix
glm::vec4 light = glm::vec4(100.0, 50.0, 100.0, 1.0); //Light's position
glm::vec4 lightEye = view*light; //Light position in eye coordinates
glUniform4fv(lgtLoc, 1, &lightEye[0]);
// --- OpenGL ---
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //Wireframe
mesh->setColor(0, 0, 1); //Mesh color = blue.
mesh->createVAO(); //Create buffer objects for the mesh
}
void display()
{
glm::mat4 proj;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 matrix = glm::mat4(1.0);
matrix = glm::rotate(matrix, rotn_x, glm::vec3(1.0, 0.0, 0.0)); //rotation about x
matrix = glm::rotate(matrix, rotn_y, glm::vec3(0.0, 1.0, 0.0)); //rotation about y
glm::mat4 prodMatrix1 = view*matrix; //Model-view matrix
proj = glm::perspective(fov, 1.0f, cam_near, cam_far); //perspective projection matrix
glm::mat4 prodMatrix2 = proj*prodMatrix1; //The model-view-projection transformation
glm::mat4 invMatrix = glm::inverse(prodMatrix1); //Inverse of model-view matrix for normal transformation
glUniformMatrix4fv(matrixLoc1, 1, GL_FALSE, &prodMatrix1[0][0]);
glUniformMatrix4fv(matrixLoc2, 1, GL_FALSE, &prodMatrix2[0][0]);
glUniformMatrix4fv(matrixLoc3, 1, GL_TRUE, &invMatrix[0][0]); //Use transpose matrix here
mesh->render();
glFlush();
}
void specialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_LEFT) rotn_y -= 5.0;
else if(key == GLUT_KEY_RIGHT) rotn_y += 5.0;
else if(key == GLUT_KEY_UP) rotn_x -= 5.0;
else if(key == GLUT_KEY_DOWN) rotn_x += 5.0;
else if(key == GLUT_KEY_PAGE_UP) fov --;
else if(key == GLUT_KEY_PAGE_DOWN) fov ++;
if(fov < 1.0) fov = 1.0;
else if(fov > 80.0) fov = 80.0;
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (600, 600);
glutInitWindowPosition (20, 10);
glutCreateWindow ("Mesh Viewer");
glutInitContextVersion (4, 2);
glutInitContextProfile (GLUT_CORE_PROFILE);
if(glewInit() == GLEW_OK)
{
cout << "GLEW initialization successful! " << endl;
cout << " Using GLEW version " << glewGetString(GLEW_VERSION) << endl;
}
else
{
cerr << "Unable to initialize GLEW ...exiting." << endl;
exit(EXIT_FAILURE);
}
initialise();
glutDisplayFunc(display);
glutSpecialFunc(specialKeys);
glutMainLoop();
return 0;
}
Vertex Shader:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec3 cols;
layout (location = 3) in vec2 texC;
uniform mat4 mvMatrix;
uniform mat4 mvpMatrix;
uniform mat4 norMatrix;
uniform vec4 lightPos;
out float diffTerm;
out vec4 vColour;
out float viewTerm;
out float silhoutte;
out vec2 TexC;
void main()
{
vec4 grey = vec4(0.2, 0.2, 0.2, 1.0);
vec4 posnEye = mvMatrix * position;
vec4 normalEye = norMatrix * vec4(normal, 0);
vec4 lgtVec = normalize(lightPos - posnEye);
vec4 viewVec = normalize(vec4(-posnEye.xyz, 0));
float viewTerm = max(dot(viewVec, normalEye),0);
vec4 material = vec4(cols, 1.0);
vec4 lgtAmb = grey * material;
diffTerm = max(dot(lgtVec, normalEye), 0);
vec4 lgtDiff = material * diffTerm;
silhoutte = dot(viewVec, normalEye);
gl_Position = mvpMatrix * position;
vColour = vec4(cols, 1);
TexC = texC;
}
Geometry Shader:
#version 430 core
layout(triangles_adjacency) in;
layout(triangle_strip, max_vertices = 6) out;
in vec2 texC[];
out vec2 TexCoord;
in vec4 vColour[];
out vec4 colorv;
in float viewTerm[];
out float viewTermg;
in float diffTerm[];
out float diffTermg;
in vec2 TexC[];
out vec2 TexCg;
uniform float HalfWidth;
uniform float OverhangLength;
out float gDist;
out vec3 gSpine;
bool IsFront(vec3 A, vec3 B, vec3 C)
{
float area = (A.x * B.y - B.x * A.y) + (B.x * C.y - C.x * B.y) + (C.x * A.y - A.x * C.y);
return area > 0;
}
void EmitEdge(vec3 P0, vec3 P1)
{
vec3 E = OverhangLength * vec3(P1.xy - P0.xy, 0);
vec2 V = normalize(E.xy);
vec3 N = vec3(-V.y, V.x, 0) * 0.005;
vec3 S = -N;
float D = HalfWidth;
gSpine = P0;
gl_Position = vec4(P0 + S - E, 1); gDist = +D; TexCoord=vec2(0.0,0.0); colorv = vColour[0]; EmitVertex();
gl_Position = vec4(P0 + N - E, 1); gDist = -D; TexCoord=vec2(1.0,0.0); colorv = vColour[1]; EmitVertex();
gSpine = P1;
gl_Position = vec4(P1 + S + E, 1); gDist = +D; TexCoord=vec2(1.0,1.0); colorv = vColour[0]; EmitVertex();
gl_Position = vec4(P1 + N + E, 1); gDist = -D; ; TexCoord=vec2(0.0,1.0); EmitVertex();
EndPrimitive();
}
void main()
{
vec3 v0 = gl_in[0].gl_Position.xyz/gl_in[0].gl_Position.w;
vec3 v1 = gl_in[1].gl_Position.xyz/gl_in[1].gl_Position.w;
vec3 v2 = gl_in[2].gl_Position.xyz/gl_in[2].gl_Position.w;
vec3 v3 = gl_in[3].gl_Position.xyz/gl_in[3].gl_Position.w;
vec3 v4 = gl_in[4].gl_Position.xyz/gl_in[4].gl_Position.w;
vec3 v5 = gl_in[5].gl_Position.xyz/gl_in[5].gl_Position.w;
if (IsFront(v0, v2, v4)) {
if (!IsFront(v0, v1, v2)) EmitEdge(v0, v2);
//if (!IsFront(v2, v3, v4)) EmitEdge(v2, v4);
//if (!IsFront(v0, v4, v5)) EmitEdge(v4, v0);
}
}
Фрагмент Shader:
#version 330
in vec4 vColourg;
in float diffTermg;
in float silhoutte;
in vec2 TexCg;
in vec2 TexCoord;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4;
uniform sampler2D tex5;
void main()
{
vec4 texColor1 = texture(tex1, TexCoord);
vec4 texColor2 = texture(tex2, TexCoord);
vec4 texColor3 = texture(tex3, TexCoord);
vec4 texColor4 = texture(tex4, TexCoord);
vec4 texColor5 = texture(tex5, TexCoord);
vec4 blue = vec4(0.0,0.0,1.0,0.0);
vec4 red = vec4(1.0,0.0,0.0,0.0);
vec4 yellow = vec4(1.0,1.0,0.0,0.0);
if (diffTermg<0)
{
gl_FragColor = blue;
}
else if (diffTermg ==0)
{
gl_FragColor = texColor5;
}
else if (diffTermg > 0 && diffTermg < 0.2)
gl_FragColor = yellow;
else if (diffTermg > 100)
gl_FragColor = blue;
}
EDIT: Shader.h
GLuint loadShader(GLenum shaderType, string filename)
{
ifstream shaderFile(filename.c_str());
if(!shaderFile.good()) cout << "Error opening shader file." << endl;
stringstream shaderData;
shaderData << shaderFile.rdbuf();
shaderFile.close();
string shaderStr = shaderData.str();
const char* shaderTxt = shaderStr.c_str();
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderTxt, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);
const char *strShaderType = NULL;
cerr << "Compile failure in shader: " << strInfoLog << endl;
delete[] strInfoLog;
}
return shader;
}
GLuint createShaderProg(string vertShader, string fragShader, string geomShader)
{
GLuint shaderv = loadShader(GL_VERTEX_SHADER, vertShader);
GLuint shaderf = loadShader(GL_FRAGMENT_SHADER, fragShader);
GLuint shaderg = loadShader(GL_GEOMETRY_SHADER, geomShader);
GLuint program = glCreateProgram();
glAttachShader(program, shaderv);
glAttachShader(program, shaderf);
glAttachShader(program, shaderg);
glLinkProgram(program);
GLint status;
glGetProgramiv (program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
fprintf(stderr, "Linker failure: %s\n", strInfoLog);
delete[] strInfoLog;
program = 0;
}
glUseProgram(program);
return program;
}
loadTGA.h
void loadTGA(string filename)
{
char id, cmap, imgtype, bpp, c_garb;
char* imageData, temp;
short int s_garb, wid, hgt;
int nbytes, size, indx;
ifstream file(filename.c_str(), ios::in | ios::binary);
if(!file)
{
cout << "*** Error opening image file: " << filename.c_str() << endl;
exit(1);
}
file.read (&id, 1);
file.read (&cmap, 1);
file.read (&imgtype, 1);
if(imgtype != 2 && imgtype != 3) //2= colour (uncompressed), 3 = greyscale (uncompressed)
{
cout << "*** Incompatible image type: " << (int)imgtype << endl;
exit(1);
}
//Color map specification
file.read ((char*)&s_garb, 2);
file.read ((char*)&s_garb, 2);
file.read (&c_garb, 1);
//Image specification
file.read ((char*)&s_garb, 2); //x origin
file.read ((char*)&s_garb, 2); //y origin
file.read ((char*)&wid, 2); //image width
file.read ((char*)&hgt, 2); //image height
file.read (&bpp, 1); //bits per pixel
file.read (&c_garb, 1); //img descriptor
nbytes = bpp/8; //No. of bytes per pixels
size = wid * hgt * nbytes; //Total number of bytes to be read
imageData = new char[size];
file.read(imageData, size);
//cout << ">>>" << nbytes << " " << wid << " " << hgt << endl;
if(nbytes > 2) //swap R and B
{
for(int i = 0; i < wid*hgt; i++)
{
indx = i*nbytes;
temp = imageData[indx];
imageData[indx] = imageData[indx+2];
imageData[indx+2] = temp;
}
}
switch (nbytes)
{
case 1:
glTexImage2D(GL_TEXTURE_2D, 0, 1, wid, hgt, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData);
break;
case 3:
glTexImage2D(GL_TEXTURE_2D, 0, 3, wid, hgt, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
break;
case 4:
glTexImage2D(GL_TEXTURE_2D, 0, 4, wid, hgt, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
break;
}
delete imageData;
}
Где вы активируете свою шейдерную программу (например, glUseProgram())? –
@AntonAngelov: я добавил файл заголовка, который выполняет загрузку шейдеров. Он содержит glUseProgram(). – Ravi
Я не вижу, где вы загружаете свои текстуры, но я предполагаю, что вы делаете это правильно. Просто идея, вы можете установить цвет фейдера-шейдера, чтобы показать УФ-координаты (просто вы можете узнать, возникает ли проблема из текстуры или коордов). Другое дело: если диффузный термин застрял в 0, означает, что либо ваш вектор света, либо нормальный вектор неверен. "vec4 lgtVec = normalize (lightPos - posnEye);" Здесь ваш светлый вектор указывает от LightPos (возможно, worldspace) на Vertex (пространство камеры), а диффузный термин Ламберта требует, чтобы L был обратным вектором (от вершины к источнику света [в том же пространстве]). Просто мысль. –