OpenGL black window

I'm trying to make a program that loads a .obj file, and a .tga file for materials/color, but all it shows is a sad black screen.
Disclaimer: This is a university project, which means i can´t simply download libraries to make my life easier, also I´m only allowed to use OpenGL, GLM and GLFW. A library provided by the teacher is being used on "Load_textures()", and the function itself is provided by the teacher as well, so it should be working properly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#pragma comment(lib, "glew32s.lib")
#pragma comment(lib, "glfw3.lib")
#pragma comment(lib, "opengl32.lib")

#include<GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>//prinf and stuff
#include <glm\glm.hpp>
#include <vector>//vectors and stuff
#include "stb_image.h"

//#include <string>
//#include <algorithm>
//#include <stdio.h>
//#include <string>
//#include <fstream>

#define WIDTH 800
#define HEIGHT 600

GLFWwindow *window;
char*image = "Iron_Man_D.tga";

std::vector< unsigned int > vertexIndices, uvIndices, normalIndices;
std::vector< glm::vec3 > temp_vertices;
std::vector< glm::vec2 > temp_uvs;
std::vector< glm::vec3 > temp_normals;
std::vector< glm::vec3 > out_vertices;
std::vector< glm::vec2 > out_uvs;
std::vector< glm::vec3 > out_normals;

bool LoadModelVertex(FILE *file);
void draw();
void display();

int main()
{
	//start glfw
	if (!glfwInit()) return -1;

	//create window
	window = glfwCreateWindow(WIDTH, HEIGHT, "A window", NULL, NULL);
	if (window == NULL)
	{
		glfwTerminate();
		return -1;
	}
	//use window
	glfwMakeContextCurrent(window);

	//ativa sincronização vertical
	glfwSwapInterval(1);

	FILE *file = fopen("Iron_Man.obj", "r");
	if (file == NULL)
	{
		printf("Impossible to open the file !\n");
		return false;
	}

	//load .obj
	LoadModelVertex(file);
	//load image
	Load_texture(image);

	//set color to clear window with
	glClearColor(0, 0, 0, 0);
	//set max clear depth default
	glClearDepth(1);
	//set min clear stencil default
	glClearStencil(0);

	display();

	//release glfw stuff
	glfwTerminate();
}

void draw()
{
	//ativa o array para escrita, e drawarrays() usa isto
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);

	//localização e formato dos dados com as coordenadas do array dado (vertices+cor)
	glVertexPointer(out_vertices.size(), GL_FLOAT, 0, &out_vertices);
	glVertexPointer(out_uvs.size(), GL_FLOAT, 0, &out_uvs);

	glDrawArrays(GL_TRIANGLES, 0, out_vertices.size());

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);

	printf("drew a frame\n");
}

void display()
{
	do
	{
		//clear stuff
		glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT || GL_STENCIL_BUFFER_BIT);

		draw();

		//swap buffers bcs we using back/front buffer
		glfwSwapBuffers(window);

		//processa eventos e retorna de seguida
		glfwPollEvents();

	} while (!glfwWindowShouldClose(window));
}

bool LoadModelVertex(FILE *file)
{
	//read vertexes

	while (1)//read .obj
	{
		char lineHeader[128];
		// read the first word of the line
		int res = fscanf(file, "%s", lineHeader);
		if (res == EOF)
		{
			break;
		}// EOF = End Of File

		if (strcmp(lineHeader, "v") == 0)
		{
			glm::vec3 vertex;
			fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
			temp_vertices.push_back(vertex);
		}
		else if (strcmp(lineHeader, "vt") == 0)
		{
			glm::vec2 uv;
			fscanf(file, "%f %f\n", &uv.x, &uv.y);
			temp_uvs.push_back(uv);
		}
		else if (strcmp(lineHeader, "vn") == 0)
		{
			glm::vec3 normal;
			fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
			temp_normals.push_back(normal);
		}
		else if (strcmp(lineHeader, "f") == 0)
		{
			std::string vertex1, vertex2, vertex3;
			unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
			int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
			if (matches != 9)
			{
				printf("File can't be read :(\n");
				return false;
			}
			vertexIndices.push_back(vertexIndex[0]);
			vertexIndices.push_back(vertexIndex[1]);
			vertexIndices.push_back(vertexIndex[2]);
			uvIndices.push_back(uvIndex[0]);
			uvIndices.push_back(uvIndex[1]);
			uvIndices.push_back(uvIndex[2]);
			normalIndices.push_back(normalIndex[0]);
			normalIndices.push_back(normalIndex[1]);
			normalIndices.push_back(normalIndex[2]);
		}
	}

	for (unsigned int i = 0; i < vertexIndices.size(); i++)
	{
		// Get the indices of its attributes
		unsigned int vertexIndex = vertexIndices[i];
		unsigned int uvIndex = uvIndices[i];
		unsigned int normalIndex = normalIndices[i];

		// Get the attributes thanks to the index
		glm::vec3 vertex = temp_vertices[vertexIndex - 1];
		glm::vec2 uv = temp_uvs[uvIndex - 1];
		glm::vec3 normal = temp_normals[normalIndex - 1];

		// Put the attributes in buffers
		out_vertices.push_back(vertex);
		out_uvs.push_back(uv);
		out_normals.push_back(normal);
	}
	fclose(file);
	return true;
}

