我正在尝试使用OpenGL 3.30使用Shader程序学习显示纹理。我能够加载图像,但我无法在每个立方体的脸上正确显示它。
下面的代码定义了顶点的属性,它是与每个立方体顶点关联的顶点和纹理坐标。然后创建2个VBO,一个保存立方体顶点,另一个保存纹理信息。
我认为我对最终结果非常接近:我获得了立方体,成功加载了图像,能够获取图像信息。那么我在这里做错了什么呢?
我正在使用stblib加载图片。
这是我的代码:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h> /* must include for the offsetof macro */
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <stdlib.h>
#include "utils.h"
#include "stb_image.h"
struct Vertex {
GLdouble position[3];
GLdouble texture[2];
};
/* These pointers will receive the contents of our shader source code files */
GLchar *vertexsource, *fragmentsource;
/* These are handles used to reference the shaders */
GLuint vertexshader, fragmentshader;
/* This is a handle to the shader program */
GLuint shaderprogram;
GLuint vbo[1]; /* Create handles for our Vertex Array Object and One Vertex Buffer Object */
//GLuint text_2d_1;
const struct Vertex plane[24] = {
// Front Face
{{1.0f, 1.0f, 1.0f}, {0.0, 0.0}},
{{-1.0f, 1.0f, 1.0f}, {1.0, 0.0}},
{{-1.0f, -1.0f, 1.0f}, {1.0, 1.0}},
{{ 1.0f, -1.0f, 1.0f}, {0.0, 1.0}},
// Back Face
{{-1.0f, -1.0f, -1.0f}, {1.0, 0.0}},
{{-1.0f, 1.0f, -1.0f}, {1.0, 1.0}},
{{ 1.0f, 1.0f, -1.0f}, {0.0, 1.0}},
{{ 1.0f, -1.0f, -1.0f}, {0.0, 0.0}},
// Top Face
{{-1.0f, 1.0f, -1.0f}, {0.0, 1.0}},
{{-1.0f, 1.0f, 1.0f}, {0.0, 0.0}},
{{ 1.0f, 1.0f, 1.0f}, {1.0, 0.0}},
{{ 1.0f, 1.0f, -1.0f}, {1.0, 1.0}},
// Bottom Face
{{-1.0f, -1.0f, -1.0f}, {1.0, 1.0}},
{{ 1.0f, -1.0f, -1.0f}, {0.0, 1.0}},
{{ 1.0f, -1.0f, 1.0f}, {0.0, 0.0}},
{{-1.0f, -1.0f, 1.0f}, {1.0, 0.0}},
// Right face
{{1.0f, -1.0f, -1.0f}, {1.0, 0.0}},
{{1.0f, 1.0f, -1.0f}, {1.0, 1.0}},
{{1.0f, 1.0f, 1.0f}, {0.0, 1.0}},
{{1.0f, -1.0f, 1.0f}, {0.0, 0.0}},
// Left Face
{{-1.0f, -1.0f, -1.0f}, {0.0, 0.0}},
{{-1.0f, -1.0f, 1.0f}, {1.0, 0.0}},
{{-1.0f, 1.0f, 1.0f}, {1.0, 1.0}},
{{-1.0f, 1.0f, -1.0f}, {0.0, 1.0}}
};
void SetupGeometry() {
/* Allocate and assign One Vertex Buffer Object to our handle */
glGenBuffers(1, vbo);
/* Bind our VBO as being the active buffer and storing vertex attributes (coordinates + colors) */
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
/* Copy the vertex data from plane to our buffer */
/* 12 * sizeof(GLfloat) is the size of the tetrahedrom array, since it contains 12 Vertex values */
glBufferData ( GL_ARRAY_BUFFER, 24 * sizeof ( struct Vertex ), plane, GL_STATIC_DRAW );
/* Specify that our coordinate data is going into attribute index 0, and contains three doubles per vertex */
/* Note stride = sizeof ( struct Vertex ) and pointer = ( const GLvoid* ) 0 */
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
/* Enable attribute index 0 as being used */
glEnableVertexAttribArray(0);
/* Specify that our color data is going into attribute index 1, and contains three floats per vertex */
/* Note stride = sizeof ( struct Vertex ) and pointer = ( const GLvoid* ) ( 3 * sizeof ( GLdouble ) ) i.e. the size (in bytes)
occupied by the first attribute (position) */
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );
/* Enable attribute index 1 as being used */
glEnableVertexAttribArray ( 1 );/* Bind our fourth VBO as being the active buffer and storing vertex attributes (texture) */
printf("vertex %d\n", offsetof(struct Vertex,position));
printf("texture %d\n", offsetof(struct Vertex,texture));
}
void SetupShaders(void) {
/* Read our shaders into the appropriate buffers */
vertexsource = filetobuf("plane/plane.vert");
fragmentsource = filetobuf("plane/plane.frag");
/* Assign our handles a "name" to new shader objects */
vertexshader = glCreateShader(GL_VERTEX_SHADER);
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
/* Associate the source code buffers with each handle */
glShaderSource(vertexshader, 1, (const GLchar**)&vertexsource, 0);
glShaderSource(fragmentshader, 1, (const GLchar**)&fragmentsource, 0);
/* Compile our shader objects */
glCompileShader(vertexshader);
glCompileShader(fragmentshader);
/* Assign our program handle a "name" */
shaderprogram = glCreateProgram();
glAttachShader(shaderprogram, vertexshader);/* Attach our shaders to our program */
glAttachShader(shaderprogram, fragmentshader);
glBindAttribLocation(shaderprogram, 0, "in_Position"); /* Bind attribute 0 (coordinates) to in_Position and attribute 1 (colors) to in_Texture */
glBindAttribLocation(shaderprogram, 1, "in_Texture");
glLinkProgram(shaderprogram);/* Link our program, and set it as being actively used */
glUseProgram(shaderprogram);
}
void Render(int i) {
GLfloat angle;
glm::mat4 Projection = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f);
angle = (GLfloat) (i % 360);
glm::mat4 View = glm::mat4(1.);
View = glm::translate(View, glm::vec3(0.f, 0.f, -5.0f));
View = glm::rotate(View, angle * -1.0f, glm::vec3(1.f, 0.f, 0.f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.f, 1.f, 0.f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.f, 0.f, 1.f));
glm::mat4 Model = glm::mat4(1.0);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderprogram, "mvpmatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
/* Bind our modelmatrix variable to be a uniform called mvpmatrix in our shaderprogram */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_QUADS, 0, 24);
/* Invoke glDrawArrays telling that our data consists of individual triangles */
}
int reverse = 1;
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if ((key == GLFW_KEY_R) && action == GLFW_PRESS)
reverse = 1 - reverse; // togrls reverse from 0 to 1 to o to ...
}
int main( void ) {
int k = 0;
GLFWwindow* window;
if( !glfwInit() ) {
printf("Failed to start GLFW\n");
exit( EXIT_FAILURE );
}
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window) {
glfwTerminate();
printf("GLFW Failed to start\n");
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window); // IMPORTANT: Must be done so glew recognises OpenGL
glewExperimental = GL_TRUE;
int err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
fprintf(stderr, "Glew done\n");
glfwSetKeyCallback(window, key_callback);
fprintf(stderr, "GL INFO %s\n", glGetString(GL_VERSION));
SetupGeometry();
SetupShaders();
int w, h, n, O;
char *filename = "plane/rock.bmp";
unsigned char * data = stbi_load(filename, &w, &h, &n, 0); //image data
if(data == NULL) {
print("Image not loaded");
const char *error = stbi_failure_reason();
printf("Failure reason %s\n", error);
exit(0);
}else{
print("Image loaded successfully");
}
printf("Image Stats %d %d %d\n", w, h, n);
// for(int d = 0; d < w * h * 3; d++)
// printf("img content: %i\n",data[d]);
printf (" first 4 bytes are: %i %i %i %i\n", data[ 0], data[ 1], data[ 2], data[ 3] );
GLuint tex;
glGenTextures(1, &tex);
Print("Texture");
Print(GL_TEXTURE0);
print((int) tex);
//glActiveTexture(GL_TEXTURE0);
/*
* To get the texture to activate, take the base texture GL_TEXTURE0 and add the value of the generated texture.
* This needs checking with more than one texture.
* beware of NIDIA specific.
*/
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_image_free(data); // free up image data
//glDisable(gl_te)
glEnable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 1.0);/* Make our background black */
while( !glfwWindowShouldClose(window) ) {// Main loop
Render(k);// OpenGL rendering goes here...
if(reverse)
k--;
else
k++;
Sleep(20);
glfwSwapBuffers(window);// Swap front and back rendering buffers
glfwPollEvents();
}
glfwTerminate();// Close window and terminate GLFW
exit( EXIT_SUCCESS );// Exit program
}
顶点着色器:
#version 330
precision highp float;
in vec3 in_Position;
in vec2 in_Texture;
// mvpmatrix is the result of multiplying the model, view, and projection matrices */
uniform mat4 mvpmatrix;
out vec2 UV;
void main(void) {
// Multiply the mvp matrix by the vertex to obtain our final vertex position
gl_Position = mvpmatrix * vec4(in_Position, 1.0);
UV = in_Texture;
}
片段着色器:
#version 330
precision highp float;
in vec2 UV;
out vec3 color;
uniform sampler2D myTexture;
void main(void) {
color = texture(myTexture, UV).rgb;
}
这是输入图片:
这是程序的输出:
答案 0 :(得分:2)
问题在于:
/* Specify that our color data is going into attribute index 1,
and contains three floats per vertex */
/* Note stride = sizeof ( struct Vertex ) and
pointer = ( const GLvoid* ) ( 3 * sizeof ( GLdouble ) )
i.e. the size (in bytes) occupied by the first attribute
(position) */
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) );
顶点纹理坐标属性有两个元素,但是你告诉OpenGL连续有3个元素。这显然既不匹配您的顶点数据也不匹配着色器顶点属性类型。将元素大小调整为2,它应该工作。哦,你不必明确地将数字文字强制转换为GLuint
。
答案 1 :(得分:2)
您使用的数据类型存在一些不一致。结构的声明对位置和纹理坐标使用双精度:
struct Vertex {
GLdouble position[3];
GLdouble texture[2];
};
在属性设置期间,您使用的是不同的类型:
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );
纹理坐标在此处用作GL_FLOAT
。此外,您在此处指定3个组件,其中struct只有2个。
很少有理由使用双打坐标。无论如何,OpenGL内部将使用32位精度。因此,如果您将属性指定为双精度数,则只会添加转换数,并使用更多内存。
要将float用于所有内容,结构应该声明如下:
struct Vertex {
GLfloat position[3];
GLfloat texture[2];
};
属性规范如下所示:
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
glVertexAttribPointer ( ( GLuint ) 1, 2, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );