Currently working in OpenGL ES 2.0 in native on iOS. For some reason, my texture quad won't render, it just won't appear. I try to load in a .bmp file for the texture, and I do know that it goes through, because the log function I put in PolygonRenderer.addTexture prints out "Image size: 256, 256", which is the size of my texture.
Edit: My .bmp texture is saved in R8, G8, B8 form.
VertexShader:
std::string textureVertex =
"attribute vec3 vertexloc; \n"
"attribute vec3 vertexcol; \n"
"attribute vec2 vertexuv; \n"
"varying vec2 TexCoords; \n"
"varying vec3 textColor; \n"
"uniform mat4 projection; \n"
"uniform mat4 view; \n"
"uniform mat4 offset; \n"
"void main() \n"
"{ \n"
" gl_Position = projection * view * offset * vec4(vertexloc, 1.0); \n"
" TexCoords = vertexuv; \n"
" textColor = vertexcol; \n"
"}";
Fragment Shader:
std::string textureFragment =
"precision mediump float; \n"
"varying vec2 TexCoords; \n"
"varying vec3 textColor; \n"
"uniform sampler2D text; \n"
"void main() \n"
"{ \n"
" vec4 sampled = vec4(1.0, 1.0, 1.0, texture2D(text, TexCoords).r); \n"
" gl_FragColor = vec4(textColor, 1.0) * sampled; \n"
"}";
Vertices:
x = sWindowWidth / 2 - 1000 / 2;
y = - sWindowHeight / 2 - 172 / 2;
w = 1000;
h = 172;
temp = {
x, y + h, 0.3,
textureColor.x, textureColor.y, textureColor.z,
0, 1,
x, y, 0.3,
textureColor.x, textureColor.y, textureColor.z,
0, 0,
x + w, y, 0.3,
textureColor.x, textureColor.y, textureColor.z,
1, 0,
x, y + h, 0.3,
textureColor.x, textureColor.y, textureColor.z,
0, 1,
x + w, y, 0.3,
textureColor.x, textureColor.y, textureColor.z,
1, 0,
x + w, y + h, 0.3,
textureColor.x, textureColor.y, textureColor.z,
1, 1
};
polygonRenderer.addLoadingPolygon(temp);
PolygonRenderer excerpts:
AddLoadingPolygon:
void PolygonRenderer::addLoadingPolygon(std::vector<GLfloat> vertices) {
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat),
vertices.data(), GL_STATIC_DRAW);
if(vertexBuffer == 0){
log("gl vertexBuffer not generated");
}
loadingPolygons.push_back(PolygonRenderObject{
vertexBuffer,
(long)vertices.size() / 8,
0
});
}
AddTexture:
void PolygonRenderer::addTexture(const char* imagePath) {
// Data read from the header of the BMP file
unsigned char header[54]; // Each BMP file begins by a 54-bytes header
unsigned int dataPos; // Position in the file where the actual data begins
unsigned int width, height;
unsigned int imageSize; // = width*height*3
// Actual RGB data
unsigned char * data;
// Open the file
FILE * file = fopen(imagePath,"rb");
if (!file) {
log("Image could not be opened\n");
return;
}
if (fread(header, 1, 54, file) != 54) {
log("Not a correct BMP file");
return;
}
if (header[0] != 'B' || header[1] != 'M') {
log("Not a correct BMP file");
return;
}
// Read ints from the byte array
dataPos = *(int*)&(header[0x0A]);
imageSize = *(int*)&(header[0x22]);
width = *(int*)&(header[0x12]);
height = *(int*)&(header[0x16]);
if (imageSize == 0) {
imageSize = width * height;
}
log("Image size: %d, %d", width, height);
if (dataPos == 0) {
dataPos = 54;
}
data = new unsigned char[imageSize];
fread(data, 1, imageSize, file);
fclose(file);
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
GL_UNSIGNED_BYTE, data);
checkForGLError("Add texture:");
log("Texture created: %d", textureId);
textures.push_back(textureId);
}
Render for this part:
glUseProgram(shader.get(1));
glBindAttribLocation(shader.get(1), 2, "vertexloc");
glBindAttribLocation(shader.get(1), 3, "vertexcol");
glBindAttribLocation(shader.get(1), 4, "vertexuv");
glBindTexture(GL_TEXTURE_2D, textures[0]);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glUniformMatrix4fv(viewLocation, 1, GL_FALSE,
&frame.combinedMatrix[16 * objects[1].ViewGroup]);
glBindBuffer(GL_ARRAY_BUFFER, objects[1].Buffer);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat),
0);
glBindBuffer(GL_ARRAY_BUFFER, objects[1].Buffer);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat),
(GLvoid*)(3 * sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, objects[1].Buffer);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat),
(GLvoid*)(6 * sizeof(GLfloat)));
checkForGLError("In Renderer");
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
Unfortunately, this was simply me not assigning a uniform to a value, which caused all vertices to go to (0,0) (or something like that).
Related
I've made an OpenGL c++ program that can display some text into the screen. I've followed
some tutorials and got help from this question. With that, I've managed to write a function called add_border but I didn't quite understand how this all works and couldn't manage to display border on the screen.
Here is what I have so far:
text.fs
#version 300 es
precision mediump float;
in vec2 vUV;
uniform sampler2D u_texture;
uniform vec3 textColor;
out vec4 fragColor;
void main()
{
vec2 uv = vUV.xy;
float text = texture(u_texture, uv).r;
fragColor = vec4(textColor.rgb*text, text);
}
text.vs
#version 300 es
precision mediump float;
layout (location = 0) in vec4 in_attr;
out vec2 vUV;
uniform mat4 projection;
uniform mat4 model;
void main()
{
vUV = in_attr.zw;
gl_Position = projection * model * vec4(in_attr.xy, 1.0f, 1.0f);
}
Text.cpp
void Text::render_text(std::string text, float x, float y, float z, std::string hex_color, float angle_rad, bool has_bg)
{
static const int scale = 1;
y /= 2;
shader.use();
glUniform3f(glGetUniformLocation(shader.ID, "textColor"), 0.9, 0.9, 0.9);
color.get_color_float(Utils::BLUE));
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
GLfloat vertices[6][4] = {
{ 0.0, 1.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, 1.0 },
{ 1.0, 0.0, 1.0, 1.0 },
{ 0.0, 1.0, 0.0, 0.0 },
{ 1.0, 0.0, 1.0, 1.0 },
{ 1.0, 1.0, 1.0, 0.0 }
};
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
glm::mat4 rotateM = glm::rotate(glm::mat4(1.0f), glm::radians(angle_rad), glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 transOriginM = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, z));
std::string::const_iterator c;
GLfloat char_x = 0.0f;
for (c = text.begin(); c != text.end(); c++)
{
Character ch = Characters[*c];
GLfloat w = ch.Size.x * scale;
GLfloat h = ch.Size.y * scale;
GLfloat xrel = char_x + ch.Bearing.x * scale;
GLfloat yrel = y - (ch.Size.y - ch.Bearing.y) * scale;
char_x += (ch.Advance >> 6) * scale; )
glm::mat4 scaleM = glm::scale(glm::mat4(1.0f), glm::vec3(w, h, 1.0f));
glm::mat4 transRelM = glm::translate(glm::mat4(1.0f), glm::vec3(xrel, yrel, z));
glm::mat4 modelM = transOriginM * rotateM * transRelM * scaleM;
GLint model_loc = glGetUniformLocation(shader.ID, "model");
glUniformMatrix4fv(model_loc, 1, GL_FALSE, glm::value_ptr(modelM));
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Text::add_border(){
if(FT_Outline_New(ft_lib, 10000, 1000, &border) != 0){
VI_ERROR("Error");
}
FT_Stroker_New(ft_lib, &stroker);
FT_Stroker_Set(stroker, 2 * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
FT_Get_Glyph(face->glyph, &glyph);
FT_Glyph_Stroke(&glyph, stroker, false);
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
{
FT_Raster_Params params;
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
//params.gray_spans = outlineRenderCallback;
//params.user = user_data;
FT_Outline_Render(ft_lib, &border, ¶ms);
}
}
Text::Text(text_attributes&& atrib, int gl_width, int gl_height)
:SCR_WIDTH(gl_width), SCR_HEIGHT(gl_height)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shader = Shader("./src/opengl/shaders/text.vs", "./src/opengl/shaders/text.fs");
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT));
shader.use();
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
if (FT_Init_FreeType(&ft_lib))
{
VI_ERROR("ERROR::FREETYPE: Could not init FreeType Library");
exit(0);
}
std::string font_name = "./src/opengl/fonts/" + *atrib.__font_name + ".ttf";
if (FT_New_Face(ft_lib, font_name.c_str(), 0, &face)) {
VI_ERROR("ERROR::FREETYPE: Failed to load font");
exit(0) ;
} else {
FT_Set_Pixel_Sizes(face, 0, atrib.__font_size);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (unsigned char c = 0; c < 128; c++)
{
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
VI_ERROR("ERROR::FREETYTPE: Failed to load Glyph");
continue;
}
add_border();
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
static_cast<unsigned int>(face->glyph->advance.x)
};
Characters.insert(std::pair<char, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
}
FT_Done_Face(face);
FT_Outline_Done(ft_lib, &border);
FT_Done_FreeType(ft_lib);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
I've read somewhere that changing FT_LOAD_RENDER to FT_LOAD_DEFAULT in FT_Load_Char() causes the text to disappear completely
Right now this code compiles and runs just fine, however there is no border around the text. I want to add some parameters to the add_border function to have it display different border's with the given parameters such as border thickness and border color.
What am I doing wrong? How can I have it display border like I want it to?
Based on the comments above:
The below example is based on my own lib (although very shortened), where i am collecting the coverage into an span array and render it later. It is also possible to render the coverage(s)/scanline directly onto a bitmap.
//structure to set the bounds
//and to hold a list of the coverage(s)
//basically the 'raw' data to produce a single glyph image
struct my_spans {
int x_min, y_min;
int x_max, y_max;
FT_Span *span_array; //needed later to reproduce the (glyph) image
};
struct my_spans spans; //initialize properly
//set the raster params accordingly
FT_Raster_Params params;
memset(¶ms, 0, sizeof(params));
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; //direct rendering
params.gray_spans = outlineRenderCallback; //our callback below
params.user = &spans; //userdata will be our struct
//will be called for each scanline, thus the single y coordinate
void outlineRenderCallback(
int y,
int count,
const FT_Span *ft_spans,
void *user
){
struct my_spans *spans = (struct my_spans*) user;
FT_Span span;
//increase array capacity by count
//foreach span
for (int i=0; i < count; ++i, ++ft_spans) {
//horizontal boundary
spans->x_min = min(spans->x_min, ft_spans->x);
spans->x_max = max(spans->x_max, ft_spans->x + ft_spans->len - 1);
//span copy, although possible to write into array directly
span.x = ft_spans->x;
span.y = y;
span.len = ft_spans->len;
span.coverage = ft_spans->coverage;
//push span to array, if not written directly
}
//vertical boundary
spans->y_min = min(spans->y_min, y);
spans->y_max = max(spans->y_max, y);
}
Reference:
FT_Outline_Render
FT_Raster_Params
FT_SpanFunc
FT_Span
I am working on a 2D game engine and I want to implement text rendering. I want to use freetype. I have the following code:
GLuint va;
glGenVertexArrays(1, &va);
GLuint vb;
glGenBuffers(1, &vb);
glBindVertexArray(va);
glBindBuffer(GL_ARRAY_BUFFER, vb);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
FT_Face testface;
FT_Error error;
error = FT_New_Face(ftlib, "arial.ttf", 0, &testface);
if (error == FT_Err_Unknown_File_Format)
{
std::cout << "Font format not supported" << std::endl;
}
else if (error)
{
std::cout << "Something else" << "\n";
}
error = FT_Set_Pixel_Sizes(testface, 0, 48);
if (error)
{
std::cout << "Problem with set px szes occ\n";
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (unsigned char c = 0; c < 128; c++)
{
if (FT_Load_Char(testface, c, FT_LOAD_RENDER))
{
std::cout << "Error. Failed to load glyph "<<c<<"\n";
continue;
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
testface->glyph->bitmap.width,
testface->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
testface->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character newchar = {
texture,
glm::ivec2(testface->glyph->bitmap.width, testface->glyph->bitmap.rows),
glm::ivec2(testface->glyph->bitmap_left, testface->glyph->bitmap_top),
testface->glyph->advance.x
};
characters.insert(std::pair<char, Character>{c, newchar});
}
FT_Done_Face(testface);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glUseProgram(text_shader_program);
glUniform4f(glGetUniformLocation(text_shader_program, "textColor"), 1.f, 1.f, 1.f, 1.f);
glActiveTexture(GL_TEXTURE0);
std::string::const_iterator c;
std::string text = "TEST";
glBindVertexArray(va);
float x = 0.f;
for (c = text.begin(); c != text.end(); c++)
{
Character ch = characters[*c];
float xpos = x + ch.bearing.x;
float ypos = 0.f - (ch.size.y - ch.bearing.y);
float w = ch.size.x;
float h = ch.size.y;
float vertices[6][4] = {
{xpos, ypos + h, 0.f, 0.f},
{xpos, ypos, 0.f, 1.f},
{xpos + w, ypos, 1.f, 1.f},
{xpos, ypos + h, 0.f, 0.f},
{xpos + w, ypos, 1.f, 1.f},
{xpos + w, ypos + h, 1.f, 0.f}
};
glBindTexture(GL_TEXTURE_2D, ch.textureID);
glBindBuffer(GL_ARRAY_BUFFER, vb);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.advance >> 6);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
I initialize the library (before the above code happens) with
FT_Error error = FT_Init_FreeType(&ftlib);
if (error)
{
std::cout << "????" << std::endl;
}
The face and library initializes properly, glyphs are loaded, but nothing is drawn. I don't use camera, so all the coordinates are in space -1 to 1 if that matters.
I have the following shaders for text rendering:
vertexshader
#version 330 core
layout(location=0) in vec4 vertex;
out vec2 TextCoords;
void main() {
gl_Position = vec4(vertex.xy, 0.0, 1.0);
TextCoords = vertex.zw;
}
fragmentshader
#version 330 core
in vec3 TextCoords;
out vec4 color;
uniform sampler2D text;
uniform vec4 textColor;
void main(){
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TextCoords).r);
color = textColor * sampled;
}
Update:
I changed the line FT_Set_Pixel_Sizes(testface, 0, 48) to FT_Set_Pixel_Sizes(testface, 0, 1) and I got a huge gray rectangle where the text should be.
Has anyone got any ideas?
The problem seems to be the result of not using z-coordinate. The problem is, when using coordinate space -1 to 1, the text is rendering in too big scale to be seen or recognized. The solution is to use the z-coordinate as a static camera view, so for 500x500 window the borders are -250.f and 250.f
I've bee playing around again with Modern OpenGL (4.1) and was everything fine until I stepped into shading realms.
But before I even render something with shading I got some problems with the vertex shader.
The program is really simple, it simply reads an OBJ file and also the texture of the mesh. I put those things in their respective buffers and then draw it. At first it was drawing everything perfectly, but then I added 2 more uniform variable in the vertex shader and BAM! Nothing gets drawn. Funny thing is: as soon as I comment one of the extra uniforms, everything gets rendered again.
I really don't understand what is happening here, I thought I was extrapolating any limit of uniforms, but it is just 3 mat4 uniforms, and from what I googled, I have at least 1024 [source].
Anyway, I'm out of ideas, out of google query, so I come here to your help.
Thanks in advance!!
Ah, I'm using MacOSX El Captain and some information of the environment (got from glGetString):
Version: 4.1 ATI-1.40.16
Renderer: AMD Radeon HD 6750M OpenGL Engine
Some of the code not include is just Context creation and Shader compiling.
Note that if I delete uniform mat4 mM; it works perfectly. Otherwise, it keeps printing "Location -> -1" (saying it cannot find any uniform).
I really don't know what's going on.
P.S.: Also please don't mind for the terrible code, still trying to figure out some stuff code still not good.
vertexShader.gs:
#version 410
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec2 vTex;
out vec2 texCoord;
uniform mat4 mM;
uniform mat4 mV;
uniform mat4 mvp;
void main () {
texCoord = vTex;
gl_Position = mvp * vec4(vPosition, 1.0f);
}
Main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <OpenGl/gl.h>
//#define GLFW_INCLUDE_GLCOREARB
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "picg.h"
#include "shader.h"
#include "tiny_obj_loader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
void matrices(GLfloat xAngle, GLfloat yAngle);
glm::mat4 projection, view, model, rotations;
glm::mat4 mvp;
glm::vec3 light;
GLuint vao, vbo, ibo, tbo;
GLuint texture;
GLuint shaderProgram;
const GLfloat angle = 1.0f;
GLfloat cYAngle;
GLfloat cXAngle;
GLfloat scale = 1.0f;
GLfloat points[] = {
-0.7f, +0.7f, +0.7f,
-0.7f, -0.7f, +0.7f,
+0.7f, -0.7f, +0.7f,
+0.7f, +0.7f, +0.7f
};
GLuint indices[] = {
0, 1, 2, 3, 0, 2
};
int main() {
GLFWwindow * window = create_context("Fish club", 600, 600);
initGL();
GLubyte vertexShader = shaderFromFile("vertexShader.gs", GL_VERTEX_SHADER);
GLubyte fragmentShader = shaderFromFile("fragmentShader.gs", GL_FRAGMENT_SHADER);
projection = glm::perspective(glm::radians(+45.f), 1024.f / 768.f, 0.1f, 600.0f);
view = glm::lookAt(
glm::vec3(+0.0f,+0.0f,+5.0f),
glm::vec3(+0.0f,+0.0f,+0.0f),
glm::vec3(+0.0f,+1.0f,+0.0f)
);
model = glm::mat4(1.0f);
model = glm::scale(model, glm::vec3(90.0f));
mvp = projection * view * model;
light = glm::vec3(0.0f, 1.0f, 1.0f);
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
if (!tinyobj::LoadObj(shapes, materials, err, "res/GOLDFISH.obj")) {
throw std::runtime_error(std::string("Error loading OBJ file:\n") + err);
}
std::cout << "Shapes: " << shapes.size() << std::endl
<< "Materials: " << materials.size() << std::endl
<< "Positions: " << shapes[0].mesh.positions.size() << std::endl
<< "Normals: " << shapes[0].mesh.normals.size() << std::endl
<< "TexCoords: " << shapes[0].mesh.texcoords.size() << std::endl;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
int width, height, numComponents;
unsigned char * imageData = stbi_load("res/GOLDFISH.bmp",
&width, &height, &numComponents, 4);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
imageData);
glBindTexture(GL_TEXTURE_2D, NULL);
stbi_image_free(imageData);
GLsizei vertex_buffer_size = 0;
for (int i = 0 ; i < shapes.size(); ++i) {
vertex_buffer_size += sizeof(float) * shapes[i].mesh.positions.size();
}
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size, NULL, GL_STATIC_DRAW);
for (int i = 0, offset = 0 ; i < shapes.size() ; ++i) {
glBufferSubData(GL_ARRAY_BUFFER, offset,
sizeof(float) * shapes[i].mesh.positions.size(),
&shapes[i].mesh.positions[0]);
offset += sizeof(float) * shapes[i].mesh.positions.size();
}
glBindBuffer(GL_ARRAY_BUFFER, NULL);
GLsizei index_buffer_size = 0;
GLsizei index_size = 0;
for (int i = 0 ; i < shapes.size() ; ++i) {
index_buffer_size += sizeof(float) * shapes[i].mesh.indices.size();
index_size += shapes[i].mesh.indices.size();
}
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_size, NULL, GL_STATIC_DRAW);
for (int i = 0, offset = 0 ; i < shapes.size() ; ++i) {
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset,
sizeof(unsigned int) * shapes[i].mesh.indices.size(),
&shapes[i].mesh.indices[0]);
offset += sizeof(unsigned int) * shapes[i].mesh.indices.size();
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
GLsizei texcoord_buffer_size = 0;
for (int i = 0 ; i < shapes.size() ; ++i) {
texcoord_buffer_size += sizeof(float) * shapes[i].mesh.texcoords.size();
}
glGenBuffers(1, &tbo);
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, texcoord_buffer_size, NULL, GL_STATIC_DRAW);
for (int i = 0, offset = 0 ; i < shapes.size() ; ++i) {
glBufferSubData(GL_ARRAY_BUFFER, offset,
sizeof(float) * shapes[i].mesh.texcoords.size(),
&shapes[i].mesh.texcoords[0]);
offset += sizeof(float) * shapes[i].mesh.texcoords.size();
}
glBindBuffer(GL_ARRAY_BUFFER, NULL);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(NULL);
glBindBuffer(GL_ARRAY_BUFFER, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cYAngle += 0.1f;
matrices(cXAngle, cYAngle);
glUseProgram(shaderProgram);
std::cout << "Location -> " << glGetUniformLocation(shaderProgram, "mV") << std::endl;
std::cout << "Location -> " << glGetUniformLocation(shaderProgram, "mM") << std::endl;
std::cout << "Location -> " << glGetUniformLocation(shaderProgram, "mvp") << std::endl;
glUniformMatrix4fv(
glGetUniformLocation(shaderProgram, "mvp"),
1, GL_FALSE, &mvp[0][0]);
glUniformMatrix4fv(
glGetUniformLocation(shaderProgram, "mV"),
1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(
glGetUniformLocation(shaderProgram, "mM"),
1, GL_FALSE, &model[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(shaderProgram, "textureSampler"), 0);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, index_buffer_size, GL_UNSIGNED_INT, NULL);
glBindVertexArray(NULL);
glUseProgram(NULL);
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
void matrices(GLfloat xAngle, GLfloat yAngle) {
model = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(xAngle), glm::vec3(+1.0f, +0.0f, +0.0f));
model = glm::rotate(model, glm::radians(yAngle), glm::vec3(+0.0f, +1.0f, +0.0f));
model = glm::scale(model, glm::vec3(40.0f));
mvp = projection * view * model;
}
edit:
As suggested I tried the following vertex shader:
#version 410
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec2 vTex;
out vec2 texCoord;
uniform mat4 mM;
uniform mat4 mV;
uniform mat4 mP;
void main () {
texCoord = vTex;
gl_Position = mP * mV * mM * vec4(vPosition, 1.0f);
}
And changed the following lines
glUseProgram(shaderProgram);
std::cout << "Location -> " << glGetUniformLocation(shaderProgram, "mP") << std::endl;
std::cout << "Location -> " << glGetUniformLocation(shaderProgram, "mV") << std::endl;
std::cout << "Location -> " << glGetUniformLocation(shaderProgram, "mM") << std::endl;
glUniformMatrix4fv(
glGetUniformLocation(shaderProgram, "mP"),
1, GL_FALSE, &projection[0][0]);
glUniformMatrix4fv(
glGetUniformLocation(shaderProgram, "mV"),
1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(
glGetUniformLocation(shaderProgram, "mM"),
1, GL_FALSE, &model[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(shaderProgram, "textureSampler"), 0);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, index_buffer_size, GL_UNSIGNED_INT, NULL);
glBindVertexArray(NULL);
glUseProgram(NULL);
And still, I can see nothing and it only returns "Location -> -1" for every uniform.
mM and mV is not used in your vertex shader code. I believe it will be removed during compilation so when you try to get their location with glGetUniformLocation() this information is not available. Try to do something with mM and mV in your shader code.
I'm completely new to OpenGL and am having trouble on binding texture and shaders to VBOs works.
Here's my code.
static const char *vertexShaderSource =
"attribute highp vec3 posAttr;\n"
"attribute highp vec2 texAttr;\n"
"varying highp vec2 texCoord;\n"
"uniform highp mat4 matrix;\n"
"void main() {\n"
" texCoord = texAttr;\n"
" gl_Position = matrix * vec4(posAttr, 1.0);\n"
"}\n";
static const char *fragmentShaderSource =
"varying highp vec2 texCoord;\n"
"uniform sampler2D gSampler;\n"
"void main() {\n"
//" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" //it work
" gl_FragColor = texture2D(gSampler, texCoord);\n" //it not work
"}\n";
create buffers.
void TriangleWindow::createVertexBuffer()
{
GLfloat vertices[] = {
1.0f,1.0f,0.0f, 0.0f,0.0f,
0.0f,1.0f,1.0f, 0.5f,0.0f,
1.0f,0.0f,1.0f, 1.0f,0.0f,
0.5f,0.0f,0.0f, 0.5f,1.0f
};
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
qDebug()<<"sizeof(vertices) is "<<sizeof(vertices);
}
void TriangleWindow::createIndexBuffer()
{
GLuint indexs[] = {
0,1,3,
0,2,1,
0,3,2,
1,3,2
};
glGenBuffers(1, &m_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexs), indexs, GL_STATIC_DRAW);
qDebug()<<"sizeof(indexs) is "<<sizeof(indexs);
}
void TriangleWindow::createTextureBuffer()
{
QString resPath = "/Users/luxiaodong/Project/Demo/OpenGLES/res";
QString imgPath = QString("%1/test.png").arg(resPath);
qDebug()<<imgPath;
QImage image = QImage(imgPath).convertToFormat( QImage::Format_RGBA8888 );
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glGenTextures(1, &m_tex);
glBindTexture(GL_TEXTURE_2D, m_tex);
glTexParameterf(m_tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(m_tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(m_tex, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)image.bits() );
//glTexImage2D(GL_TEXTURE_2D, 0, 4, image.width(), image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
}
initialize
void TriangleWindow::initialize()
{
createVertexBuffer();
createIndexBuffer();
createTextureBuffer();
m_program = new QOpenGLShaderProgram(this);
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
m_program->link();
m_posAttr = m_program->attributeLocation("posAttr");
m_texAttr = m_program->attributeLocation("texAttr");
m_matrixUniform = m_program->uniformLocation("matrix");
m_gSampler = m_program->uniformLocation("gSampler");
m_program->setUniformValue(m_gSampler, 0);
qDebug()<<m_posAttr<<m_texAttr<<m_matrixUniform<<m_gSampler;
}
render
void TriangleWindow::render()
{
const qreal retinaScale = devicePixelRatio();
glViewport(0, 0, width() * retinaScale, height() * retinaScale);
glClear(GL_COLOR_BUFFER_BIT);
m_program->bind();
QMatrix4x4 matrix;
matrix.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f);
matrix.translate(0, 0, -4);
matrix.rotate(100.0f * m_frame/screen()->refreshRate(), 0, 1, 0);
m_program->setUniformValue(m_matrixUniform, matrix);
m_program->setUniformValue(m_gSampler, 0);
glEnableVertexAttribArray(m_posAttr);
glEnableVertexAttribArray(m_texAttr);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 20, (const GLvoid*)0);
glVertexAttribPointer(m_texAttr, 2, GL_FLOAT, GL_FALSE, 20, (const GLvoid*)12);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_tex);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (const GLvoid*)0 );
glDisableVertexAttribArray(m_texAttr);
glDisableVertexAttribArray(m_posAttr);
m_program->release();
++m_frame;
}
I'm not sure what i am doing wrong. I tried different things with the shader but it seems it doesn't matter. in fragmentShader.
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" //it work
" gl_FragColor = texture2D(gSampler, texCoord);\n" //it not work
Is this a problem with the shader I'm using, or is it something else that I'm not understanding?
Either the uniform(gSampler) or attribute(texAttr) should be the reason. To verify texAttr, use this as
gl_FragColor = vec4(texCoord.x,texCoord.y,0.0,1.0);
if your output is in some color then there is no problem in texAttr. I don't see any coding issue for texAttr. Anyway check once.
To verify gSampler, verify the glUniform1i(m_gSampler,unit), the unit should match the value(GL_TEXTURE0) you used to bind before glDrawElement.
I'm trying to render a checkerboard in OpenGL but I get and incorrect output. [checkerboard] http://s9.postimg.org/g3wk1py4f/large_checkerboard.png "large checkerboard"
I tried to narrow down the problem and I notices that when I try to draw a 11 by 11 grid i get only 10 pixels in vertical direction [small checkerboard] http://s12.postimg.org/olu7575jd/small_checkerboard.png "small checkerboard"
The texture itself is OK. I suspect problem is with vertex coordinates. Here's the code:
texture creation:
const int size = 11;
unsigned char buffer[size * size * 4];
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
unsigned char rgb = i % 2 == 1 || j % 2 == 1 ? 255 : 0;
int index = (i * size + j) * 4;
buffer[index] = rgb;
buffer[index + 1] = rgb;
buffer[index + 2] = rgb;
buffer[index + 3] = 255;
}
}
texture parameters:
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
vertices: (screen size is 1024 * 768, I'm drawing without any transformations at top right quarter)
float w = size / 512.0f;
float h = size / 384.0f;
GLfloat vertices[] =
{
0.0f, h, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f,
w, h, 1.0f, 1.0f,
w, 0.0f, 1.0f, 0.0f
};
int positionLocation = glGetAttribLocation(program.getId(), "a_position");
int textureLocation = glGetAttribLocation(program.getId(), "a_texCoord");
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertices);
glEnableVertexAttribArray(textureLocation);
glVertexAttribPointer(textureLocation, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertices + 2);
glUniform1i(textureLocation, 0);
drawing:
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
and the shaders:
const char* VertexShaderCode =
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_texCoord = a_texCoord; \n"
"}";
const char* FragmentShaderCode =
"uniform sampler2D s_texture; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_FragColor = texture2D(s_texture, v_texCoord); \n"
"}";
This is a FAQ. It's been answered countless times (also by me) on StackOverflow. Here's one of those answers https://stackoverflow.com/a/17422950/524368
Essentially you're running into a fenceposting problem.
This was a bug in my code. Not related to OpenGL. I was passing width and height into CreateWindow instead of adjustedWidth and adjustedHeight. (which I calculated to take into account borders and menu bar)