I've got a basic opengl setup working with shaders, IBOs, and VBOs. And can do simple things such as drawing a 2D rectangle or square or anything of that sense. However, when I implement a vbo and an ibo containing data for a cube nothing shows up on the screen. I've created a cube class which stores the vertex and indices for the cube.
Note: I have not implemented a projection matrix in the shader yet, I am waiting till I get the distorted 3d cube on the screen.
Here's my code-
main.cpp
#include <iostream>
#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <glm\glm.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <glm\gtc\type_ptr.hpp>
#include "shader.h"
#include "cube.h"
#undef main
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* mainWindow = SDL_CreateWindow("game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 512, SDL_WINDOW_OPENGL);
SDL_GLContext mainContext = SDL_GL_CreateContext(mainWindow);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
glewExperimental = GL_TRUE;
glewInit();
GLuint VBO, VAO, IBO;
cube block1(0, 0, -2.5, .2);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*36, block1.indices, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 24, block1.vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
shader sqreProg("shaders/shader.vert", "shaders/shader.frag");
bool running = true;
while (running) {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
sqreProg.useShader();
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
SDL_GL_SwapWindow(mainWindow);
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
}
}
}
SDL_GL_DeleteContext(mainContext);
SDL_DestroyWindow(mainWindow);
SDL_Quit();
}
Shader.h
#pragma once
#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <string>
#include <fstream>
#include <streambuf>
#include <iostream>
class shader {
public:
shader(const char* vShader, const char* fShader) {
vShaderCode = readFile(vShader);
fShaderCode = readFile(fShader);
shaderProgramID = glCreateProgram();
addShader(vShaderCode.c_str(), GL_VERTEX_SHADER);
addShader(fShaderCode.c_str(), GL_FRAGMENT_SHADER);
glLinkProgram(shaderProgramID);
}
void useShader() { glUseProgram(shaderProgramID); }
private:
GLuint shaderProgramID;
std::string vShaderCode;
std::string fShaderCode;
std::string readFile(const char* fileName) {
std::ifstream file(fileName);
std::string fileContents;
fileContents.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return fileContents;
}
void addShader(const char* code, GLenum type) {
GLuint shaderID = glCreateShader(type);
const GLchar* theCode[1];
theCode[0] = code;
GLint codeLength[1];
codeLength[0] = strlen(code);
glShaderSource(shaderID, 1, theCode, codeLength);
glCompileShader(shaderID);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &result);
if (!result) {
glGetShaderInfoLog(shaderID, 1024, NULL, eLog);
fprintf(stderr, "error compile the %d shader: '%s'\n", type, eLog);
return;
}
glAttachShader(shaderProgramID, shaderID);
}
};
cube.h
#pragma once
#include <GL\glew.h>
class cube {
public:
cube() {
x = 0;
y = 0;
z = 0;
width = 0;
vertices = 0;
indices = 0;
}
cube(GLfloat X, GLfloat Y, GLfloat Z, float w) {
x = X;
y = Y;
z = Z;
width = w;
vertices = new GLfloat[24];
//1
vertices[0] = x;
vertices[1] = y;
vertices[2] = z;
//2
vertices[3] = x + width;
vertices[4] = y;
vertices[5] = z;
//3
vertices[6] = x;
vertices[7] = y - width;
vertices[8] = z;
//4
vertices[9] = x + width;
vertices[10] = y - width;
vertices[11] = z;
//5
vertices[12] = x;
vertices[13] = y;
vertices[14] = z - width;
//6
vertices[15] = x + width;
vertices[16] = y;
vertices[17] = z - width;
//7
vertices[18] = x;
vertices[19] = y - width;
vertices[20] = z - width;
//8
vertices[21] = x + width;
vertices[22] = y - width;
vertices[23] = z - width;
indices = new unsigned int[36];
//0
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
//1
indices[3] = 1;
indices[4] = 2;
indices[5] = 3;
//2
indices[6] = 4;
indices[7] = 5;
indices[8] = 6;
//3
indices[9] = 5;
indices[10] = 6;
indices[11] = 7;
//4
indices[12] = 4;
indices[13] = 0;
indices[14] = 1;
//5
indices[15] = 4;
indices[16] = 5;
indices[17] = 1;
//6
indices[18] = 6;
indices[19] = 2;
indices[20] = 3;
//7
indices[21] = 6;
indices[22] = 7;
indices[23] = 3;
//8
indices[24] = 1;
indices[25] = 5;
indices[26] = 3;
//9
indices[27] = 5;
indices[28] = 7;
indices[29] = 3;
//10
indices[30] = 4;
indices[31] = 0;
indices[32] = 2;
//11
indices[33] = 4;
indices[34] = 6;
indices[35] = 2;
}
GLfloat* vertices;
unsigned int* indices;
private:
GLfloat x;
GLfloat y;
GLfloat z;
float width;
};
Related
so I am trying to render Koch's snowflake. whenever the user clicks the "w" button it should generate a new generation using this function:
void nextGen(int& gen, vector<KochLine>& v, GLFWwindow* window, float angle) {
gen++;
if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS && gen <= 6) {
vector<KochLine> nextGen;
int p = power(4, gen);
for (int j = 0; j < v.size(); j++) {
if (j < p) {
v[j].generate(nextGen, angle);
} else {
v[j].generate(nextGen, -angle);
}
}
v = nextGen;
}
}
can anyone tell me how to do that?
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include ".\classes\KochLine.h"
#include ".\classes\Shader.h"
#define PI 3.1415926538
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void closeWindow(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
int power(int a, int b) {
int ans = 1;
while(b > 0) {
int lb = (b & 1);
if(lb) {
ans *= a;
}
a *= a;
b = b >> 1;
}
return ans;
}
void nextGen(int& gen, vector<KochLine>& v, GLFWwindow* window, float angle) {
gen++;
if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS && gen <= 6) {
vector<KochLine> nextGen;
int p = power(4, gen);
for (int j = 0; j < v.size(); j++) {
if (j < p) {
v[j].generate(nextGen, angle);
} else {
v[j].generate(nextGen, -angle);
}
}
v = nextGen;
}
}
int main() {
int gen = 0, type = -1;
while(type != 1 && type != 2) {
cout << "Enter which type of koch snowflake you want\n";
cout << "[1]Koch's Snowflake\n";
cout << "[2]Anti-Koch's Snowflake\n";
cin >> type;
}
// koch curve stuff
Vertex v1{-0.75f, -0.75f};
Vertex v2{0.75f, -0.75f};
Vertex v3{0.0f, 0.75f};
KochLine e2{v1, v2};
KochLine e1{v1, v3};
KochLine e3{v2, v3};
vector<KochLine> v;
v.push_back(e1);
v.push_back(e2);
v.push_back(e3);
float angle = PI / 3.0f;
if(type == 2) {
angle *= -1;
}
/*for(int i = 0; i < gen; i++) {
vector<KochLine> nextGen;
int p = power(4, i);
for(int j = 0; j < v.size(); j++) {
if(j < p) {
v[j].generate(nextGen, angle);
} else {
v[j].generate(nextGen, -angle);
}
}
v = nextGen;
}*/
float* vertecies = (float*)malloc(v.size() * 6 * sizeof(float));
int p = 0;
for(int i = 0; i < v.size() * 6; i += 6) {
vertecies[i] = v[p].p1.x;
vertecies[i + 1] = v[p].p1.y;
vertecies[i + 2] = 0.0f;
vertecies[i + 3] = v[p].p2.x;
vertecies[i + 4] = v[p].p2.y;
vertecies[i + 5] = 0.0f;
p++;
}
// openGL stuff
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "Cobweb_Diagram", NULL, NULL);
if (window == NULL) {
cout << "Failed to create GLFW window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
cout << "Failed to initialize GLAD" << endl;
return -1;
}
Shader ourShader("./shaders/my_vertex.vs", "./shaders/my_fragment.fs");
int k = v.size();
unsigned int VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, k * 6 * sizeof(float), vertecies, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(0));
glEnableVertexAttribArray(0);
while (!glfwWindowShouldClose(window)) {
closeWindow(window);
nextGen(gen, v, window, angle);
float* vertecies = (float*)malloc(v.size() * 6 * sizeof(float));
int p = 0;
for (int i = 0; i < v.size() * 6; i += 6) {
vertecies[i] = v[p].p1.x;
vertecies[i + 1] = v[p].p1.y;
vertecies[i + 2] = 0.0f;
vertecies[i + 3] = v[p].p2.x;
vertecies[i + 4] = v[p].p2.y;
vertecies[i + 5] = 0.0f;
p++;
}
glBufferData(GL_ARRAY_BUFFER, k * 6 * sizeof(float), vertecies, GL_STATIC_DRAW);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
ourShader.use();
glDrawArrays(GL_LINES, 0, v.size() * 2);
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Edit: I tried to run glBufferData in render loop but it doesn't work.
I've got a point cloud of an object using kinect and I want to create a 3d representation of the point cloud and save the image. I'm not sure how I can approach this task. I want it to be able to detect an object and derive the point cloud of the object. For example for 3d scanning purposes, it would be able to 3d scan the object from all directions and then get a point cloud from it.
main.cpp
#include "main.h"
#include "glut.h"
#include <cmath>
#include <cstdio>
#include <Windows.h>
#include <Ole2.h>
#include <NuiApi.h>
#include <NuiImageCamera.h>
#include <NuiSensor.h>
// OpenGL Variables
long depthToRgbMap[width*height*2];
// We'll be using buffer objects to store the kinect point cloud
GLuint vboId;
GLuint cboId;
// Kinect variables
HANDLE depthStream;
HANDLE rgbStream;
INuiSensor* sensor;
bool initKinect() {
// Get a working kinect sensor
int numSensors;
if (NuiGetSensorCount(&numSensors) < 0 || numSensors < 1) return false;
if (NuiCreateSensorByIndex(0, &sensor) < 0) return false;
// Initialize sensor
sensor->NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH | NUI_INITIALIZE_FLAG_USES_COLOR);
sensor->NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH, // Depth camera or rgb camera?
NUI_IMAGE_RESOLUTION_640x480, // Image resolution
0, // Image stream flags, e.g. near mode
2, // Number of frames to buffer
NULL, // Event handle
&depthStream);
sensor->NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, // Depth camera or rgb camera?
NUI_IMAGE_RESOLUTION_640x480, // Image resolution
0, // Image stream flags, e.g. near mode
2, // Number of frames to buffer
NULL, // Event handle
&rgbStream);
return sensor;
}
void getDepthData(GLubyte* dest) {
float* fdest = (float*) dest;
long* depth2rgb = (long*) depthToRgbMap;
NUI_IMAGE_FRAME imageFrame;
NUI_LOCKED_RECT LockedRect;
if (sensor->NuiImageStreamGetNextFrame(depthStream, 0, &imageFrame) < 0) return;
INuiFrameTexture* texture = imageFrame.pFrameTexture;
texture->LockRect(0, &LockedRect, NULL, 0);
if (LockedRect.Pitch != 0) {
const USHORT* curr = (const USHORT*) LockedRect.pBits;
for (int j = 0; j < height; ++j) {
for (int i = 0; i < width; ++i) {
// Get depth of pixel in millimeters
USHORT depth = NuiDepthPixelToDepth(*curr++);
// Store coordinates of the point corresponding to this pixel
Vector4 pos = NuiTransformDepthImageToSkeleton(i, j, depth<<3, NUI_IMAGE_RESOLUTION_640x480);
*fdest++ = pos.x/pos.w;
*fdest++ = pos.y/pos.w;
*fdest++ = pos.z/pos.w;
// Store the index into the color array corresponding to this pixel
NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution(
NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480, NULL,
i, j, depth<<3, depth2rgb, depth2rgb+1);
depth2rgb += 2;
}
}
}
texture->UnlockRect(0);
sensor->NuiImageStreamReleaseFrame(depthStream, &imageFrame);
}
void getRgbData(GLubyte* dest) {
float* fdest = (float*) dest;
long* depth2rgb = (long*) depthToRgbMap;
NUI_IMAGE_FRAME imageFrame;
NUI_LOCKED_RECT LockedRect;
if (sensor->NuiImageStreamGetNextFrame(rgbStream, 0, &imageFrame) < 0) return;
INuiFrameTexture* texture = imageFrame.pFrameTexture;
texture->LockRect(0, &LockedRect, NULL, 0);
if (LockedRect.Pitch != 0) {
const BYTE* start = (const BYTE*) LockedRect.pBits;
for (int j = 0; j < height; ++j) {
for (int i = 0; i < width; ++i) {
// Determine rgb color for each depth pixel
long x = *depth2rgb++;
long y = *depth2rgb++;
// If out of bounds, then don't color it at all
if (x < 0 || y < 0 || x > width || y > height) {
for (int n = 0; n < 3; ++n) *(fdest++) = 0.0f;
}
else {
const BYTE* curr = start + (x + width*y)*4;
for (int n = 0; n < 3; ++n) *(fdest++) = curr[2-n]/255.0f;
}
}
}
}
texture->UnlockRect(0);
sensor->NuiImageStreamReleaseFrame(rgbStream, &imageFrame);
}
void getKinectData() {
GLubyte* ptr;
glBindBuffer(GL_ARRAY_BUFFER, vboId);
ptr = (GLubyte*) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
if (ptr) {
getDepthData(ptr);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, cboId);
ptr = (GLubyte*) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
if (ptr) {
getRgbData(ptr);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void rotateCamera() {
static double angle = 0.;
static double radius = 3.;
double x = radius*sin(angle);
double z = radius*(1-cos(angle)) - radius/2;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(x,0,z,0,0,radius/2,0,1,0);
angle += 0.05;
}
void drawKinectData() {
getKinectData();
rotateCamera();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, cboId);
glColorPointer(3, GL_FLOAT, 0, NULL);
glPointSize(1.f);
glDrawArrays(GL_POINTS, 0, width*height);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
int main(int argc, char* argv[]) {
if (!init(argc, argv)) return 1;
if (!initKinect()) return 1;
// OpenGL setup
glClearColor(0,0,0,0);
glClearDepth(1.0f);
// Set up array buffers
const int dataSize = width*height * 3 * 4;
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, dataSize, 0, GL_DYNAMIC_DRAW);
glGenBuffers(1, &cboId);
glBindBuffer(GL_ARRAY_BUFFER, cboId);
glBufferData(GL_ARRAY_BUFFER, dataSize, 0, GL_DYNAMIC_DRAW);
// Camera setup
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, width /(GLdouble) height, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,0,0,0,1,0,1,0);
// Main loop
execute();
return 0;
}
In order to use modern openGl with tinyobjloader, I'm trying to change the viewer exemple.
I just change the LoadObjAndConvert function, to add vertex array objects as i seen in this tutorial, and to no longer use the buffer object that contains all the data (position, indices, color, uv) because it seems that we can no longer use it with modern openGL.
Result look like I have bad vertex index, the model is only partly rendered, and if the model has only one mesh (the stanford bunny) it does not even show up.
The code is too long, but it is the same as the tinyobjloader viewer exemple, so I will only post functions that are different.
Here is the LoadObjAndConvert function modified (modified parts are between lines to help) :
static bool LoadObjAndConvert(float bmin[3], float bmax[3],
std::vector<DrawObject>* drawObjects,
std::vector<tinyobj::material_t>& materials,
std::map<std::string, GLuint>& textures,
const char* filename) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
timerutil tm;
tm.start();
std::string base_dir = GetBaseDir(filename);
if (base_dir.empty()) {
base_dir = ".";
}
#ifdef _WIN32
base_dir += "\\";
#else
base_dir += "/";
#endif
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
base_dir.c_str());
if (!err.empty()) {
std::cerr << err << std::endl;
}
tm.end();
if (!ret) {
std::cerr << "Failed to load " << filename << std::endl;
return false;
}
printf("Parsing time: %d [ms]\n", (int)tm.msec());
printf("# of vertices = %d\n", (int)(attrib.vertices.size()) / 3);
printf("# of normals = %d\n", (int)(attrib.normals.size()) / 3);
printf("# of texcoords = %d\n", (int)(attrib.texcoords.size()) / 2);
printf("# of materials = %d\n", (int)materials.size());
printf("# of shapes = %d\n", (int)shapes.size());
// Append `default` material
materials.push_back(tinyobj::material_t());
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%d].diffuse_texname = %s\n", int(i),
materials[i].diffuse_texname.c_str());
}
// Load diffuse textures
{
for (size_t m = 0; m < materials.size(); m++) {
tinyobj::material_t* mp = &materials[m];
if (mp->diffuse_texname.length() > 0) {
// Only load the texture if it is not already loaded
if (textures.find(mp->diffuse_texname) == textures.end()) {
GLuint texture_id;
int w, h;
int comp;
std::string texture_filename = mp->diffuse_texname;
if (!FileExists(texture_filename)) {
// Append base dir.
texture_filename = base_dir + mp->diffuse_texname;
if (!FileExists(texture_filename)) {
std::cerr << "Unable to find file: " << mp->diffuse_texname
<< std::endl;
exit(1);
}
}
unsigned char* image =
stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default);
if (!image) {
std::cerr << "Unable to load texture: " << texture_filename
<< std::endl;
exit(1);
}
std::cout << "Loaded texture: " << texture_filename << ", w = " << w
<< ", h = " << h << ", comp = " << comp << std::endl;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (comp == 3) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
GL_UNSIGNED_BYTE, image);
} else if (comp == 4) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, image);
} else {
assert(0); // TODO
}
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
}
}
}
}
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
{
for (size_t s = 0; s < shapes.size(); s++) {
/*-----------------------------------------------------------*/
DrawObject o;// I keep this object for later purpose, texture, etc
//std::vector<float> buffer; // pos(3float), normal(3float), color(3float)
//I replace "buffer" by arrays:
std::vector<GLfloat> mesh_vertex;
std::vector<GLfloat> mesh_normals;
std::vector<GLfloat> mesh_colors;
std::vector<GLfloat> mesh_textCoords;
std::vector<GLuint> mesh_indices;
/*fill index array*/
for (long i = 0; i < shapes[s].mesh.indices.size(); i++)
{
mesh_indices.push_back(shapes[s].mesh.indices[i].vertex_index);
}
/*-----------------------------------------------------------*/
// Check for smoothing group and compute smoothing normals
std::map<int, vec3> smoothVertexNormals;
if (hasSmoothingGroup(shapes[s]) > 0) {
std::cout << "Compute smoothingNormal for shape [" << s << "]" << std::endl;
computeSmoothingNormals(attrib, shapes[s], smoothVertexNormals);
}
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
int current_material_id = shapes[s].mesh.material_ids[f];
if ((current_material_id < 0) ||
(current_material_id >= static_cast<int>(materials.size()))) {
// Invaid material ID. Use default material.
current_material_id =
materials.size() -
1; // Default material is added to the last item in `materials`.
}
// if (current_material_id >= materials.size()) {
// std::cerr << "Invalid material index: " << current_material_id <<
// std::endl;
//}
//
float diffuse[3];
for (size_t i = 0; i < 3; i++) {
diffuse[i] = materials[current_material_id].diffuse[i];
}
float tc[3][2];
if (attrib.texcoords.size() > 0) {
if ((idx0.texcoord_index < 0) || (idx1.texcoord_index < 0) ||
(idx2.texcoord_index < 0)) {
// face does not contain valid uv index.
tc[0][0] = 0.0f;
tc[0][1] = 0.0f;
tc[1][0] = 0.0f;
tc[1][1] = 0.0f;
tc[2][0] = 0.0f;
tc[2][1] = 0.0f;
} else {
assert(attrib.texcoords.size() >
size_t(2 * idx0.texcoord_index + 1));
assert(attrib.texcoords.size() >
size_t(2 * idx1.texcoord_index + 1));
assert(attrib.texcoords.size() >
size_t(2 * idx2.texcoord_index + 1));
// Flip Y coord.
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1];
tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index];
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
}
} else {
tc[0][0] = 0.0f;
tc[0][1] = 0.0f;
tc[1][0] = 0.0f;
tc[1][1] = 0.0f;
tc[2][0] = 0.0f;
tc[2][1] = 0.0f;
}
float v[3][3];
for (int k = 0; k < 3; k++) {
int f0 = idx0.vertex_index;
int f1 = idx1.vertex_index;
int f2 = idx2.vertex_index;
assert(f0 >= 0);
assert(f1 >= 0);
assert(f2 >= 0);
v[0][k] = attrib.vertices[3 * f0 + k];
v[1][k] = attrib.vertices[3 * f1 + k];
v[2][k] = attrib.vertices[3 * f2 + k];
bmin[k] = std::min(v[0][k], bmin[k]);
bmin[k] = std::min(v[1][k], bmin[k]);
bmin[k] = std::min(v[2][k], bmin[k]);
bmax[k] = std::max(v[0][k], bmax[k]);
bmax[k] = std::max(v[1][k], bmax[k]);
bmax[k] = std::max(v[2][k], bmax[k]);
}
float n[3][3];
{
bool invalid_normal_index = false;
if (attrib.normals.size() > 0) {
int nf0 = idx0.normal_index;
int nf1 = idx1.normal_index;
int nf2 = idx2.normal_index;
if ((nf0 < 0) || (nf1 < 0) || (nf2 < 0)) {
// normal index is missing from this face.
invalid_normal_index = true;
} else {
for (int k = 0; k < 3; k++) {
assert(size_t(3 * nf0 + k) < attrib.normals.size());
assert(size_t(3 * nf1 + k) < attrib.normals.size());
assert(size_t(3 * nf2 + k) < attrib.normals.size());
n[0][k] = attrib.normals[3 * nf0 + k];
n[1][k] = attrib.normals[3 * nf1 + k];
n[2][k] = attrib.normals[3 * nf2 + k];
}
}
} else {
invalid_normal_index = true;
}
if (invalid_normal_index && !smoothVertexNormals.empty()) {
// Use smoothing normals
int f0 = idx0.vertex_index;
int f1 = idx1.vertex_index;
int f2 = idx2.vertex_index;
if (f0 >= 0 && f1 >= 0 && f2 >= 0) {
n[0][0] = smoothVertexNormals[f0].v[0];
n[0][1] = smoothVertexNormals[f0].v[1];
n[0][2] = smoothVertexNormals[f0].v[2];
n[1][0] = smoothVertexNormals[f1].v[0];
n[1][1] = smoothVertexNormals[f1].v[1];
n[1][2] = smoothVertexNormals[f1].v[2];
n[2][0] = smoothVertexNormals[f2].v[0];
n[2][1] = smoothVertexNormals[f2].v[1];
n[2][2] = smoothVertexNormals[f2].v[2];
invalid_normal_index = false;
}
}
if (invalid_normal_index) {
// compute geometric normal
CalcNormal(n[0], v[0], v[1], v[2]);
n[1][0] = n[0][0];
n[1][1] = n[0][1];
n[1][2] = n[0][2];
n[2][0] = n[0][0];
n[2][1] = n[0][1];
n[2][2] = n[0][2];
}
}
for (int k = 0; k < 3; k++) {
/*-----------------------------------------------------------*/
// I leave old calls to "buffer" in comment for understanding
//buffer.push_back(v[k][0]);
//buffer.push_back(v[k][1]);
//buffer.push_back(v[k][2]);
mesh_vertex.push_back(v[k][0]);
mesh_vertex.push_back(v[k][1]);
mesh_vertex.push_back(v[k][2]);
//buffer.push_back(n[k][0]);
//buffer.push_back(n[k][1]);
//buffer.push_back(n[k][2]);
mesh_normals.push_back(n[k][0]);
mesh_normals.push_back(n[k][1]);
mesh_normals.push_back(n[k][2]);
// Combine normal and diffuse to get color.
float normal_factor = 0.2;
float diffuse_factor = 1 - normal_factor;
float c[3] = {n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
n[k][2] * normal_factor + diffuse[2] * diffuse_factor};
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
if (len2 > 0.0f) {
float len = sqrtf(len2);
c[0] /= len;
c[1] /= len;
c[2] /= len;
}
//buffer.push_back(c[0] * 0.5 + 0.5);
//buffer.push_back(c[1] * 0.5 + 0.5);
//buffer.push_back(c[2] * 0.5 + 0.5);
mesh_colors.push_back(c[0] * 0.5 + 0.5);
mesh_colors.push_back(c[1] * 0.5 + 0.5);
mesh_colors.push_back(c[2] * 0.5 + 0.5);
//buffer.push_back(tc[k][0]);
//buffer.push_back(tc[k][1]);
mesh_textCoords.push_back(tc[k][0]);
mesh_textCoords.push_back(tc[k][1]);
/*-----------------------------------------------------------*/
}
}
o.vb_id = 0;
o.numTriangles = 0;
// OpenGL viewer does not support texturing with per-face material.
if (shapes[s].mesh.material_ids.size() > 0 &&
shapes[s].mesh.material_ids.size() > s) {
o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID
// of the first face.
} else {
o.material_id = materials.size() - 1; // = ID for default material.
}
printf("shape[%d] material_id %d\n", int(s), int(o.material_id));
/*-----------------------------------------------------------*/
/*if (buffer.size() > 0) {
glGenBuffers(1, &o.vb_id);
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float),
&buffer.at(0), GL_STATIC_DRAW);
o.numTriangles = buffer.size() / (3 + 3 + 3 + 2) /
3; // 3:vtx, 3:normal, 3:col, 2:texcoord
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
o.numTriangles);
}
drawObjects->push_back(o);*/
// Replace by :
GLuint positionVBO = 0;
GLuint texcoordVBO = 0;
GLuint normalVBO = 0;
GLuint indicesEBO = 0;
// Upload per-vertex positions
if (!mesh_vertex.empty())
{
glGenBuffers(1, &positionVBO);
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
glBufferData(GL_ARRAY_BUFFER, mesh_vertex.size() * sizeof(GLfloat), &mesh_vertex[0], GL_STATIC_DRAW); // GL_DYNAMIC_DRAW ?
glBindBuffer(GL_ARRAY_BUFFER, 0);
positionVBO_array.push_back(positionVBO);
}
// Upload per-vertex texture coordinates
if (!mesh_textCoords.empty())
{
glGenBuffers(1, &texcoordVBO);
glBindBuffer(GL_ARRAY_BUFFER, texcoordVBO);
glBufferData(GL_ARRAY_BUFFER,
mesh_textCoords.size() * sizeof(float),
&mesh_textCoords[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Upload per-vertex normals
if (!mesh_normals.empty())
{
glGenBuffers(1, &normalVBO);
glBindBuffer(GL_ARRAY_BUFFER, normalVBO);
glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(GLfloat), &mesh_normals[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
normalVBO_array.push_back(normalVBO);
}
// Upload the indices that form triangles
if (!shapes[0].mesh.indices.empty())
{
glGenBuffers(1, &indicesEBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
shapes[s].mesh.indices.size() * sizeof(unsigned int),
shapes[s].mesh.indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
indicesEBO_array.push_back(indicesEBO);
indicesEBOSize_array.push_back(shapes[s].mesh.indices.size());
}
// Hook up vertex/index buffers to a "vertex array object" (VAO)
// VAOs are the closest thing OpenGL has to a "mesh" object.
// VAOs feed data from buffers to the inputs of a vertex shader.
GLuint meshVAO;
vglGenVertexArrays(1, &meshVAO);
meshVAO_array.push_back(meshVAO);// I keep the ids in order to loop inside meshVAO_array in the draw function
// Attach position buffer as attribute 0
if (positionVBO != 0)
{
glBindVertexArray(meshVAO);
// Note: glVertexAttribPointer sets the current
// GL_ARRAY_BUFFER_BINDING as the source of data
// for this attribute.
// That's why we bind a GL_ARRAY_BUFFER before
// calling glVertexAttribPointer then
// unbind right after (to clean things up).
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
sizeof(float) * 3, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Enable the attribute (they are disabled by default
// -- this is very easy to forget!!)
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
// Attach texcoord buffer as attribute 1
if (texcoordVBO != 0)
{
glBindVertexArray(meshVAO);
glBindBuffer(GL_ARRAY_BUFFER, texcoordVBO);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
sizeof(float) * 2, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
// Attach normal buffer as attribute 2
if (normalVBO != 0)
{
glBindVertexArray(meshVAO);
glBindBuffer(GL_ARRAY_BUFFER, normalVBO);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE,
sizeof(float) * 3, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(2);
glBindVertexArray(0);
}
if (indicesEBO != 0)
{
glBindVertexArray(meshVAO);
// Note: Calling glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// when a VAO is bound attaches the index buffer to the VAO.
// From an API design perspective, this is subtle.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesEBO);
glBindVertexArray(0);
}
/*-----------------------------------------------------------*/
}
}
printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
return true;
}
(Sorry for this long code block)
And here is the while loop of the main function, the only difference with tinyobjloader is between the two lines:
unsigned int program = shaders::CreateShader("data/simple.vert", "data/simple.frag"); // just some really simples shaders
while (glfwWindowShouldClose(window) == GL_FALSE) {
glfwPollEvents();
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// camera & rotate
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat mat[4][4];
gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0],
up[1], up[2]);
build_rotmatrix(mat, curr_quat);
glMultMatrixf(&mat[0][0]);
// Fit to -1, 1
glScalef(1.0f / maxExtent, 1.0f / maxExtent, 1.0f / maxExtent);
// Centerize object.
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
-0.5 * (bmax[2] + bmin[2]));
/*-----------------------------------------------------------*/
//Draw(gDrawObjects, materials, textures);
// Can now bind the vertex array object to
// the graphics pipeline, to render with it.
glUseProgram(program);
for (int s = 0; s < meshVAO_array.size(); s++)
{
glBindVertexArray(meshVAO_array[s]);
glDrawElements(GL_TRIANGLES, indicesEBOSize_array[s], GL_UNSIGNED_INT, 0);//mesh.IndexCount
glBindVertexArray(0);
}
glUseProgram(0);
// when done, unbind it from the graphics pipeline:
glBindVertexArray(0);
/*-----------------------------------------------------------*/
glfwSwapBuffers(window);
}
What am I doing wrong?
In the nested loops you all the indices of shapes[].mesh.indices are use to lokkup the attributes, which are stored in attrib.vertices, attrib.normals and attrib.texcoords.
This attributes are prepared and linearized. They are stored in there idexed order to the linear arrays mesh_vertex, mesh_normals, mesh_colors and mesh_textCoords.
But the indices are directly copied from shapes[].mesh.indices to mesh_indices
for (long i = 0; i < shapes[s].mesh.indices.size(); i++)
{
mesh_indices.push_back(shapes[s].mesh.indices[i].vertex_index);
}
The indices in mesh_indices still refer to the vertex coordinates stored in attrib.vertices but the have no meaning for the attributes in the new containers.
The original indices are not needed any more. The indices of the new attribute would be continuously ascending: [0, 1, 2, 3, 4, 5 ...]
It is sufficient to draw the array of generic vertex attribute data in its existing order:
// you have to know the number of attributes
// something like mesh_vertex.size() / 3;
GLsizei no_of_attributes = .... ;
glBindVertexArray(meshVAO_array[s]);
glDrawArrays(GL_TRIANGLES, 0, no_of_attributes);
glBindVertexArray(0);
I am using freetype and freetype-gl to render text.
Unfortunately my text is rendering as quads.
That's how I am doing it:
enum
{
//Max num of objects
MAX_SPRITES = 60000,
//Max num of indices
//One sprite got 6 indices
MAX_INDICES = MAX_SPRITES * 6,
//Once sprite got 4 vertices
SPRITE_SIZE = sizeof(Vertex) * 4,
//Max num of GL_TEXTUREX => X -> int <0; 32>
MAX_TEXTURES = 32
};
enum BUFFER_SIZE
{
VERTEX = SPRITE_SIZE * MAX_SPRITES,
INDEX = MAX_INDICES * sizeof(GLuint),
};
enum SHADER_OUT
{
POSITION = 0,
COLOR = 1,
UV = 2,
TEXTURE = 3,
};
class Renderer2D
{
public:
Renderer2D() = default;
~Renderer2D();
void Create();
void RenderClear();
void DrawString(const std::string& text, const Vector2& position, const Color& color);
void Render();
private:
Uint vao = 0,
vbo = 0,
ebo = 0,
indexCount = 0,
drawCalls = 0;
ftgl::texture_atlas_t* textureAtlas = nullptr;
ftgl::texture_font_t* font = nullptr;
std::vector<MiUint> textureSlots;
Vertex* mappedVertex = nullptr;
void End();
Uint* SetIndices();
float FindTexture();
};
Renderer2D::~Renderer2D()
{
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
glDeleteVertexArrays(1, &vao);
ftgl::texture_atlas_delete(textureAtlas);
ftgl::texture_font_delete(font);
textureSlots.clear();
}
void Renderer2D::Create()
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, BUFFER_SIZE::VERTEX, nullptr, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_OUT::POSITION);
glEnableVertexAttribArray(SHADER_OUT::COLOR);
glEnableVertexAttribArray(SHADER_OUT::UV);
glEnableVertexAttribArray(SHADER_OUT::TEXTURE);
glVertexAttribPointer(SHADER_OUT::POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, position));
glVertexAttribPointer(SHADER_OUT::COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (const void*)offsetof(Vertex, color));
glVertexAttribPointer(SHADER_OUT::UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, uv));
glVertexAttribPointer(SHADER_OUT::TEXTURE, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, texID));
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, BUFFER_SIZE::INDEX, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, NULL, BUFFER_SIZE::INDEX, SetIndices());
glBindVertexArray(0);
textureAtlas = ftgl::texture_atlas_new(512, 512, 1);
font = ftgl::texture_font_new_from_file(textureAtlas, 50, "Media/arial.ttf");
}
void Renderer2D::RenderClear()
{
textureSlots.clear();
mappedVertex = nullptr;
mappedVertex = (Vertex*)glMapNamedBufferRange(vbo, NULL, BUFFER_SIZE::VERTEX, GL_MAP_WRITE_BIT);
}
void Renderer2D::DrawString(const std::string& text, const Vector2& position, const Color& color)
{
using namespace ftgl;
float ts = FindTexture(),
x = position.x;
for (MiUint i = 0; i < text.length(); i++) {
char c = text[i];
texture_glyph_t* glyph = texture_font_get_glyph(font, c);
if (glyph != nullptr) {
if (i > 0) {
float kerning = texture_glyph_get_kerning(glyph, text[i - 1]);
x += kerning;
}
float x0 = x + glyph->offset_x,
x1 = x0 + glyph->width,
y0 = position.y + glyph->offset_y,
y1 = y0 - glyph->height,
u0 = glyph->s0,
u1 = glyph->s1,
v0 = glyph->t0,
v1 = glyph->t1;
mappedVertex->position = Vector3(x0, y0, 0.0f);
mappedVertex->uv = Vector2(u0, v0);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
mappedVertex->position = Vector3(x0, y1, 0.0f);
mappedVertex->uv = Vector2(u0, v1);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
mappedVertex->position = Vector3(x1, y1, 0.0f);
mappedVertex->uv = Vector2(u1, v1);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
mappedVertex->position = Vector3(x1, y0, 0.0f);
mappedVertex->uv = Vector2(u1, v0);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
indexCount += 6;
x += glyph->advance_x;
}
}
}
void Renderer2D::Render()
{
End();
drawCalls = 0;
for (int i = 0; i < (int)textureSlots.size(); ++i) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, textureSlots[i]);
}
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
++drawCalls;
indexCount = 0;
textureSlots.clear();
mappedVertex = nullptr;
glDisable(GL_BLEND);
}
void Renderer2D::End()
{
glUnmapNamedBuffer(vbo);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
MiUint* Renderer2D::SetIndices()
{
MiUint* indices = new MiUint[BUFFER_SIZE::INDEX],
offset = 0;
for (int i = 0; i < BUFFER_SIZE::INDEX; i += 6) {
indices[i] = offset;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset;
offset += 4;
}
return indices;
}
float Renderer2D::FindTexture()
{
float result = 0.0f;
bool found = false;
for (MiUint i = 0; i < (MiUint)textureSlots.size(); i++) {
if (textureSlots[i] == textureAtlas->id) {
result = (float)(i + 1);
found = true;
break;
}
}
if (!found) {
if (textureSlots.size() >= MAX_TEXTURES)
{
Render();
RenderClear();
}
textureSlots.push_back(textureAtlas->id);
result = (float)(textureSlots.size());
}
return result;
}
and my main is just setting up a 2d camera (ortho matrix, etc.), renderer.Create, in main loop clear renderer, drawString("STRING", Vector2(0.0f, 0.0f), Color(255, 0, 0, 255)) and renderer render.
Result is like:
How to fix it? I went through drawString method and it seems as if it works perfectly fine. What causes that it's rendered like this?
#Rabbid76
Simply just
Vertex:
#version 460 core
layout (location = 0) in vec2 a_position;
layout (location = 1) in vec4 a_color;
layout (location = 2) in vec2 a_uv;
layout (location = 3) in float a_texID;
out vec2 v_fragmentUV;
out vec4 v_fragmentColor;
out vec2 v_fragmenPosition;
out float v_texID;
uniform mat4 u_camera;
void main()
{
gl_Position = u_camera * vec4(a_position, 0.0, 1.0);
v_fragmenPosition = a_position;
v_fragmentColor = a_color;
v_texID = a_texID;
v_fragmentUV = vec2(a_uv.x, 1 - a_uv.y);
}
Pixel:
#version 460 core
out vec4 outColor;
in vec2 v_fragmentUV;
in vec4 v_fragmentColor;
in vec2 v_fragmenPosition;
in float v_texID;
layout (location = 0) uniform sampler2D u_textureSampler[32];
void main()
{
int texID = int(v_texID - 0.5);
outColor = texture(u_textureSampler[texID], v_fragmentUV);
}
I set tetxure sampler uniform in main. When I render textures like a player it's rendered very well. There are only text problems.
Wher do you use glUniform* to set the texture unit index to the texture sampler uniform?
Maybe I should just show my main class
App2D::App2D()
{
window.Init(4, 6);
window.Create("w", 1280, 720, WINDOW_RESIZABLE);
camera.Projection(0.0f, 1280.0f, 0.0f, 720.0f);
SetupShaders();
renderer2D.Create();
glClearColor(0.5, 0.5, 0.5, 1.0);
/*short textureIDS[] = {
texture.LoadFromFile("Media/MenuImage.png"),
texture.LoadFromFile("Media/image1.png"),
texture.LoadFromFile("Media/image2.png"),
};
for (int y = 0; y < 720; y += 4.) {
for (int x = 0; x < 1280; x += 4.) {
sprite.push_back(new Sprite2D(Rect(x, y, 4.0f), Rect(0.0f, 0.0f, 1.0f, 1.0f), rand() % 3 + 1));
}
}
std::cout << sprite.size() << std::endl;*/
}
void App2D::MainLoop()
{
int frames = 0;
float time = 0.0f;
while (!quit) {
timer.Reset();
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
ExitGame();
}
UpdateInput();
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SetupCameraShader();
camera.Update();
Update(1.0f);
renderer2D.RenderClear();
renderer2D.DrawString("STRING", Vector2(0.0f, 0.0f), Color(255, 0, 0, 255));
renderer2D.Render();
window.SwapBuffers();
frames++;
if (timer.Elapsed() - time > 1.0f) {
time++;
Log("FPS: " + std::to_string(frames) + "\n");
frames = 0;
}
}
}
void App2D::SetupShaders()
{
shader.Free();
GLuint shaders[2] = {
shader.CreateShader("vertex.shader", GL_VERTEX_SHADER),
shader.CreateShader("fragment.shader", GL_FRAGMENT_SHADER)
}; shader.CreateAndUseProgram(shaders, 2);
GLint textures[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};
glUniform1iv(0, 10, textures);
}
void App2D::SetupCameraShader()
{
GLint u_camera = shader.GetUniformLocation("u_camera");
Mat4 cameraMatrix = Mat4(1.0f);
cameraMatrix = camera.getCameraMatrix();
//cameraMatrix = textCamera.getCameraMatrix();
glUniformMatrix4fv(u_camera, 1, GL_FALSE, &(cameraMatrix[0][0]));
}
1>------ Build started: Project: RageBotGamingEngine, Configuration: Debug Win32 ------
1> Sprite.cpp
1>c:\users\nha\documents\visual studio 2013\projects\ragebotgamingengine\ragebotgamingengine\sprite.cpp(51): error C4700: uninitialized local variable 'i' used
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Above is what the output logs say.
Below are some related files that could be involved with this problem:
Sprite.cpp
#include "Sprite.h"
#include "Vertex.h"
#include <cstddef>
Sprite::Sprite()
{
_vboID = 0;
}
Sprite::~Sprite()
{
if (_vboID != 0) {
glDeleteBuffers(1, &_vboID);
}
}
void Sprite::init(float x, float y, float width, float height) {
_x = x;
_y = y;
_width = width;
_height = height;
if (_vboID == 0) {
glGenBuffers(1, &_vboID);
}
Vertex vertexData[6];
//First Triangle
vertexData[0].position.x = x + width;
vertexData[0].position.y = y + width;
vertexData[1].position.x = x;
vertexData[1].position.y = y + height;
vertexData[2].position.x = x;
vertexData[2].position.y = y;
//Second Triangle
vertexData[3].position.x = x;
vertexData[3].position.y = y;
vertexData[4].position.x = x + width;
vertexData[4].position.y = y;
vertexData[5].position.x = x + width;
vertexData[5].position.y = y + height;
for (int i; i < 6; i++) {
vertexData[i].color.r = 255;
vertexData[i].color.g = 0;
vertexData[i].color.b = 255;
vertexData[i].color.a = 255;
}
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Sprite::draw() {
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glEnableVertexAttribArray(0);
//This is position attribute pointer
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
//This is color attribute pointer
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
I have tried to find the problem but I'm relatively new to OpenGL, SDL, & C++ & as you can imagine it has been a huge hassle because of the fact that the OpenGL wiki isn't exactly easy to follow & consistent. Just about any help would be very much needed as well as appreciated.
I'm trying to create a Game Engine (obviously I'm pretty much un-skilled & lack the time to develop this project)
for (int i; i < 6; i++)
should be
for (int i=0; i < 6; i++)
You declared variable 'i' but forgot to initialise the variable, so it could have any arbitrary value, not necessarily '0'