void Load_texture(char *namepath) {
	GLuint textureName = 0;

	// Gera um nome de textura
	glGenTextures(1, &textureName);

	// Ativa a Unidade de Textura #0
	// A Unidade de Textura 0 já está ativa por defeito.
	// Só uma Unidade de Textura está ativa a cada momento.
	glActiveTexture(GL_TEXTURE0);

	// Vincula esse nome de textura ao target GL_TEXTURE_2D da Unidade de Textura ativa.
	glBindTexture(GL_TEXTURE_2D, textureName);

	// Define os parâmetros de filtragem (wrapping e ajuste de tamanho)
	// para a textura que está vinculada ao target GL_TEXTURE_2D da Unidade de Textura ativa.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	// Leitura/descompressão do ficheiro com imagem de textura
	int width, height, nChannels;
	// Ativa a inversão vertical da imagem, aquando da sua leitura para memória.
	stbi_set_flip_vertically_on_load(true);
	// Leitura da imagem para memória do CPU
	unsigned char *imageData = stbi_load(namepath, &width, &height, &nChannels, 0);
	if (imageData) {
		// Carrega os dados da imagem para o Objeto de Textura vinculado ao target GL_TEXTURE_2D da Unidade de Textura ativa.
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, nChannels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, imageData);

		// Gera o Mipmap para essa textura
		glGenerateMipmap(GL_TEXTURE_2D);

		// Liberta a imagem da memória do CPU
		stbi_image_free(imageData);
	}
	else {
		printf("Error loading texture!\n");
	}
	printf("Texture loaded?\n");
}
Im rusty, but the last time I had to display an image in opengl I seem to recall that I would create a rectangle of the dimensions of the image, the texture the rectangle with that, and display the image that way. There may be a way to directly display one, but I can't recall it.

You didn't specify what exactly the problem is. Anyways, there's an excellent library that parses .obj files for you called assimp but I assume you are unable to use it. I've written my own .obj parser once but that was a while ago so I'm quite rusty in that area as well. Anyways, you need to ensure that you are reading all the vertices properly. Chuck in a breakpoint and go through your code step by step. The first step is to read the .obj file. Then, make sure you are storing all the vertices in your glm::vec3 data structures. Once that's done, send the data down the rendering pipeline in order to render the model. You may use a tool called Nsight for graphics debugging that's made by NVIDIA to see if the model is being rendered as it could be rendering fine except it's not in your view space. Good luck.
The problem is I can´t seem to figure out the problem itself... I suspect it's somewhere on passing the data from my vec3 arrays to the buffers, but I don't know what exactly... All i get is a black screen; if my vertexes were disorganized somehow then at least a mess of triangles would show up, but that is not the case...
I haven't done shaders yet, but I assume it shows the model on some default shading if none is specified...
As for that Nsight, I'll give that a go, it might just be behind the camera and I'm being retarded

EDIT:
So i didn't manage to use Nsight, aparently the driver I have is too recent... but I've used this instead on my code:
lookAt(*new vec3(0, 0, 0), *new vec3(0, 0, 1), *new vec3(0, 1, 0));//position, facing,UP
which turns my camera around (it faces the -z direction by default, and i set it to z) from glm, but i still get a black screen :(
I willl reopen the question, trying to focus on what i think is the problem
Last edited on
I don't know why Nsight wouldn't work for you as it works fine on my device and my drivers are up to date as well. Anyway, what I would do is try to draw a simple triangle with the code you have to ensure your rendering code as well as your shaders are functioning correctly. If that's the case, then make sure you are doing the same thing for your iron man model whereby the vertices are being stored properly and you are sending them correctly to the render pipeline. I personally use VAOs and VBOs to render objects to the screen using glGenVertexArrays() and glGenBuffers().
Visual studios tells me it needs an outdated driver, i have a more recent one...

Anyways, I've tried your sugestion UK, tryed to draw a simple triangle, and nothing showed up anyways (black screen), here's what i did:

std::vector< glm::vec3 > test;
test.push_back(vec3(0.5f, 0, -2));
test.push_back(vec3(-0.5f, 0, -2));
test.push_back(vec3(0, 1, -2));

main initializes...

display() ->

do
{
//clear stuff
glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT);

DrawTest();

//swap buffers bcs we using back/front buffer
glfwSwapBuffers(window);

//processa eventos e retorna de seguida
glfwPollEvents();

} while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&glfwWindowShouldClose(window) == 0);

And my DrawTest() ->

glEnableClientState(GL_VERTEX_ARRAY);

glVertexPointer(test.size(), GL_FLOAT, 0, &test);

glDrawArrays(GL_TRIANGLES, 0, test.size());

glDisableClientState(GL_VERTEX_ARRAY);

printf("drew a frame\n");

So unless i failed at constructing a triangle, i think the drawing process is what's failing... I'm not sure what though... I'm a complete noob in this ;(
Hello, sorry for not responding, I've been very busy for the past few days.

Not sure if you've fixed this by now, but since you cannot get a simple triangle going, the problem could be either one of two things (or both things really):

1. Something to do with your shader program (ensure that your shader is being created, linked, and compiled successfully)
2. The way you are sending your vertex data is wrong (ensure you are allocating the necessary amount of data in bytes on the GPU side)

I can see in your DrawTest() function that you never bind a shader program. I don't know how much of modern OpenGL you known, but to draw something in modern OpenGL you will need to have a shader program. Unless you use direct-mode (glBegin and glEnd but these are deprecated and I'm pretty sure your professor wouldn't want you using them). I recommend giving this a read: https://learnopengl.com/Getting-started/Hello-Triangle

Good luck!
Topic archived. No new replies allowed.