I'm writing a simple but useful OpenGL program for my work, which consists of showing how a vector field looks like. So the program simply takes the data from a file and draws arrows. I need to draw a few thousands of arrows. I'm using Qt for windows and OpenGL API.
The arrow unit is a cylinder and a cone, combined together in the function Arrow().
for(long i = 0; i < modifiedArrows.size(); i++) {
glColor4d(modifiedArrows[i].color.redF(),modifiedArrows[i].color.greenF(),
modifiedArrows[i].color.blueF(),modifiedArrows[i].opacity);
openGLobj->Arrow(modifiedArrows[i].fromX,modifiedArrows[i].fromY,
modifiedArrows[i].fromZ,modifiedArrows[i].toX,
modifiedArrows[i].toY,modifiedArrows[i].toZ,
simulationSettings->vectorsThickness);
}
Now the problem is that running an infinite loop to keep drawing this gets the CPU fully busy, which is not so nice. I tried as much as possible to remove all calculations from the paintGL() functions, and only simple ones remained. I end The paintGL() function with glFlush() and glFinish(), and yet I always have the main CPU full.
If I remove this loop, the CPU doesn't get too busy anymore. But I have to draw thousands of arrows anyway.
Is there any solution to this other than parallelizing?
You didn't pointed out on how you have implemented your openGLobj->Arrow method, but if you are using 100% CPU time on this, you are probably painting the arrows with immediate mode. This is really CPU intensive, because you have to transfer data from CPU to the GPU for every single instruction inside glBegin() and glEnd(). If you are using GLUT to draw your data, it's really ineficient too.
The way to go here is use GPU memory and processing power to dipslay your data. Phyatt has already pointed you some directions, but I will try to be more specific: use a Vertex Buffer Object (VBO).
The idea is to pre-allocate the needed memory for display your data on GPU and just update this chunk of memory when needed. This will probably make a huge difference on the efficience of your code, because you will use the efficient video card driver to handle the CPU->GPU transfers.
To illustrate the concept, I will show you just some pseudo-code in the end of the answer, but it's by no means completely correct. I didn't tested it and didn't had time to implement the drawing for you, but's it's a concept that can clarify your mind.
class Form
{
public:
Form()
{
// generate a new VBO and get the associated ID
glGenBuffers(1, &vboId);
// bind VBO in order to use
glBindBuffer(GL_ARRAY_BUFFER, vboId);
//Populate the buffer vertices.
generateVertices();
// upload data to VBO
glBufferData(GL_ARRAY_BUFFER_ARB, vertices.size(), vertices.data(), GL_STATIC_DRAW_ARB);
}
~Form()
{
// it is safe to delete after copying data to VBO
delete [] vertices;
// delete VBO when program terminated
glDeleteBuffersARB(1, &vboId);
}
//Implementing as virtual, because if you reimplement it on the child class, it will call the child method :)
//Generally you will not need to reimplement this class
virtual void draw()
{
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
//I am drawing the form as triangles, maybe you want to do it in your own way. Do it as you need! :)
//Look! I am not using glBegin() and glEnd(), I am letting the video card driver handle the CPU->GPU
//transfer in a single instruction!
glDrawElements(GL_TRIANGLES, vertices.size(), GL_UNSIGNED_BYTE, 0);
glDisableClientState(GL_VERTEX_ARRAY);
// bind with 0, so, switch back to normal pointer operation
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
private:
//Populate the vertices vector with the form vertices.
//Remember, any geometric form in OpenGL is rendered as primitives (points, quads, triangles, etc).
//The common way of rendering this is to use multiple triangles.
//You can draw it using glBegin() and glEnd() just to debug. After that, instead of rendering the triangles, just put
//the generated vertices inside the vertices buffer.
//Consider that it's at origin. You can use push's and pop's to apply transformations to the form.
//Each form(cone or cilinder) will have its own way of drawing.
virtual void generateVertices() = 0;
GLuint vboId;
std::vector<GLfloat> vertices;
}
class Cone : public Form
{
public:
Cone() : Form() {}
~Cone() : ~Form() {}
private:
void generateVertices()
{
//Populate the vertices with cone's formula. Good exercise :)
//Reference: http://mathworld.wolfram.com/Cone.html
}
GLuint vboId;
std::vector<GLfloat> vertices;
}
class Cilinder : public Form
{
public:
Cone() : Form() {}
~Cone() : ~Form() {}
private:
void generateVertices()
{
//Populate the vertices with cilinders's formula. Good exercise :)
//Reference: http://math.about.com/od/formulas/ss/surfaceareavol_3.htm
}
GLuint vboId;
std::vector<GLfloat> vertices;
}
class Visualizer : public QOpenGLWidget
{
public:
//Reimplement the draw function to draw each arrow for each data using the classes below.
void updateGL()
{
for(uint i = 0; i<data.size(); i++)
{
//I really don't have a clue on how you position your arrows around your world model.
//Keep in mind that those functions glPush, glPop and glMatrix are deprecated. I recommend you reading
//http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Chapter-3:-3D-transformation-and-projection.html if you want to implement this in the most efficient way.
glPush();
glMatrix(data[i].transform());
cilinder.draw();
cone.draw();
glPop();
}
}
private:
Cone cone;
Cilinder cilinder;
std::vector<Data> data;
}
As a final note, I can't assure you that this is the most efficient way of doing things. Probably, if you have a HUGE ammount of data, you would need some data-structure like Octrees or scene-graphs to optimize your code.
I recommend you taking a look at OpenSceneGraph or Visualization ToolKit to see if that methods are not already implemented for you, what would save you a lot of time.
Try this link for some ideas:
What are some best practices for OpenGL coding (esp. w.r.t. object orientation)?
Basically what I've seen that people do to increase their FPS and drop quality includes the following:
Using DisplayLists. (cache complex or repetitive matrix stacks).
Using Vertex Arrays.
Using simpler geometry with fewer faces.
Using simpler lighting.
Using simpler textures.
The main advantage of OpenGL is that is works with a lot of graphics cards, which are built to do a lot of the 4x4 matrix transformations, multiplications, etc, very quickly and they provide more RAM memory for storing rendered or partially rendered objects.
Assuming that all the vectors are changing so much and often that you can't cache any of the renderings...
My approach to this problem would be to simplify the drawing down to just lines and points, and get that to draw at the desired frame rate. (A line for your cylinder and a colored point on the end for the direction.)
After that draws fast enough, try making the drawing more complex, like a rectangular prism instead of a line, and a pyramid instead of a colored point.
Rounded objects typically require a lot more surfaces and calculations.
I am not an expert on the subject, but I would google other OpenGL tutorials that deal with optimization.
Hope that helps.
EDIT: Removed references to NeHe tutorials because of comments.
Related
For my game, suppose I have a class called GameTexture, where the default constructor looks like this:
GameTexture::GameTexture() {
this->shader = ShaderManager::get_instance()->get_shader("2d_texture", "2d_texture", "", 0);
}
get_shader() looks like this:
Shader* ShaderManager::get_shader(std::string vertex, std::string fragment, std::string geometry, unsigned int features) {
if (!shader_map.contains(vertex)
|| !shader_map[vertex].contains(fragment)
|| !shader_map[vertex][fragment].contains(geometry)
|| !shader_map[vertex][fragment][geometry].contains(features)) {
shader_map[vertex][fragment][geometry][features].init(vertex, fragment, geometry, features);
}
return &shader_map[vertex][fragment][geometry][features];
}
and initializing a shader starts like this:
void Shader::init(std::string vertex_dir, std::string fragment_dir, std::string geometry_dir, unsigned int features) {
ShaderManager* shader_manager = ShaderManager::get_instance();
id = glCreateProgram();
Note that it's not safe to set the shader to nullptr by default, because then if we ever attempt to render an unloaded GameTexture, the program will immediately crash upon trying to dereference the nullptr. So instead, we set it to a default shader that won't cause any damage even if everything else about the texture is the default. On its own this is fine, but it becomes a problem if we ever load a GameTexture before OpenGL has been initialized. Suppose we add another singleton called RenderManager. RenderManager is responsible for creating a window, loading OpenGL, etc. Suppose it looks like this:
class RenderManager {
public:
RenderManager(RenderManager& other) = delete;
void operator=(const RenderManager& other) = delete;
SDL_Window* window;
SDL_Renderer* sdl_renderer;
SDL_GLContext sdl_context;
int s_window_width;
int s_window_height;
GameTexture example_texture;
static RenderManager* get_instance();
void destroy_instance();
private:
RenderManager();
static RenderManager* instance;
};
RenderManager::RenderManager() {
float width = 1920.0;
float height = 1080.0;
window = SDL_CreateWindow("Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_GetWindowSize(window, &s_window_width, &s_window_height);
sdl_renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED);
sdl_context = SDL_GL_CreateContext(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cout << "Failed to initialize GLEW!" << std::endl;
}
SDL_GL_MakeCurrent(window, sdl_context);
SDL_GL_SetSwapInterval(1);
example_texture.init("example/path/here.png");
}
Suppose we start to create an instance of the RenderManager. Before calling the constructor, it goes through all of its members and finds example_texture. It calls the constructor for example_texture, which tells it to get a shader. ShaderManager hasn't already loaded that shader, so it starts to do so. However, this causes the program to crash because it's calling glCreateProgram() despite OpenGL not yet having been loaded.
Which leads me to my question. I know that I'm going to manually initialize this specific instance of a GameTexture, and in fact in this case I'm required to seeing as how the program trying to create the GameTexture on its own doesn't work, so is there any possible way to force the constructor not to run for this specific instance of a GameTexture without deleting it outright? That way it could be stored in the RenderManager as a member variable, but it wouldn't try to call any gl functions before gl was loaded.
Note that I'm aware that there are other solutions to this which I'm willing to do. If I were to heap-allocate this GameTexture, its constructor wouldn't run until I actually allocated it. That's the approach I'm currently taking, but I'm not happy with the idea of heap-allocating just to use it like a stack-allocated variable in all contexts when no other GameTextures are on the heap to begin with.
The whole point of having constructors is that you have to run one. If you don't want to run one constructor, you have to run a different constructor. If you don't have a different constructor, you have to add one. Or, move the code you don't want to run in the constructor, so it isn't in the constructor, but somewhere else.
You seem to have painted yourself into a corner by insisting that you have to have classes that act a certain way. You want every shader object to actually be a shader (not null); you want to get a shader in every texture object; you want to create a texture object before OpenGL has been initialized; and you can't get a shader until after OpenGL has been initialized. It is impossible to satisfy all these requirements. You have to change one.
One possibility is that you change the requirement that all textures have to have a shader object. I would consider creating the texture object in a null state and then loading the actual texture into it later (as you seem to be already doing!) and loading the shader at the same time. I've done this before. It is not too difficult to make a linked list of all the texture objects that exist, then when OpenGL is loaded, you go through them all and actually load the textures.
Another suggestion is that you don't create the texture object until after OpenGL has been initialized. Initialize OpenGL, then create all the textures. If that means your window and your game rendering have to be in two separate classes, so be it. If you make a Window class and put a Window window; inside class RenderManager - before GameTexture example_texture; - the constructor for Window will run before the constructor for GameTexture. Then you'll have OpenGL initialized when you go to create the texture and shader.
Extras:
In fact it's kinda weird that you don't know when your window will be created. Normally you want to know which order your code runs in, surely? Create the window, then initialize OpenGL, then load the level file, then load all the textures for the level, then send the message saying "a new player has joined the game." - trying to make all this happen in the right order without actually saying the order is sometimes a recipe for disaster. You might have caught "singleton fever" and be trying to do some fancy class shenanigans instead of just. telling. the. computer. what. you. want. it. to. do. It's okay, everyone goes through that phase.
Another thing I noticed is that textures aren't usually associated with shaders. Generally, materials are associated with shaders - a material being a shader and all the textures it needs. Some shaders use zero textures (like a distortion effect); some use multiple (like a diffuse colour texture and also a normal map).
I developed a simple Point Cloud Data viewer (just for learning) and I am using Qt Library. My first implementation used QOpenGLWindow but now I want to use a QOpenGLWidget to uses it such as dynamic library.
Regarding QOpenGLWidget, it just works in the first "painting" (call to PaintGL when I create the widget) and nothing happens on successive paintGL() calls. This problem does not appear in QOpenGLWindow, it works perfectly.
My PaintGL() paint using the next method of my class:
void AEOpenGLViewer::renderGL() {
// Clear
glClear(GL_COLOR_BUFFER_BIT);
shader_program->bind();
shader_program->setUniformValue(u_worldToCamera, camera.toMatrix());
shader_program->setUniformValue(u_cameraToView, projection);
{
for (size_t globjects_index = 0; globjects_index < objects.size(); ++globjects_index) {
objects.at(globjects_index).vao->bind();
shader_program->setUniformValue(u_modelToWorld, objects.at(globjects_index).transform.toMatrix());
glDrawArrays(objects.at(globjects_index).primitive_type, 0, objects.at(globjects_index).vertices.size());
objects.at(globjects_index).vao->release();
}
}
shader_program->release();
}
where "objects" is a std::vector of a local struct that define an OpenGL's object in my applicacion:
typedef struct {
QOpenGLBuffer *vbo;
QOpenGLVertexArrayObject *vao;
GLenum primitive_type;
std::vector<Vertex> vertices;
Transform3D transform;
} GLObject;
The slot "update()" is called using input events (KeyPressEvent, MouseMoveEvent..) just in order to reduce the GPU load.
In case someone is interested, the vbo is allocated as follow:
void AEOpenGLViewer::prepareObjectInGPU(GLObject globject) {
shader_program->bind();
{
// Create Buffer (Do not release until VAO is created) (vbo)
globject.vbo->create();
globject.vbo->bind();
globject.vbo->setUsagePattern(QOpenGLBuffer::StaticDraw);
globject.vbo->allocate(globject.vertices.data(), globject.vertices.size() * sizeof(Vertex));
// Create Vertex Array Object (vao)
globject.vao->create();
globject.vao->bind();
shader_program->enableAttributeArray(0);
shader_program->enableAttributeArray(1);
shader_program->setAttributeBuffer(0, GL_FLOAT, Vertex::positionOffset(), Vertex::PositionTupleSize, Vertex::stride());
shader_program->setAttributeBuffer(1, GL_FLOAT, Vertex::colorOffset(), Vertex::ColorTupleSize, Vertex::stride());
// Release (unbind) all
globject.vbo->release();
globject.vao->release();
}
shader_program->release();
}
The problem is solved, It happened because I have to make the corresponding context current during the allocation of the object in the GPU (my prepareObjectInGPU() method). So, the problem is solved as follow:
void AEOpenGLViewer::prepareObjectInGPU(GLObject globject) {
makeCurrent();
shader_program->bind();
{
...
}
shader_program->release();
doneCurrent();
}
In the QOpenGLWindow, it was not necessary but I recommended to do it as good practices. Remember, during the PaintGL() It is not necessary to call the makeCurrent() because it is called automatically before invoking paintGL().
However, if someone want to answer me then you are welcome.
Thanks!
I'm writing an object oriented wrapper for SDL2. I have decided to make 2 classes: a Sprite class, and a Rectangle Class. I used a bit of polymorphism so I don't have to overload the draw function for every drawable object. I have a base class Drawable which has a pure virutal function draw.
Now Sprite and Rect inherit Drawable and define the draw function to suit the style of class. Now, when I have to draw many things to the screen, I'm taking a pointer to Drawable, then calling the draw method. This is happening 1000+ times a second.
If I look at my CPU usage, it's about 10%. I know 1000+ Sprites being drawn every 60 times a second is going to hinder my CPU usage, but I didn't think it would this much.
Now, my question: Is there any way to optimize this? Maybe take out the pure virtual function and just overload the functions?
My Code (I tried to shorten it as much as possible):
Sprite::Draw Declaration
void Draw() override;
Sprite::Draw Function
void Sprite::Draw() {
// rect is SDL_Rect
rect.x = rect.x - window->getCamera().getCoords().x;
rect.y = rect.y - window->getCamera().getCoords().y;
SDL_RenderCopyEx(window->renderer, texture, NULL, &rect, 0, NULL, flip);
}
The Function that calls Sprite::Draw
void Window::Draw(Drawable *d) {
d->Draw();
}
Drawing Loop
// 1024 grass Sprites
for (int i = 0; i < 1024; i++) {
mainWindow.Draw(&grass[i]); // Calls Window::Draw
}
As I said earlier, it is eating up about 10% of my CPU usage. I have an AMD 6300, and a NVIDIA GTX 750Ti. I am using Microsoft Visual Studio Express 2013.
The executable name is OBA.exe
Can the textures for these grass sprites be condensed into 1 texturemap and then you draw a portion of it (the third param, srcrect -- https://wiki.libsdl.org/SDL_RenderCopyEx)?
I'm guessing you don't have 1024 unique grass textures, but a handful of repeated ones. Combine them all into one image and load that as a grass texture.
Your sprite class then needs to just define a SDL_Rect for which part of the texture it uses to draw.
Sample texture:
Say your sprite uses texture 0, it's srcrect would be 0,0,32,32. Drawing it just adds one parameter to your RenderCopy call.
SDL_RenderCopyEx(window->renderer, texture, &srcrect, &rect, 0, NULL, flip);
This should improve performance for drawing a lot of sprites. Additionally, you could only draw sprites if they are in the camera view.
I fixed it, what I did was just draw the Sprites that were currently in the Camera's view. The reason SDL_LogCritical was being called so much is being every SDL_RenderCopyEx call, SDL_LogCritical is called, along with other SDL functions. But by drawing just what the user can see, I got the CPU usage down to about 0.1%
I have been through all the custom draw questions related to cocos2d-x on stack overflow and other places, I would just like to know if it's possible to override the draw function in CCSprite, not in CCLayer. I want to draw a rounded rectangle. I am used to controlling what is being drawn on screen using spriteBatches in libgdx and XNA (R.I.P :( ). I am a bit lost as to how i can do custom draw for my sprite objects. Below is what I have and it does not work.
// object.h
private:
std::string _colourLabel;
int width;
int height;
cocos2d::Vec2 position;
public:
PLOPPP(std::string colour, cocos2d::Vec2 pos, int width, int height);
virtual void draw(cocos2d::Renderer *renderer, const cocos2d::kmMat4 &transform, bool transformUpdated);
void onDraw(const Mat4 &transform, uint32_t flags);
//object.cpp
void PLOPPP::draw(cocos2d::Renderer* renderer, const cocos2d::kmMat4& transform, bool transformUpdated)
{
cocos2d::ccDrawColor4F(1.0f, 0.0f, 0.0f, 1.0f);
cocos2d::ccDrawLine(ccp(0, 0), ccp(100, 100));
}
void PLOPPP::onDraw(const Mat4 &transform, uint32_t flags)
{
cocos2d::ccDrawColor4F(1.0f, 0.0f, 0.0f, 1.0f);
cocos2d::ccDrawLine(ccp(0, 0), ccp(100, 100));
}
I have also put break points in both the methods and it's never called. I also tried to use the sprite->visit() method to direct the render component into the onDraw method as recommended on other questions. Cocos's has a horrible documentation so I use their test projects and read the header files. I see that there is a draw method to override but it's not hitting. I am not very experienced in C++ but I have a good grip on Programming concepts and writing games in general. So you can use any terms you would use to explain to other programmers.
The reason why I want to use CCsprite is to get the benefits of the actions. I also tried to use the CCNode class as a base but it still does not hit. I don't want to make every object a layer because that would go completely against the concept of having objects in a game drawn on a layer. If anyone can suggest any way I can draw custom shapes as sprites, that is also affected by the actions applied to it. It would be greatly appreciated.
If you think I could benefit from other posts please point to it. This should not be a difficult process but it seems to be taking up a lot of my time. If I could just draw a line I'll be able to fly through the rest of the challenges. I just want to draw a custom something.
i need some advice. i have 2 classes for a game that i am making, and those classes are:
Graphics
Sprite
the sprite class consists of an image buffer for the image, an (x, y) offset, and a width and a height. the graphics class has a buffer for the screen. the screen buffer can have things blitted to it like the image buffer for the sprite.
are there any recommended ways of blitting the sprite's image buffer to the graphics screen buffer? i had 2 ideas:
have a method like this (in the sprite class):
void Sprite::blit(SDL_Surface* screen)
{
// code goes here
}
or this (in the graphics class):
void Graphics::blit(Sprite sprite)
{
// code
}
or even this (also in the graphics class):
void Graphics::blit(SDL_Surface* aSpritesImageBuffer)
{
// code
}
there are problems with all of these tho. in both classes, i use encapsulation to hide both the sprite's image buffer and the graphics component's screen buffer. they are returned as a constant so no one can manipulate them without using the functions provided in the class. this is how i did it:
class Graphics
{
public:
const getScreenBuffer() const {return screenBuffer;}
private:
screenBuffer;
};
^ same with the sprite's image buffer.
so if i tried (in my main class)
void handleRendering()
{
graphics.blit(sprite.getImageBuffer());
}
that would not be very good?
or even:
void handleRendering()
{
graphics.blit(sprite);
}
and i don't think this is good:
void handleRendering()
{
sprite.blit(graphics.getScreenBuffer());
}
are there any better methods of doing this without getting errors like const to non-const? << i get an error like that.
I don't know if your sprite class is only a low-level rendering element (so, basically only a wrapper around SDL_Surface*), or if it's already the actual representation of a creature in your game. In the latter case, as an alternative to your different solutions, you could only keep an id of the bitmap in the sprite class, among other properties like coordinates, size, speed... And the actual code dependent of the rendering technology in a separate set of classes, like "Graphics", "BitmapCollection"...
So on one side, you would have a "clean" sprite class with simple properties like position, size, speed... and on the other side, the "dirty stuff", with low level SDL_nnn objects and calls. And one day, that id would not represent a bitmap, but for example a 3D model.
That would give something like that:
void handleRendering()
{
graphics.blit( bitmapCollection.Get( sprite.getImageId());
}
I don't know if the image of a sprite really has to be private or read only. Several sprites could share the same image, other classes like "SpecialEffects" could modify the sprite bitmaps, swap them, make semi-transparent following ghosts on screen and so on.
A common way to do this would be to have a container in your Graphics object that holds all of the sprites in the scene. Your main loop would call Graphics::blit(), and the Graphics object would iterate through the container of sprites and call the Sprite::blit(SDL_Surface* screen) function on each one passing in its screen buffer.