Related
I want to draw multiple polygons in one buffer, here is my conception of how I think it should work, but it does not.
This is what I have:
GLuint VertexArrayID;
GLuint vao;
GLuint program;
typedef struct object{
GLuint vao;
GLuint numVertices;
} object;
object objects[MAX_VERTEX_COUNT];
Here I create VBO:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, VertexArrayID);
glBufferData(GL_ARRAY_BUFFER, 2 * vertex_count * sizeof(float), data, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(data), data);
glUseProgram(program);
GLuint vPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glVertexPointer(2, GL_FLOAT, 0, NULL);
glEnableClientState(GL_VERTEX_ARRAY);
//glDrawArrays(GL_TRIANGLE_FAN, 0, vertex_count);
And I made loop like that, but I think, when I put vao in objects[i].vao, every time when I came through that loop, it does the same without this loop, but I am not sure.
for (int i = 0; i < 5; i++)
{
objects[i].vao = vao;
glBindVertexArray(objects[i].vao);
objects[i].numVertices = vertex_count;
glDrawArrays(GL_TRIANGLE_FAN, 0, objects[i].numVertices);
}
glDisableClientState(GL_VERTEX_ARRAY);
Maybe you have some ideas?
Here I have an Image2D class object that is used to render basic 2D Images that works with my GUI hierarchy. My Shader Engine is quite large for I have a system to manage Shaders using template types. It also uses a Batch Process and all of my Assets that are loaded into memory are saved into a Storage class that handles the clean up of their memory footprint. It is too large of a project to show everything necessary to be able to compile a working program, but here is an example of a generated renderable object from within my ShaderEngine.
Image2d.h
class Image2d : public VisualMko {
private:
TextureInfo m_textureInfo;
// --- Only For Version 1.0 ---
// VBO //
unsigned m_vboTexture; //
unsigned m_vboPosition; //
unsigned m_vboIndices; //
// //
// VAO //
unsigned m_vao; //
// ------------------------- //
// version 2.0 variables below
glm::vec2 m_offsetPosition;
public:
Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId );
Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId = std::string() );
virtual ~Image2d();
void setOffsetPosition( const glm::vec2& offset );
virtual void clearTextureInfos() override;
void render() override;
TextureInfo getTextureInfo() const;
void setTextureInfo( const TextureInfo& textureInfo );
private:
Image2d( const Image2d& c ); // Not Implemented
Image2d& operator=( const Image2d& c );
}; // Image2d
} // namespace vmk
#endif // IMAGE2D_H
Image2d.cpp
#include "stdafx.h"
#include "Image2d.h"
#include "AssetStorage.h"
#include "ShaderManager.h" // Only Needed For Version 1.0
#include "TextureFileReader.h"
namespace vmk {
// ----------------------------------------------------------------------------
// Image2d()
// Creates A Rectangular 2D Imgae Of The Size Specified And Stores It In A
// Vertex Array Object For Rendering. The Surface Verts Are Defined Like:
// width
// <------->
// v0 --- v2 ^
// : / : | height
// : / : |
// v1 --- v3 v
//
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
if ( fWidth <= 0 || fHeight <= 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
throw ExceptionHandler( strStream );
}
// Save TextureID
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );
// Define Texture Coordinates
std::vector<float> vTextureCoordinates;
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0.0f );
// Define Vertex Positions (x,y,z)
std::vector<float> vVertexPositions;
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
// Define 2 Triangle Faces
std::vector<unsigned char> vIndices;
vIndices.push_back( 0 );
vIndices.push_back( 1 );
vIndices.push_back( 2 );
vIndices.push_back( 3 );
// Create Vertex Array Object
glGenVertexArrays( 1, &m_vao );
glBindVertexArray( m_vao ); // Start Array
m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );
// Create Position Buffer And Store On Video Card
glGenBuffers( 1, &m_vboPosition );
glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_POSITION );
// Create Texture Coordinate Buffer
glGenBuffers( 1, &m_vboTexture );
glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );
// Create Index Buffer
glGenBuffers( 1, &m_vboIndices );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );
glBindVertexArray( 0 ); // Stop Array
// Disable Attribute Pointers
m_pShaderManager->disableAttribute( A_POSITION );
m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );
// THIS MUST BE AFTER: Vertex Array Buffer Is Unbound!
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer
} // Image2d - v1.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
m_version = 2;
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
m_config.uTextureId = m_textureInfo.uTextureId;
if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
throw ExceptionHandler( strStream );
}
// Verify Image Fits Inside Texture
if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
<< " which is too small for an image that is " << size
<< " pixels in size, with an origin point set at " << origin ;
throw ExceptionHandler( strStream );
}
glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
1.0f / static_cast<float>( m_textureInfo.size.y ) );
glm::vec2 texCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
glm::vec2 texCoordTopRight = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
textureCoordScaleFactor.y * (m_textureInfo.size.y - origin.y ) );
// Set Colors And Texture Coordinates (Position Will Be Updated In Render Function
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordBottomLeft.x, texCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordBottomLeft.x, texCoordBottomLeft.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordTopRight.x, texCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordTopRight.x, texCoordBottomLeft.y ) ) );
} // Image2d() - v2.0
// ----------------------------------------------------------------------------
// ~Image2d()
Image2d::~Image2d() {
if ( 1 == m_version ) {
// Destroy Objects
if ( m_vboTexture != 0 ) {
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboTexture );
m_vboTexture = 0;
}
if ( m_vboPosition != 0 ) {
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboPosition );
m_vboPosition = 0;
}
if ( m_vboIndices != 0 ) {
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboIndices );
m_vboIndices = 0;
}
if ( m_vao != 0 ) {
glBindVertexArray( 0 );
glDeleteVertexArrays( 1, &m_vao );
m_vao = 0;
}
}
} // Image2d
// ----------------------------------------------------------------------------
// setOffsetPosition()
void Image2d::setOffsetPosition( const glm::vec2& offset ) {
if ( offset.x != m_offsetPosition.x || offset.y != m_offsetPosition.y ) {
m_offsetPosition = offset;
m_transformMatrix.updateTranslation = true;
}
} // setOffsetPosition
// ----------------------------------------------------------------------------
// clearTextureInfos()
void Image2d::clearTextureInfos() {
if ( m_pAssetStorage->removeTextureInfo( m_textureInfo.uTextureId ) ) {
m_textureInfo = TextureInfo();
}
} // clearTextureInfos
// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
if ( 1 == m_version ) {
m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );
glBindVertexArray( m_vao );
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
glBindVertexArray( 0 );
} else {
// Version 2.0
// Update Vertices
if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;
// Order Of Operations Matter Here!
glm::mat4 matrix; // identity
if ( m_transformMatrix.hasTranslation ) {
matrix[3][0] = m_transformMatrix.translation.x;
matrix[3][1] = m_transformMatrix.translation.y;
}
if ( m_transformMatrix.hasRotation ) {
matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleDegrees, glm::vec3( 0.0f, 0.0f, -1.0f ) );
}
if ( m_transformMatrix.hasScale ) {
matrix = matrix * glm::mat4( m_transformMatrix.scale.x, 0.0f, 0.0f, 0.0f,
0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f );
}
// Center Offset
if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
}
// Apply Transformation To All 4 Vertices
m_vVertices[0].position = glm::vec2( matrix * glm::vec4( 0, 0, 0, 1.0f ) );
m_vVertices[1].position = glm::vec2( matrix * glm::vec4( 0, m_size.y, 0, 1.0f ) );
m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x, 0, 0, 1.0f ) );
m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
}
renderBatch();
}
} // render
// ----------------------------------------------------------------------------
// getTextureInfos()
TextureInfo Image2d::getTextureInfo() const {
return m_textureInfo;
} // getTextureInfo
// ----------------------------------------------------------------------------
// setTextureInfo()
void Image2d::setTextureInfo( const TextureInfo& textureInfo ) {
m_textureInfo = textureInfo;
} // setTextureInfo
} // namespace vmk
Now this class has two constructors which will get called depending on which version of the Image2d is being used. If I remember correctly version 1 does not use the BatchManager or Batch Process while version 2 does. If you look at the 1st Constructor. glBindVertexArray( 0 ); and glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); methods are called to stop the arrays and buffers. In render call in the first section of the if statement again we call glBindVertexArray( 0 ); to stop the array.
If you look at the destructor version 2 does not get cleaned up due to the fact that it is being used through the BatchManager and everything that is used through the BatchManager is automatically cleaned up and handled by my AssetStorage class. However, since version 1 of this class does not use the BatchManager it has to clean itself up and you can see the calls to glBindBuffer( BUFFER_ENUMERATED_TYPE, 0 ); followed by a glDeleteBuffers(...); call then setting the VBOs and VAO to 0.
If you would like to know more about this and how to successfully build a 3D Graphics ShaderEngine using modern OpenGL visit http://www.marekknows.com for this is where I have learned how to successfully use OpenGL. These works are not of my own design, but everything in this Engine was manually typed and debugged by following Marek's video tutorials.
I'm drawing sprites that are all in a buffer using glDrawElements.
To tell sprites what texture to be in the fragment shader I have uniform sampler2D textures[32]; each vertex has an index, which is passed to the fragment shader from the vertex shader:
color = texture(textures[index], fs_in.uv);
when I try draw my sprites with more than 1 texture active it gets the wrong textures in the top right corner
http://puu.sh/lyr5j/d8c2cf6c8f.png
I have no clue why this is happening have tried texture parameters
I cant seem to find anyone who has had a similar problem.
This is my renderer's init function (I am purposly passing the texid as float since I have heard ints don't work well (also tried))
glGenBuffers(1, &m_VDBO);
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VDBO);
glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glEnableVertexAttribArray(SHADER_UV_INDEX);
glEnableVertexAttribArray(SHADER_COLOR_INDEX);
glEnableVertexAttribArray(SHADER_TEXID_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::vertex));
glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::uv));
glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_UNSIGNED_BYTE, GL_TRUE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::color));
glVertexAttribPointer(SHADER_TEXID_INDEX, 1, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *)offsetof(VertexData, VertexData::texID));
glBindBuffer(GL_ARRAY_BUFFER, 0);
const GLushort modelindices[] = { 0, 1, 2, 2, 3, 0 };
GLuint indices[RENDERER_INDICES_SIZE];
for (int i = 0; i < RENDERER_INDICES_SIZE; i += 6)
{
for (int o = 0; o < 6; o++)
{
indices[i + o] = modelindices[o] + (i / 6 * 4);
}
}
glGenBuffers(1, &m_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, RENDERER_INDICES_SIZE * sizeof(GLuint), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
the flush function
glBindVertexArray(m_VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
for (int i = 0; i < m_TextureSlots.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, m_TextureSlots[i]);
}
glDrawElements(GL_TRIANGLES, m_IndexCount, GL_UNSIGNED_INT, 0);
m_TextureSlots.clear();
m_IndexCount = 0;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
It is hard for me to see where your problem is coming from, the only thing I can suggest is taking a look at an Image2d class object constructor that I have. Now, my source depends on outside classes such as a ShaderManager class that relies heavily on template types and a Batch class and a BatchManager class to send over the vertices to the video card. Also this Image2d is an inherited object. However, this may serve as some help to you in tracking down your own problem. There are two different constructors for different versions of the implementation depending on which version of OpenGL and GLSL is being used. If I remember correctly version 2 uses the BatchManager to send the vertices to the video card where version 1 doesn't which can be seen within the render() method.
Image2d v1.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
if ( fWidth <= 0 || fHeight <= 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
throw ExceptionHandler( strStream );
}
// Save TextureId
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );
// Define Texture Co-Ordinates
std::vector<float> vTextureCoordinates;
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0 );
vTextureCoordinates.push_back( 0 );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0 );
// Define Vertex Positions (x,y,z)
std::vector<float> vVertexPositions;
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
// Define 2 Triangle Faces
std::vector<unsigned char> vIndices;
vIndices.push_back( 0 );
vIndices.push_back( 1 );
vIndices.push_back( 2 );
vIndices.push_back( 3 );
// Create Vertex Array Object
glGenVertexArrays( 1, &m_vao );
glBindVertexArray( m_vao ); // Start Array
m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );
// Create Position Buffer And Store On Video Card
glGenBuffers( 1, & m_vboPosition );
glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_POSITION );
// Create Texture Coordinate Buffer
glGenBuffers( 1, &m_vboTexture );
glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );
// Create Index Buffer
glGenBuffers( 1, &m_vboIndices );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );
glBindVertexArray( 0 ); // Stop Array
// Disable Attribute Pointers
m_pShaderManager->disableAttribute( A_POSITION );
m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );
// THIS MUST BE AFTER Vertex Array Buffer Is Unbound!
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer
// We have a Valid Image2d Save Filename
m_strFilename = strTextureFilename;
} // Image2D - v1.0
Image2D - v2.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
m_version = 2;
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
m_config.uTextureId = m_textureInfo.uTextureId;
if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << "size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
throw ExceptionHandler( strStream );
}
// Verify Image Fits Inside Texture
if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
<< " which is too small for an image that is " << size
<< " pixels in size, with an origin point set at " << origin ;
throw ExceptionHandler( strStream );
}
glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
1.0f / static_cast<float>( m_textureInfo.size.y ) );
glm::vec2 textureCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
glm::vec2 textureCoordTopRight = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y ) );
// Set Colors And Texture Coordinates (Position Will Be Updated In Render Function)
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordBottomLeft.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x, textureCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x, textureCoordBottomLeft.y ) ) );
} // Image2d - v2.0
and here is my render() method
// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
if ( 1 == m_version ) {
m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );
glBindVertexArray( m_vao );
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
glBindVertexArray( 0 );
} else {
// Version 2.0
// Update Vertices
if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;
// Order Of Operations Matter Here!
glm::mat4 matrix; // Identity
if ( m_transformMatrix.hasTranslation ) {
matrix[3][0] = m_transformMatrix.translation.x;
matrix[3][1] = m_transformMatrix.translation.y;
}
if ( m_transformMatrix.hasRotation ) {
matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleRadians, glm::vec3( 0.0f, 0.0f, -1.0f ) );
}
if ( m_transformMatrix.hasScale ) {
matrix = matrix * glm::mat4( m_transformMatrix.scale.x, 0.0f, 0.0f, 0.0f,
0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f );
}
// Center Offset
if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
}
// Apply Transformation To All 4 Vertices
m_vVertices[0].position = glm::vec2( matrix * glm::vec4( 0, 0, 0, 1.0f ) );
m_vVertices[1].position = glm::vec2( matrix * glm::vec4( 0, m_size.y, 0, 1.0f ) );
m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x, 0, 0, 1.0f ) );
m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
}
renderBatch();
}
} // render
Make sure that the sizes you are specifying in your glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
is accurate. Also make sure that you are stopping your your VertexArray at the appropriate time as well as disabling your Attribute Pointers. Everything that you bound must be unbound, and for some types Order does matter!
I just started with DirectX learning and decided to write a simple classic game: SpaceBattle. But now I have some performance problems mainly related to Render (I guess not to Update). As a result: I have 150-200 FPS with maximum 80-100 polygons. If I comment Render method, FPS grows up to 2500-3000. So here is my Render method:
void DX11Game::Render()
{
if( d3dContext_ == 0 )
return;
stride = sizeof( VertexPT );
offset = 0;
d3dContext_->IASetInputLayout(inputLayout);
d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3dContext_->VSSetShader(VS, 0, 0);
d3dContext_->PSSetShader(PS, 0, 0);
d3dContext_->PSSetSamplers(0, 1, &samplerState);
d3dContext_->VSSetConstantBuffers(0, 1, &cbMatricesBuffer);
d3dContext_->PSSetConstantBuffers(1, 1, &cbParametersBuffer);
switch (DX11Game::gameState)
{
case GAME_STATE::GAME_STATE_PLAY:
d3dContext_->ClearRenderTargetView(backBufferTarget_, backColor);
DrawAsteroids();
DrawShip();
DrawUserBullets();
DrawEnemies();
DrawGUI();
break;
case GAME_STATE::GAME_STATE_GAMEOVER:
d3dContext_->ClearRenderTargetView(backBufferTarget_, backColor);
DrawAsteroids();
DrawShip();
DrawUserBullets();
DrawGameOver();
break;
case GAME_STATE::GAME_STATE_SCORES:
break;
}
swapChain_->Present(0, 0);
}
And here is one of the methods that draws game objects. Others Draws is similar to this:
void DX11Game::DrawAsteroids()
{
std::vector<std::shared_ptr<Asteroid>>* asteroids = gameLogic->GetAsteroids();
std::vector<std::shared_ptr<Asteroid>>::iterator it = asteroids->begin();
while (it != asteroids->end())
{
float SIZE = *((*it)->GetSize());
float* temp = (*it)->GetTexCoord();
XMFLOAT4 texBounds = XMFLOAT4( temp[0], temp[1], temp[2], temp[3] );
vertices[0].pos = XMFLOAT3( SIZE, SIZE, 1.0f );
vertices[0].tex0 = XMFLOAT2( texBounds.x + texBounds.z, texBounds.y );
vertices[1].pos = XMFLOAT3( SIZE, -SIZE, 1.0f );
vertices[1].tex0 = XMFLOAT2( texBounds.x + texBounds.z, texBounds.y + texBounds.w );
vertices[2].pos = XMFLOAT3( -SIZE, -SIZE, 1.0f );
vertices[2].tex0 =XMFLOAT2( texBounds.x,texBounds.y + texBounds.w );
vertices[3].pos = XMFLOAT3( -SIZE, -SIZE, 1.0f );
vertices[3].tex0 =XMFLOAT2( texBounds.x, texBounds.y + texBounds.w );
vertices[4].pos = XMFLOAT3( -SIZE, SIZE, 1.0f );
vertices[4].tex0 = XMFLOAT2( texBounds.x, texBounds.y );
vertices[5].pos = XMFLOAT3( SIZE, SIZE, 1.0f );
vertices[5].tex0 =XMFLOAT2( texBounds.x +texBounds.z, texBounds.y );
XMMATRIX world = XMMatrixTranslation(
( *it )->GetPosition()[0],
( *it )->GetPosition()[1],
0.0f );
world = XMMatrixTranspose(world);
d3dContext_->PSSetShaderResources(0, 1, &texGameSprites);
d3dContext_->UpdateSubresource(vertexBuffer, 0, 0, vertices, 0, 0);
CB_Matrices matrices;
matrices.World = world;
matrices.Projection = proj;
d3dContext_->UpdateSubresource(cbMatricesBuffer, 0, 0, &matrices, 0, 0);
CB_Parameters params;
params.isTextured = true;
params.color[0] = 1.0f; params.color[1] = 1.0f;
params.color[2] = 0.0f; params.color[3] = 1.0f;
d3dContext_->UpdateSubresource(cbParametersBuffer, 0, 0, ¶ms, 0, 0);
d3dContext_->Draw(6, 0);
it++;
}
}
So what I have to do to optimize my game?
Thanks!
I am having an issue with openGL when drawing my sketched line to the screen in that it seems to be adding an extra point at the origin which is not in the point list:
(0,0) is definitely not in the points that are in the array to be drawn, just cant seem to reason it out. I would guess that maybe my array size is too big or something but I can't see it
Here is my code for populating the array and the draw call
void PointArray::repopulateObjectBuffer()
{
//Rebind Appropriate VAO
glBindVertexArray( vertex_array_object_id );
//Recalculate Array Size
vertexArraySize = points.size()*sizeof(glm::vec2);
//Rebind Appropriate VBO
glBindBuffer( GL_ARRAY_BUFFER, buffer_object_id );
glBufferData( GL_ARRAY_BUFFER, vertexArraySize, NULL, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, vertexArraySize, (const GLvoid*)(&points[0]) );
//Set up Vertex Arrays
glEnableVertexAttribArray( 0 ); //SimpleShader attrib at position 0 = "vPosition"
glVertexAttribPointer( (GLuint)0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
//Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void PointArray::draw() {
glBindVertexArray(vertex_array_object_id);
glLineWidth(4);
glDrawArrays( GL_LINE_STRIP, 0, vertexArraySize );
glBindVertexArray(0);
}
and here is where I am adding points in the mouse callback
void mouseMovement(int x, int y)
{
mouseDX = x - lastX ;
mouseDY = y - lastY ;
lastX = x;
lastY = y;
if(mouse_drag)
{
cam->RotateByMouse(glm::vec2(mouseDX*mouseSens, mouseDY * mouseSens));
}
if(sketching)
{
sketchLine.addPoint(glm::vec2((float)x,(float)y));
sketchLine.repopulateObjectBuffer();
updatePickray(x,y);
}
}
Finally my simple ortho vertex shader
in vec2 vPosition;
void main(){
const float right = 800.0;
const float bottom = 600.0;
const float left = 0.0;
const float top = 0.0;
const float far = 1.0;
const float near = -1.0;
mat4 orthoMat = mat4(
vec4(2.0 / (right - left), 0, 0, 0),
vec4(0, 2.0 / (top - bottom), 0, 0),
vec4(0, 0, -2.0 / (far - near), 0),
vec4(-(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1)
);
gl_Position = orthoMat * vec4(vPosition, 0.0, 1.0);
}
You seem to be using vertexArraySize as the parameter to glDrawArrays, which is not correct. The count of glDrawArrays should be the number of vertices, not the number of bytes of the vertex array.
In your case I guess it would be glDrawArrays( GL_LINE_STRIP, 0, points.size());.
Good afternoon,
I'm trying to learn to use a graphics library that uses OpenGL. I can draw 2D primitives (text and lines) but 3D triangles don't render. I've tried everything I can think of but as an OpenGL newcomer I've probably missed something obvious.
This code is not intended to be efficient. I'm trying to get it to work first.
Here's the setup at startup:
// 800 by 600 windows 32 bit depth
Driver->setDisplay( UDriver::CMode( ScreenWidth, ScreenHeight, 32 ) );
NL3D::CViewport viewport;
viewport.initFullScreen();
Driver->setViewport( viewport );
NLMISC::CMatrix mtx;
mtx.identity();
Driver->setViewMatrix( mtx );
Driver->setModelMatrix( mtx );
// screen size is same as pixel resolution
// CFrustum(float left, float right, float bottom, float top, float znear, float zfar, bool perspective= true)
Driver->setMatrixMode2D( CFrustum( 0.0f, ScreenWidth, 0.0f, ScreenHeight, -2.0f, 10000.0f, false ) );
Here's the code in my rendering loop:
static NL3D::CMaterial mat;
mat.initUnlit();
mat.setColor( CRGBA( 255, 255, 0, 128 ) );
float x = 200.0f;
float y = 200.0f;
float width = 200.0f; // (float)ScreenWidth * 0.125f;
float height = 200.0f; // (float)ScreenHeight * 0.125f;
static NL3D::CVertexBuffer vb;
if ( vb.getName().empty() )
vb.setName("drawBitmap");
vb.setVertexFormat( NL3D::CVertexBuffer::PositionFlag | NL3D::CVertexBuffer::TexCoord0Flag );
vb.setNumVertices( 4 );
{
NL3D::CVertexBufferReadWrite vba;
vb.lock( vba );
vba.setVertexCoord( 0, NLMISC::CVector( x, 0, y ) );
vba.setVertexCoord( 1, NLMISC::CVector( x + width, 0, y ) );
vba.setVertexCoord( 2, NLMISC::CVector( x + width, 0, y + height ) );
vba.setVertexCoord( 3, NLMISC::CVector( x, 0, y + height ) );
vba.setTexCoord( 0, 0, 0.f, 1.f );
vba.setTexCoord( 1, 0, 1.f, 1.f );
vba.setTexCoord( 2, 0, 1.f, 0.f );
vba.setTexCoord( 3, 0, 0.f, 0.f );
}
dynamic_cast<NL3D::CDriverUser*>(Driver)->getDriver()->activeVertexBuffer( vb );
static NL3D::CIndexBuffer pb;
if ( pb.getName().empty() )
pb.setName("drawBitmap");
pb.setFormat( NL_DEFAULT_INDEX_BUFFER_FORMAT );
pb.setNumIndexes( 6 );
{
CIndexBufferReadWrite iba;
pb.lock( iba );
iba.setTri( 0, 0, 1, 2 );
iba.setTri( 3, 2, 3, 0 );
}
dynamic_cast<NL3D::CDriverUser*>(Driver)->getDriver()->activeIndexBuffer( pb );
dynamic_cast<NL3D::CDriverUser*>(Driver)->getDriver()->renderTriangles( mat, 0, 2 );
Any suggestions?
Thanks
It turned out to be multiple OpenGL contexts. It wasn't setting things back before trying to draw.