Results 1 to 9 of 9

Thread: Custom 3D object class not working

  1. #1
    Junior Member Newbie
    Join Date
    Jun 2016
    Posts
    9

    Question Custom 3D object class not working

    I have been learning OpenGL for a while now, and I decided to try to make my own "game engine".
    My first step is to create a class for a 3D object.
    The constructor assigns its arguments to class variables (for example, the object's position).
    There are also three other functions: void init() - initializes OpenGL stuff, void update() - updates the model, view and projection matrices, void draw() - draws the object.
    But it doesn't work. The program doesn't draw anything and I can't find the error.
    Code (it doesn't let me post links):

    main.cpp
    Code :
    #define GLEW_STATIC
    #define GLM_FORCE_RADIANS
    #include <glew.h>
    #include <GLFW\glfw3.h>
    #include <glm\glm.hpp>
    #include <glm\gtc\matrix_transform.hpp>
    #include <glm\gtc\type_ptr.hpp>
    #include <SOIL.h>
     
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <chrono>
     
    #include "shaders.h"
    #include "object.h"
     
    using namespace std;
     
    float vertices [] =
    {
    	// cube
    	-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    	0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	-0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
     
    	-0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    	0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	-0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	-0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
     
    	-0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	-0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	-0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    	-0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
     
    	0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    	0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
     
    	-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	-0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    	-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
     
    	-0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    	0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    	0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    	-0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    	-0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f
    };
     
    int main()
    {
    	glfwInit();
     
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    	glfwWindowHint(GLFW_SAMPLES, 4);
    	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
     
    	GLFWwindow* window = glfwCreateWindow(1024, 768, "opengl tutorial", nullptr, nullptr);
     
    	if (window == nullptr)
    	{
    		cout << "Failed to create window" << endl;
    		glfwTerminate();
    		system("pause");
    		return -1;
    	}
     
    	glfwMakeContextCurrent(window);
     
    	cout << "Address of window: " << window << endl;
     
    	glewExperimental = GL_TRUE;
    	glewInit();
     
    	glEnable(GL_DEPTH_TEST);
    	glEnable(GL_MULTISAMPLE);
     
    	GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    	string vsStr = loadShader("vertex.glsl");
    	const char* vsSource = vsStr.c_str();
    	glShaderSource(vs, 1, &vsSource, nullptr);
    	glCompileShader(vs);
     
    	char vsLog[512];
    	glGetShaderInfoLog(vs, 512, nullptr, vsLog);
    	cout << "Vertex shader output: " << endl;
    	cout << vsLog << endl;
     
    	GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    	string fsStr = loadShader("fragment.glsl");
    	const char* fsSource = fsStr.c_str();
    	glShaderSource(fs, 1, &fsSource, nullptr);
    	glCompileShader(fs);
     
    	char fsLog[512];
    	glGetShaderInfoLog(fs, 512, nullptr, fsLog);
    	cout << "Fragment shader output: " << endl;
    	cout << fsLog << endl;
     
    	GLuint prog = glCreateProgram();
    	glAttachShader(prog, vs);
    	glAttachShader(prog, fs);
    	glLinkProgram(prog);
     
    	float rot = 0.0f;
     
    	glm::mat4 model;
    	model = glm::mat4(1.0f) * glm::rotate(model, glm::radians(rot), glm::vec3(0.0f, 1.0f, 0.0f));
     
    	glm::mat4 view;
    	view = glm::lookAt(glm::vec3(0.0f, 1.2f, 3.5f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
     
    	glm::mat4 proj;
    	proj = glm::perspective(glm::radians(45.0f), 1024.0f / 768.0f, 1.0f, 10.0f);
     
    	object cube(vertices, 36, "box-texture.png", prog, glm::vec3(0.0f, 0.0f, 0.0f), view, proj);
    	cube.init();
     
    	while (!glfwWindowShouldClose(window))
    	{
    		if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    			glfwSetWindowShouldClose(window, GL_TRUE);
     
    		int currentL = glfwGetKey(window, GLFW_KEY_LEFT);
    		int currentR = glfwGetKey(window, GLFW_KEY_RIGHT);
    		if (currentL == GLFW_PRESS)
    		{
    			rot += 1.0f;
    		}
    		else if (currentR == GLFW_PRESS)
    		{
    			rot -= 1.0f;
    		}
     
    		glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    		cube.update();
    		cube.draw();
     
    		glfwSwapBuffers(window);
    		glfwPollEvents();
    	}
     
    	glDeleteShader(vs);
    	glDeleteShader(fs);
     
    	glfwTerminate();
     
    	return 0;
    }

    object.h
    Code :
    #pragma once
     
    #include <glew.h>
    #include <GLFW\glfw3.h>
    #include <glm\gtc\matrix_transform.hpp>
    #include <glm\gtc\type_ptr.hpp>
    #include <SOIL.h>
     
    #include "shaders.h"
    #include <iostream>
     
    using namespace std;
     
    // 3D object
    class object
    {
    public:
    	GLuint vbo;
    	GLuint vao;
    	GLuint texture;
    	GLuint prog; // shader program to use
    	glm::vec3 position;
    	float* vertices;
    	int count; // number of vertices
    	const char* texName; // texture file name
    	glm::mat4 model; //
    	glm::mat4 view;  // matrices
    	glm::mat4 proj;  //
    	GLint posAttrib;  //
    	GLint colAttrib;  // attributes
    	GLint texAttrib;  //
    	GLint uniModel;    //
    	GLint uniView;     // uniforms
    	GLint uniProj;     //
     
    	object(float* _vertices, int _count, const char* _texName, GLuint _prog, glm::vec3 _pos, glm::mat4 _view, glm::mat4 _proj)
    	{
    		vertices = _vertices;
    		prog = _prog;
    		position = _pos;
    		count = _count;
    		texName = _texName;
    		model = glm::mat4(1.0f) * glm::translate(model, position);
    		view = _view;
    		proj = _proj;
    	}
     
    	void init()
    	{
    		glGenVertexArrays(1, &vao);
    		glBindVertexArray(vao);
     
    		glGenBuffers(1, &vbo);
    		glBindBuffer(GL_ARRAY_BUFFER, vbo);
    		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
     
    		glUseProgram(prog);
     
    		posAttrib = glGetAttribLocation(prog, "pos"); // position
    		glEnableVertexAttribArray(posAttrib);
    		glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), nullptr);
     
    		colAttrib = glGetAttribLocation(prog, "vColor"); // color
    		glEnableVertexAttribArray(colAttrib);
    		glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3 * sizeof(float)));
     
    		texAttrib = glGetAttribLocation(prog, "tex_coord"); // tex coords
    		glEnableVertexAttribArray(texAttrib);
    		glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (6 * sizeof(float)));
     
    		uniModel = glGetUniformLocation(prog, "model");
    		uniView = glGetUniformLocation(prog, "view");
    		uniProj = glGetUniformLocation(prog, "proj");
     
    		int w, h;
    		unsigned char* texData = SOIL_load_image(texName, &w, &h, nullptr, SOIL_LOAD_RGB);
    		if (texData == nullptr)
    		{
    			cout << "The texture is nullptr" << endl;
    			system("pause");
    		}
    		else
    		{
    			glGenTextures(1, &texture);
    			glBindTexture(GL_TEXTURE_2D, texture);
    			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texData);
    			SOIL_free_image_data(texData);
    			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    			glGenerateMipmap(GL_TEXTURE_2D);
     
    			glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
    			glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));
    			glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
    		}
    	}
     
    	void update()
    	{
    		glUseProgram(prog);
    		model = glm::mat4(1.0f) * glm::translate(model, position);
     
    		glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
    		glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));
    		glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
    	}
     
    	void draw()
    	{
    		// binding stuff before drawing (in case more objects are drawn)
    		glBindVertexArray(vao);	
    		glBindBuffer(GL_ARRAY_BUFFER, vbo);
    		glBindTexture(GL_TEXTURE_2D, texture);
     
    		glDrawArrays(GL_TRIANGLES, 0, count);
    	}
     
    	~object()
    	{
    		glDeleteBuffers(1, &vbo);
    		glDeleteVertexArrays(1, &vao);
    		glDeleteTextures(1, &texture);
    	}
    };

    You can notice that I'm loading shaders with my own function from another file, but that has nothing to do with this.

    Thanks

  2. #2
    Senior Member Regular Contributor
    Join Date
    May 2016
    Posts
    477
    i just want to point out, that using for each object a new vertex array / buffer isnt the "best" solution
    you should decouple models (contains much data) from actual objects (only instances with a model matrix and further object infos)

    why dont you start with a simple triangle tutorial and if you got it working, expand your code with additional features like texture / normals / light etc

    you didnt check for the shaders link status / errors, what does glGetError() say ?

  3. #3
    Junior Member Newbie
    Join Date
    Jun 2016
    Posts
    9
    Thanks for your quick answer.

    Quote Originally Posted by john_connor View Post
    i just want to point out, that using for each object a new vertex array / buffer isnt the "best" solution
    you should decouple models (contains much data) from actual objects (only instances with a model matrix and further object infos)
    I removed it and put the VAO back in main().

    Quote Originally Posted by john_connor View Post
    why dont you start with a simple triangle tutorial and if you got it working, expand your code with additional features like texture / normals / light etc
    Now I removed the texture part and just tried to render a triangle with red, green and blue vertices (I changed the offsets in glVertexAttribPointer accordingly).

    Quote Originally Posted by john_connor View Post
    you didnt check for the shaders link status / errors, what does glGetError() say ?
    Shaders don't give any errors, but glGetError() returns GL_INVALID_ENUM. I guess that it means that some function doesn't like a GLenum type argument?

  4. #4
    Senior Member Regular Contributor
    Join Date
    Sep 2013
    Posts
    186
    Quote Originally Posted by syntax_error View Post
    glGetError() returns GL_INVALID_ENUM. I guess that it means that some function doesn't like a GLenum type argument?
    Yes exactly. Some argument which you pass to some method is wrong. To find out which it is you have to call glGetError() after every opengl call. When you found out which method produces the error you can look up in the reference pages what INVALID_ENUM means for that particular opengl method.

  5. #5
    Junior Member Newbie
    Join Date
    Jun 2016
    Posts
    9
    Now I have no idea what is going on.
    I made a function for processing the glGetError error:
    Code :
    void error(GLenum e)
    {
    	switch (e)
    	{
    	case GL_INVALID_ENUM:
    		cout << "Error: GL_INVALID_ENUM" << endl;
    		system("pause");
    		glfwTerminate();
    		break;
    	case GL_INVALID_VALUE:
    		cout << "Error: GL_INVALID_VALUE" << endl;
    		system("pause");
    		glfwTerminate();
    		break;
    	case GL_INVALID_OPERATION:
    		cout << "Error: GL_INVALID_OPERATION" << endl;
    		system("pause");
    		glfwTerminate();
    		break;
    	case GL_INVALID_FRAMEBUFFER_OPERATION:
    		cout << "Error: GL_INVALID_FRAMEBUFFER_OPERATION" << endl;
    		system("pause");
    		glfwTerminate();
    		break;
    	case GL_OUT_OF_MEMORY:
    		cout << "Error: GL_OUT_OF_MEMORY" << endl;
    		system("pause");
    		glfwTerminate();
    		break;
    	case GL_NO_ERROR:
    		cout << "No error reported" << endl;
    		break;
    	}
    }

    And I called it after the first four or five OpenGL function calls.
    Here's the strange part.
    I called it first after my first OpenGL call (that is glEnable(GL_DEPTH_TEST)). It returns GL_INVALID_ENUM. But the other calls all return GL_INVALID_OPERATION.
    Then I comment out the first glGetError call so the second one becomes the first. Now that one returns GL_INVALID_ENUM and all others return GL_INVALID_OPERATION.
    If I comment out the second so the third call is the first, the same happens.
    What is going on?!

  6. #6
    Senior Member Regular Contributor
    Join Date
    Sep 2013
    Posts
    186
    Errors are buffered. The INVALID_ENUM is generated at some point in your program and kept until you call glGetError() for the first time. It doesnt matter if you call it immediately after the call that generated the error or at some later point in time. Its all explained within the reference pages: https://www.opengl.org/sdk/docs/man/...GetError.xhtml

  7. #7
    Senior Member Regular Contributor
    Join Date
    May 2016
    Posts
    477
    just tested that code: i get a access violation if that part remains in main()
    Code :
    //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    	//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    	//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    	//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    	//glfwWindowHint(GLFW_SAMPLES, 4);
    	//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    if i comment that part out, it works

    another thing i want to point out:
    its one thing to get a VAO working aand pointers correct, its another to develop a complete game engine
    Code :
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    std::cout << "just a test for the array size:       " << sizeof(vertices) << std::endl;
    that little test says: you are just filling 8 bytes (= size of a x64 pointer) into your buffer
    i would recommend to use c++ containers such as <vector> and pass it to that "object" by &reference

    to make a simple model renderer shouldnt be that difficult, te question is only: how good it'll be
    http://www.cplusplus.com/articles/28hv0pDG/
    http://www.cplusplus.com/articles/1w6AC542/

  8. #8
    Junior Member Newbie
    Join Date
    Jun 2016
    Posts
    9
    Yep, the fact that I'm using a float pointer is a problem.
    I just tried to define the vertices in a float array as a global variable and it works.
    Now the problem is that OpenGL doesn't like vectors.
    Apparently there is a trick to convert a vector to an array:
    Code :
    float* arr = &vec[0];
    But I still get a pointer so it doesn't work.
    I tried to do this:
    Code :
    int count; // this is a class-level variable, number of vertices
    ....
    float v[8 * count]; // 3 coords, 3 colors, 2 texcoords; ERROR: expression did not evaluate to a constant
    for (int i = 0; i < (8 * count); i++)
    {
        v[i] = vec[i];
    }

    But it doesn't work.
    I also tried to define 8 * count as a const int variable, but although that variable is const, it still won't let me use it as array size.
    I'm out of ideas.

  9. #9
    Junior Member Newbie
    Join Date
    Jun 2016
    Posts
    9
    I solved it. I just had to put sizeof(vertices) * count * 8 as size argument for glBufferData, as there are count vertices and each vertex has 3 coords, 3 color components and 2 texcoords (3+3+2=

Similar Threads

  1. OpenGL Attrib Pointer Not Working Inside Class Method
    By BenSwolo in forum OpenGL: Basic Coding
    Replies: 4
    Last Post: 03-26-2018, 12:42 AM
  2. Code not working when inside class constructor?
    By Todegal in forum OpenGL: Basic Coding
    Replies: 4
    Last Post: 01-24-2017, 10:50 AM
  3. Depth test for custom framebuffer not working
    By Blizzard_jedi in forum OpenGL: Basic Coding
    Replies: 6
    Last Post: 06-16-2014, 04:30 PM
  4. rotate around a custom object
    By bbazatu in forum OpenGL: Advanced Coding
    Replies: 1
    Last Post: 04-18-2006, 10:47 PM
  5. rotate around custom object
    By in forum OpenGL: Basic Coding
    Replies: 3
    Last Post: 04-15-2006, 11:25 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean