Im trying to draw a triangle on screen using openGL on cocos2dx. Currently i have subclassed cocos' Node object inside which i do my drawing.
In the latest version of cocos2dx i cannot override the draw() function instead im trying to override draw(Renderer* renderer, const Mat4 &transform, uint32_t flags) and add Custom commands to the renderer, like so.
const GLfloat vertices[9] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
void MyNodeSubclass::draw(Renderer* renderer, const Mat4 &transform, uint32_t flags){
CustomCommand *_customCommand = new CustomCommand();
_customCommand->init(_globalZOrder);
_customCommand->func = CC_CALLBACK_0(MyNodeSubclass::drawTriangle, this);
renderer->addCommand(_customCommand);
}
void MyNodeSubclass::drawTriangle(){
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE,0, vertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
And My Load Shader method
void MyNodeSubclass::loadOurShaders(){
GLProgram* myShader = new GLProgram();
myShader->initWithFilenames("shader.vert", "shader.frag");
myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
myShader->link();
myShader->updateUniforms();
}
I dont see the triangle on screen. But I'm able to draw cocos2dx primitive objects (polygons , points , lines) by just swapping out whats in my drawTriangle function but not my vertices using openGL.
What am i missing here?
Related
I'm trying to make a system that allows you to type in a position and scale and it will create a vector that automatically generates all the vertices. The problem is when I try to draw my object it just won't show up. I have used OpenGL's built-in debugging system but it didn't say anything was wrong. So then I tried to manually debug myself but everything seemed to draw just fine.
Renderer::createQuad() method:
Shape Renderer::createQuad(glm::vec2 position, glm::vec2 scale, Shader shader, Texture texture)
{
float x = position.x;
float y = position.y;
float width = scale.x;
float height = scale.y;
std::vector<float> vertices =
{
x+width, y+height, 1.0f, 1.0f, // TR
x+width, y-height, 1.0f, 0.0f, // BR
x-width, y-height, 0.0f, 0.0f, // BL
x-width, y+height, 0.0f, 1.0f // TL
};
std::vector<uint32_t> indices =
{
0, 1, 3,
1, 2, 3
};
m_lenVertices = vertices.size();
m_lenIndices = indices.size();
// these Create methods should be fine as OpenGL does not give me any error
// also I have another function that requires you to pass in the vertex data and indices that works just fine
// I bind the thing I am creating
createVAO();
createVBO(vertices);
createEBO(indices);
createTexture(texture);
createShader(shader.getVertexShader(), shader.getFragmentShader());
Shape shape;
glm::mat4 model(1.0f);
glUniformMatrix4fv(glGetUniformLocation(m_shader, "model"), 1, GL_FALSE, glm::value_ptr(model));
shape.setShader(m_shader);
shape.setVAO(m_VAO);
shape.setTexture(m_texture);
shape.setPosition(position);
return shape;
}
Renderer::draw() method:
void Renderer::draw(Shape shape)
{
if (!m_usingIndices)
{
// Unbinds any other shapes
glBindVertexArray(0);
glUseProgram(0);
shape.bindShader();
shape.bindVAO();
shape.bindTexture();
glDrawArrays(GL_TRIANGLES, 0, m_lenVertices);
}
else
{
// Unbinds any other shapes
glBindVertexArray(0);
glUseProgram(0);
shape.bindShader();
shape.bindVAO();
shape.bindTexture();
glDrawElements(GL_TRIANGLES, m_lenIndices, GL_UNSIGNED_INT, 0);
}
}
Projection matrix:
glm::mat4 m_projectionMat = glm::ortho(-Window::getWidth(), Window::getWidth(), -Window::getHeight(), Window::getHeight, 0.1f, 100.0f);
Creating then rendering the Quad:
// Creates the VBO, VAO, EBO, etc.
quad = renderer.createQuad(glm::vec2(500.0f, 500.0f), glm::vec2(200.0F, 200.0f), LoadFile::loadShader("Res/Shader/VertShader.glsl", "Res/Shader/FragShader.glsl"), LoadFile::loadTexture("Res/Textures/Lake.jpg"));
// In the main game loop we render the quad
quad.setCamera(camera); // Sets the View and Projection matrix for the quad
renderer.draw(quad);
Output:
Output of the code before
I am against one problem with my C++ code. I am using the Assimp library, and I have one class that has one attribute of type const aiScene*. In the constructor of the class, I assign this value and all works fine, but when I exit the constructor code, the parameter const aiScene* does not have any data assigned
I paste you here the code.
Model.h
class Model
{
public:
Model(std::string objectLoc, std::string vertexLoc, std::string fragmentLoc,
glm::vec3 position, glm::vec3 scale, glm::vec3 rotation,
Camera* camera);
void render();
~Model();
private:
std::string objectLoc, vertexLoc, fragmentLoc;
Shader* shader;
glm::mat4 model;
glm::vec3 position, scale, rotation;
Camera* camera;
std::vector<Mesh*> meshes;
std::vector<Texture*> textures;
std::vector<unsigned int> meshToTex;
std::unordered_map<std::string, GLuint> boneMapping;
std::vector<glm::mat4> bonesTransformations;
const aiScene* scene;
glm::mat4 globalInverseTransform;
GLuint boneCount;
};
Model.cpp
Model::Model(std::string objectLoc, std::string vertexLoc, std::string fragmentLoc, glm::vec3
position, glm::vec3 scale, glm::vec3 rotation, Camera* camera)
: objectLoc(objectLoc), vertexLoc(vertexLoc), fragmentLoc(fragmentLoc),
position(position), scale(scale), rotation(rotation),
camera(camera),
boneCount(0)
{
shader = new Shader(vertexLoc, fragmentLoc,
DirectionalLight(glm::vec3(1.0f, 1.0f, 1.0f), 0.4f, 0.1f, glm::vec3(0.0f, 0.0f, -1.0f)),
SpecularLight(1.0f, 250.0f),
SpotLight(glm::vec3(1.0f, 1.0f, 1.0f), 0.0f, 1.0f, glm::vec3(0.0f, 0.0f, 0.0f), 1.0f, 0.0f, 0.0f,
glm::vec3(0.0f, 0.0f, -1.0f), glm::radians(10.0f)));
shader->addPointLight(PointLight(glm::vec3(1.0f, 0.0f, 0.0f), 0.2f, 0.2f, glm::vec3(0.0f, 0.0f,
-15.0f), 0.3f, 0.2f, 0.1f));
shader->addPointLight(PointLight(glm::vec3(0.0f, 1.0f, 0.0f), 0.2f, 0.2f, glm::vec3(10.0f, 0.0f,
-15.0f), 0.3f, 0.2f, 0.1f));
shader->addPointLight(PointLight(glm::vec3(0.0f, 0.0f, 1.0f), 0.2f, 1.2f, glm::vec3(-10.0f, 0.0f,
-15.0f), 0.8f, 0.2f, 0.1f));
model = glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), scale)
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1, 0, 0))
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0, 1, 0))
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0, 0, 1));
Assimp::Importer importer;
scene = importer.ReadFile(objectLoc,
aiProcess_Triangulate |
aiProcess_FlipUVs |
aiProcess_GenSmoothNormals |
aiProcess_JoinIdenticalVertices);
if (!scene)
{
printf("Cannot load model %s: %s\n", objectLoc.c_str(), importer.GetErrorString());
return;
}
aiNode* rootNode = scene->mRootNode;
globalInverseTransform = aiMatrix4x4ToGlm(rootNode->mTransformation.Inverse());
loadNode(rootNode);
loadTextures();
}
I have tried everything, from copy one by one the attributes to the object scene, to make a clone method in all classes involved, but nothing. Even, I have thought that the problem could be the const identifier in the scene attribute, but if I make the object not constant, it works wrongly the same.
I am not modifying that attribute in any of the methods of the Model class.
I paste you here some photos of the problem.
Good result in the constructor
Bad result out of the constructor
If you could help me it would be great.
The documentation says
The returned data is intended to be read-only, the importer object keeps ownership of the data and will destroy it upon destruction.
[Assimp::Importer::ReadFile]
When the constructor is left Assimp::Importer importer; and the object scene is pointing to are destroyed.
You have to make a copy of it before you leave the constructor or
Use GetOrphanedScene() to take ownership of it.
[Assimp::Importer::ReadFile]
aiScene* Assimp::Importer::GetOrphanedScene ( )
Returns the scene loaded by the last successful call to ReadFile() and releases the scene from the ownership of the Importer instance.
The application is now responsible for deleting the scene. Any further calls to GetScene() or GetOrphanedScene() will return NULL - until a new scene has been loaded via ReadFile().
Returns:
Current scene or NULL if there is currently no scene loaded
Note:
Use this method with maximal caution, and only if you have to. By design, aiScene's are exclusively maintained, allocated and deallocated by Assimp and no one else. The reasoning behind this is the golden rule that deallocations should always be done by the module that did the original allocation because heaps are not necessarily shared. GetOrphanedScene() enforces you to delete the returned scene by yourself, but this will only be fine if and only if you're using the same heap as assimp. On Windows, it's typically fine provided everything is linked against the multithreaded-dll version of the runtime library. It will work as well for static linkage with Assimp.
[Assimp::Importer::GetOrphanedScene]
I just ran my first java program running JOGL. I have worked on c++ using the Glut.h library. I have a question as I am trying to understand the coordinate system on the graphic window displayed using JOGL.
Now, in c++, the window coordinate system begins at the top left corner of the window (that is where the origin is). However, when I run the below JOGL program, the origin is not at the top left corner. The below program will draw 3 lines, all of which start at the origin:
import com.sun.opengl.util.Animator;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
public class Lab2 implements GLEventListener {
public static void main(String[] args) {
Frame frame = new Frame("My First JOGL Project");
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(new Lab2());
frame.add(canvas);
frame.setSize(640, 480);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
// Run this on another thread than the AWT event queue to
// make sure the call to Animator.stop() completes before
// exiting
new Thread(new Runnable() {
public void run() {
animator.stop();
System.exit(0);
}
}).start();
}
});
// Center frame
frame.setLocationRelativeTo(null);
frame.setVisible(true);
animator.start();
}
public void init(GLAutoDrawable drawable) {
// Use debug pipeline
// drawable.setGL(new DebugGL(drawable.getGL()));
GL gl = drawable.getGL();
System.err.println("INIT GL IS: " + gl.getClass().getName());
// Enable VSync
gl.setSwapInterval(1);
// Setup the drawing area and shading mode
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glShadeModel(GL.GL_SMOOTH); // try setting this to GL_FLAT and see what happens.
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL gl = drawable.getGL();
GLU glu = new GLU();
if (height <= 0) { // avoid a divide by zero error!
height = 1;
}
final float h = (float) width / (float) height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
//glu.gluPerspective(45.0f, h, 1.0, 20.0);
glu.gluPerspective(45.0f, h, 2.0, 20.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
// Clear the drawing area
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Reset the current matrix to the "identity"
gl.glLoadIdentity();
// Move the "drawing cursor" around
gl.glTranslatef(-1.5f, 0.0f, -6.0f);
// Drawing Lines
gl.glBegin(GL.GL_LINES);
gl.glColor3f(0.0f, 1.0f, 0.0f); // Set the current drawing color to green
gl.glVertex3f(0.0f, 0.0f, 0.0f); //Set first vertex of first line
gl.glVertex3f(1.0f, 0.0f, 0.0f); //Set second vertex of first line
gl.glColor3f(0.0f, 0.0f, 1.0f); // Set the current drawing color to blue
gl.glVertex3f(0.0f, 0.0f, 0.0f); //Set first vertex of second line
gl.glVertex3f(0.0f, 1.0f, 0.0f); //Set second vertex of second line
gl.glColor3f(1.0f, 0.0f, 0.0f); // Set the current drawing color to red
gl.glVertex3f(0.0f, 0.0f, 0.0f); //Set first vertex of third line
gl.glVertex3f(0.0f, 0.0f, 1.0f); //Set second vertex of third line
gl.glEnd();
// Flush all drawing operations to the graphics card
gl.glFlush();
}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean
deviceChanged) {}
}
Can someone epxlain?
Leaning how to use OpenGL ES under cocos2d-x.
Help me to understand while the below function crashes with EXC_BAD_ACCESS on noise->visit(); which probably means that my OpenGL state is screwed-up by the time the command is executed.
My method:
Sprite* GameLevelLayer::spriteWithColor(Color4F bgColor, float textureWidth, float textureHeight)
{
// 1: Create new RenderTexture
auto rt = RenderTexture::create(textureWidth, textureHeight);
// 2: Call RenderTexture:begin
rt->beginWithClear(bgColor.r, bgColor.g, bgColor.b, bgColor.a);
// 3: Draw into the texture
//// gradient
gradient_command.init(rt->getGlobalZOrder());
gradient_command.func = std::bind(&GameLevelLayer::onDrawGradient, this, textureWidth, textureHeight);
auto renderer = Director::getInstance()->getRenderer();
renderer->addCommand(&gradient_command);
//// noise cloud
BlendFunc blendFunc;
blendFunc.src = GL_DST_COLOR;
blendFunc.dst = GL_ZERO;
auto noise = Sprite::create("Noise.png");
noise->setBlendFunc(blendFunc);
noise->setPosition(Vec2(textureWidth / 2, textureHeight / 2));
// XXX
noise->visit();
// 4: Call RenderTexture:end
rt->end();
// 5: Create a new Sprite from the texture
return Sprite::createWithTexture(rt->getSprite()->getTexture());
}
and the gradient:
void GameLevelLayer::onDrawGradient(float textureWidth, float textureHeight)
{
setGLProgram(ShaderCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_COLOR));
getGLProgram()->use();
getGLProgram()->setUniformsForBuiltins();
float gradientAlpha = 0.8f;
std::vector<Vec2> vertices;
std::vector<Color4F> colors;
vertices.push_back(Vec2(0, 0));
colors.push_back(Color4F(0.0f, 0.0f, 0.0f, 0.0f ));
vertices.push_back(Vec2(textureWidth, 0));
colors.push_back(Color4F(0.0f, 0.0f, 0.0f, 0.0f ));
vertices.push_back(Vec2(0, textureHeight));
colors.push_back(Color4F(0.0f, 0.0f, 0.0f, gradientAlpha ));
vertices.push_back(Vec2(textureWidth, textureHeight));
colors.push_back(Color4F(0.0f, 0.0f, 0.0f, gradientAlpha ));
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices.data());
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 0, colors.data());
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)vertices.size());
}
Is this because I am using parameters of a wrong size, somewhere? How does one go about debugging something like this?
So I have begun learning OpenGL, reading from the book "OpenGL Super Bible 5 ed.". It's explains things really well, and I have been able to create my first gl program myself! Just something simple, a rotating 3d pyramid.
Now for some reason one of the faces are not rendering. I checked the vertecies (plotted it on paper first) and it seemed to be right. Found out if I changed the shader to draw a line loop, it would render. However it would not render a triangle. Can anyone explain why?
void setupRC()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
shaderManager.InitializeStockShaders();
M3DVector3f vVerts1[] = {-0.5f,0.0f,-0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,-0.5f};
M3DVector3f vVerts2[] = {-0.5f,0.0f,-0.5f,0.0f,0.5f,0.0f,-0.5f,0.0f,0.5f};
M3DVector3f vVerts3[] = {-0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,0.5f};
M3DVector3f vVerts4[] = {0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,0.5f,0.0f,-0.5f};
triangleBatch1.Begin(GL_LINE_LOOP, 3);
triangleBatch1.CopyVertexData3f(vVerts1);
triangleBatch1.End();
triangleBatch2.Begin(GL_TRIANGLES, 3);
triangleBatch2.CopyVertexData3f(vVerts2);
triangleBatch2.End();
triangleBatch3.Begin(GL_TRIANGLES, 3);
triangleBatch3.CopyVertexData3f(vVerts3);
triangleBatch3.End();
triangleBatch4.Begin(GL_TRIANGLES, 3);
triangleBatch4.CopyVertexData3f(vVerts4);
triangleBatch4.End();
glEnable(GL_CULL_FACE);
}
float rot = 1;
void renderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 0.5f};
GLfloat vBlue[] = {0.0f, 1.0f, 0.0f, 0.5f};
GLfloat vGreen[] = {0.0f, 0.0f, 1.0f, 0.5f};
GLfloat vWhite[] = {1.0f, 1.0f, 1.0f, 0.5f};
M3DMatrix44f transformMatrix;
if (rot >= 360)
rot = 0;
else
rot = rot + 1;
m3dRotationMatrix44(transformMatrix,m3dDegToRad(rot),0.0f,1.0f,0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vRed);
triangleBatch1.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vBlue);
triangleBatch2.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vGreen);
triangleBatch3.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, vWhite);
triangleBatch4.Draw();
glutSwapBuffers();
glutPostRedisplay();
Sleep(10);
}
You've most likely defined the vertices in clockwise order for the triangle that isn't showing, and in counterclockwise order (normally the default) for those that are. Clockwise winding essentially creates an inward facing normal and thus OpenGL won't bother to render it when culling is enabled.
The easiest way to check this is to set glCullFace(GL_FRONT)--that should toggle it so you see the missing triangle and no longer see the other three.
The only thing I see that affects polygons here is glEnable(GL_CULL_FACE);.
You shouldn't have that, because if you plot your vertices backwards, the polygon won't render.
Remove it or actually call glDisable(GL_CULL_FACE); to be sure.
In your case, it's not likely that you want to draw a polygon that you can see from one side only.