Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically add Opengl shapes

I am following this tutorial to add Opengl to my Android app. https://www3.ntu.edu.sg/home/ehchua/programming/android/Android_3D.html. In all the examples the shapes are created in MyGLRenderer constructor but I want to know how I can add Opengl shapes dynamically after the Renderer has been created. How can this be done?

like image 985
amanda45 Avatar asked Apr 30 '17 20:04

amanda45


2 Answers

You create an interface or class called Shape. This will contain the data needed to render a 3D shape (vertices, indices, color data, etc). Alternatively the VAO/VBO/texture IDs/other IDs for rendering.

The advantage here of using a class is that you can initialize the methods and keep everything in a single class while maintaining the ability to extend it and create more classes (Cube, Pyramid, Model, etc) to customize your objects. Or just use different instances loaded with different data. There's lots of ways to do the same thing here.

You can add more data after renderer initialization though, but by storing your data, you can reuse it later. Assuming the raw model data is stored in a way that can be reused (for your purpose, to be clear. All data can be reused, but it's pointless to reuse if you can't apply it to your use case), you can apply matrices to get different positions and "instances" of the same object. The point being, you can at any point create new shapes; OpenGL doesn't care if that's when the renderer is initialized or a while after the fact, as long as all the data is in place when you're trying to use it.

After you create the class(es) and relevant instances of them, you create a new list or map:

public List<Shape> shapes = new ArrayList<>();
//add whatever shapes you want. Create them at runtime (generate) 
// or keep them static. It is up to you 

In this class you create you can also implement a rendering method. In there you draw the objects. An advantage with using a class is that you can add the drawing into this class. If you don't define a specific draw method in the class, you have to manually draw every object in the main rendering method.


Personally, I separate the raw model data (meaning vertices, UV coordinates, etc.) in a single class, that's sourced into a tree of abstraction. For textured models, I currently have a Renderable Entity (where Renderable is an interface containing a draw(Shader)-function - basically one level of abstraction up from Shape). The Entity contains a TexturedModel, which contains a Texture and a Model. The Model contains the raw data, and the Texture contains the relevant texture (because it has to be applied before it's rendered).

There might be more efficient design options than that, but there's lots of ways to abstract object rendering. Like I mentioned, OpenGL doesn't care when you initialize your data, as long as you don't expect it to render data you haven't given it yet. Abstracting your models, shapes, or whatever you wanna render into classes means you have a single, managable, renderable unit. You can add more on the fly as well -- this has also been proven by every single game with changing scenes or characters/entities in the scene.

To connect this back to the link you've provided, you already have two classes. If you add a super class and add a single list, you can render any number of them. By using matrices (C++/general OpenGL, Android), you can draw these in different positions, if that's what you meant by adding more.

Strictly speaking, with the code in the link, you don't even need to worry about reusability. You need matrices to get several of a single shape in different positions. You can also use uniform variables if you want different colors, but that's a different can of worms you didn't ask about (AKA this is an exercise for the reader; uniforms are a critical part of shaders, and you'll have to learn them at some point anyway).


It's somewhat unclear what you mean by "dynamically" in this case. if you just mean you want more objects with manually generated data, and just randomly add any, a Shape class/interface is the way to go.

If you want dynamic position, you want matrices in the shader.

If you want a pre-made abstraction tree, honestly, there isn't one. You'll have to make one based on what you need for your project. In a case where you only have a few simple geometric shapes, a Shape class makes sense, potentially in combination with the advice from the previous line. When it comes to rendering objects in OpenGL, to put it mildly, there's many ways to Rome, depending on what you need and what you intend to render.

If this answer doesn't directly apply to your situation (either you OP, or you, random reader who happened to stumble over this), I cannot recommend experimenting highly enough. What works is substantially different when you leave the world of tutorials and/or books and/or courses, and enter the world of your own projects. The key takeaways from this answer though though (TL;DR):

  • Abstract to a class or interface that describes the smallest unit of whatever you want to render; whether that's a Renderable, Shape, Model3D or something completely different is purely down to what you're making
  • Inheritance and instance reuse is your friend in cases like these
  • Additional models can be created after your renderer has started if you need it; OpenGL doesn't care when the data is sourced as long as you source it before you try to use it.
  • Dynamic changes to model data (such as position or color) can easily be done with shaders and uniform values and matrices. Don't forget: if you use VBOs, you can reuse the same model, and have different positions or other attributes and alter how your model is rendered through, among other things, uniform variables.

Further reading/watching

  • ThinMatrix' series (LWJGL, but explains a lot of theory)
  • opengl-tutorial.org (C++, a bit of the API matches, but OpenGL and OpenGL ES are different - largely recommend the theory bits over the code bits)
  • Android developer documentation (covers implementation on Android, as well as theory)
  • LWJGL GitBook (LWJGL again, but also contains a decent chunk of theory that generalizes to OpenGL ES)
  • docs.gl - API documentation for OpenGL ES 2 and 3, as well as OpenGL 2-4
like image 75
Zoe stands with Ukraine Avatar answered Nov 09 '22 18:11

Zoe stands with Ukraine


Derive Triangle, Quad, Circle, etc.. From a 'Shape' interface that defines the draw() method. http://tutorials.jenkov.com/java/interfaces.html

Then create a List and shove the shapes into and out of it as needed. http://www.codejava.net/java-core/collections/java-list-collection-tutorial-and-examples

In your onDrawFrame(GL10 gl) method, loop over the shape list.

for( Shape s : shapeList ) s.draw(gl);

Also, probably should add the Shape position to the Shape for the glTranslate Calls

like image 41
James Poag Avatar answered Nov 09 '22 17:11

James Poag