Overview
We have an image/movie viewer powered via Qt5 and OpenGL that performs well however, we find that the draw surface itself consumes a large swath of resources no matter what is playing, even when we strip down the shaders.
We've added timing (gl query timers) for all of our own, custom, tools and cannot locate the source of the additional performance draw. The draw times are quite low considering our use case (~7ms per frame).
This is for an image rendering app; So 2D textures only. We use 2 triangles to cover the viewport and then dynamically generate the fragment based on the input requirements. This is for the film industry in which we do many many things to an image in terms of color and composite.
Discovery
We've stripped down the fragment to near nothing:
#version 330 core
void main() {
outColor = vec4(0.5, 0.0, 0.0, 1.0);
}
We've also disabled all PBO usage and have no uniform assignment. All timers read 0-1024ns for all of their commands (because all of our own gl commands are disabled)
The draw surface only calls paintGL, the Qt paint event for their OpenGL widget, once every ~42ms (24fps). Even with the simplicity of this, we use 70-80% of a GTX 1050 (resolution 3000x2000)
While this card is by no means a powerhouse, we are expecting to see less usage than that for something as simple as a solid color fragment. If we shrink the OpenGL window down to nothing, to only render the additional UI elements, we see ~5% usage. So our OpenGL surface that's doing next to nothing at a fixed frame rate is still consuming ~60-70% of the GPU for a reason we cannot determine.
Misc Info:
https://forum.qt.io/topic/121179/high-gpu-usage-when-animating/2
Additional Testing
We've attempted an apitrace for the gl commands but nothing jumped out at us. This included turn off the blit from our render frame buffer to the windows' buffer. So realistically, all of these are internal Qt-driven OpenGL commands.
10008 glViewport(x = 0, y = 0, width = 3000, height = 1896)
10009 glClearColor(red = 0, green = 0, blue = 0, alpha = 1)
10010 glClear(mask = GL_COLOR_BUFFER_BIT)
10011 glBindVertexArray(array = 1)
10012 glUseProgram(program = 7)
10013 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 9)
10014 glVertexAttribPointer(index = 0, size = 3, type = GL_FLOAT, normalized = GL_TRUE, stride = 0, pointer = NULL)
10015 glEnableVertexAttribArray(index = 0)
10016 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
10017 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 10)
10018 glVertexAttribPointer(index = 1, size = 2, type = GL_FLOAT, normalized = GL_TRUE, stride = 0, pointer = NULL)
10019 glEnableVertexAttribArray(index = 1)
10020 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
10021 glBindTexture(target = GL_TEXTURE_2D, texture = 1)
10022 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 9)
10023 glVertexAttribPointer(index = 0, size = 3, type = GL_FLOAT, normalized = GL_TRUE, stride = 0, pointer = NULL)
10024 glEnableVertexAttribArray(index = 0)
10025 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
10026 glUniformMatrix4fv(location = 4, count = 1, transpose = GL_FALSE, value = {1, 0, 0, 0, 0, 0.8016878, 0, 0, 0, 0, 1, 0, 0, 0.1476793, 0, 1})
10027 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 10)
10028 glVertexAttribPointer(index = 1, size = 2, type = GL_FLOAT, normalized = GL_TRUE, stride = 0, pointer = NULL)
10029 glEnableVertexAttribArray(index = 1)
10030 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
10031 glUniform1i(location = 1, v0 = 0)
10032 glUniformMatrix3fv(location = 3, count = 1, transpose = GL_FALSE, value = {1, 0, 0, 0, 1, 0, 0, 0, 1})
10033 glDrawArrays(mode = GL_TRIANGLES, first = 0, count = 6)
10034 glBindTexture(target = GL_TEXTURE_2D, texture = 0)
10035 glPixelStorei(pname = GL_UNPACK_ROW_LENGTH, param = 3000)
10036 glBindTexture(target = GL_TEXTURE_2D, texture = 2)
10037 glTexSubImage2D(target = GL_TEXTURE_2D, level = 0, xoffset = 0, yoffset = 48, width = 3000, height = 1520, format = GL_RGBA, type = GL_UNSIGNED_BYTE, pixels = blob(18240000))
10038 glPixelStorei(pname = GL_UNPACK_ROW_LENGTH, param = 0)
10039 glEnable(cap = GL_BLEND)
10040 glBlendFuncSeparate(sfactorRGB = GL_ONE, dfactorRGB = GL_ONE_MINUS_SRC_ALPHA, sfactorAlpha = GL_ONE, dfactorAlpha = GL_ONE)
10041 glBindTexture(target = GL_TEXTURE_2D, texture = 2)
10042 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 9)
10043 glVertexAttribPointer(index = 0, size = 3, type = GL_FLOAT, normalized = GL_TRUE, stride = 0, pointer = NULL)
10044 glEnableVertexAttribArray(index = 0)
10045 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
10046 glUniformMatrix4fv(location = 4, count = 1, transpose = GL_FALSE, value = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1})
10047 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 10)
10048 glVertexAttribPointer(index = 1, size = 2, type = GL_FLOAT, normalized = GL_TRUE, stride = 0, pointer = NULL)
10049 glEnableVertexAttribArray(index = 1)
10050 glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
10051 glUniform1i(location = 1, v0 = 1)
10052 glUniformMatrix3fv(location = 3, count = 1, transpose = GL_FALSE, value = {1, 0, 0, 0, -1, 0, 0, 1, 1})
10053 glDrawArrays(mode = GL_TRIANGLES, first = 0, count = 6)
10054 glBindTexture(target = GL_TEXTURE_2D, texture = 0)
10055 glDisable(cap = GL_BLEND)
10056 glUseProgram(program = 0)
10057 glBindVertexArray(array = 0)
10058 wglSwapBuffers(hdc = 0xffffffff86011399) = TRUE
Any ideas would be excellent. I'm also happy to provide more information if required.
Related
I am working on a project and I need to use texture arrays to apply textures. I have asked many questions about this, none of which I got an answer I was completely satisfied with (Get access to later versions of GLSL , OpenGL: Access Array Texture in GLSL , and OpenGL: How would I implement texture arrays?) so I'm asking a more broad question to hopefully get a response. Anyways, How would I texture an object in OpenGL (PyOpenGL more specifically, but it's fine if you put your answer in C++). I already have a way to load the texture arrays, just not a way to apply it. This is the desired result:
Image from opengl-tutorial
and this is what I currently have for loading array textures:
def load_texture_array(path,width,height):
teximg = pygame.image.load(path)
texels = teximg.get_buffer().raw
texture = GLuint(0)
layerCount = 6
mipLevelCount = 1
glGenTextures(1, texture)
glBindTexture(GL_TEXTURE_2D_ARRAY, texture)
glTexStorage3D(GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, width, height, layerCount)
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, layerCount, GL_RGBA, GL_UNSIGNED_BYTE, texels)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
TLDR: How would I apply textures to objects in OpenGL using texture arrays?
I will happily provide any other information if necessary.
If you want to use a 2D Array Texture for a cube, each of the 6 textures for the 6 side must be the same size.
You can lookup the texture by 3 dimensional texture coordinates. The 3rd component of the texture coordinate is the index of the 2d texture in the 2d texture array.
Hence the texture coordinates for the 6 sides are
0: [(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]
1: [(0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1)]
2: [(0, 0, 2), (1, 0, 2), (1, 1, 2), (0, 1, 2)]
3: [(0, 0, 3), (1, 0, 3), (1, 1, 3), (0, 1, 3)]
4: [(0, 0, 4), (1, 0, 4), (1, 1, 4), (0, 1, 4)]
5: [(0, 0, 5), (1, 0, 5), (1, 1, 5), (0, 1, 5)]
Get the 3 dimensional texture coordinate attribute in the vertex shader and pass it to the fragment shader:
in a_uv;
out v_uv;
// [...]
void main()
{
v_uv = a_uv;
// [...]
}
Use the 3 dimensional texture coordinate to look up the sampler2DArray in the fragment shader:
out v_uv;
uniform sampler2DArray u_texture;
// [...]
void main()
{
vec4 texture(u_texture, v_uv.xyz);
// [...]
}
Create a GL_TEXTURE_2D_ARRAY and use glTexSubImage3D to load 6 2-dimensional images to the 6 planes of the 2D Array Texture. In the following image_planes is a list with the 6 2-dimensional image planes:
tex_obj = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D_ARRAY, self.tex_obj)
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, sizeX, sizeY, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
for i in range(6):
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, sizeX, sizeY, 1, GL_RGBA, GL_UNSIGNED_BYTE, image_planes[i])
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
See also PyGame and OpenGL 4.
Minimal example:
import os, math, ctypes
import glm
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from OpenGL.arrays import *
import pygame
pygame.init()
image_path = r"images"
image_names = ["banana64.png", "apple64.png", "fish64.png", "rocket64.png", "ice64.png", "boomerang64.png"]
image_planes = [
(GLubyte * 4)(255, 0, 0, 255), (GLubyte * 4)(0, 255, 0, 255), (GLubyte * 4)(0, 0, 255, 255),
(GLubyte * 4)(255, 255, 0, 255), (GLubyte * 4)(0, 255, 255, 255), (GLubyte * 4)(255, 0, 255, 255)]
image_size = (1, 1)
for i, filename in enumerate(image_names):
try:
image = pygame.image.load(os.path.join(image_path, filename))
image_size = image.get_size()
image_planes[i] = pygame.image.tostring(image, 'RGBA')
except:
pass
class MyWindow:
__glsl_vert = """
#version 130
in vec3 a_pos;
in vec3 a_nv;
in vec3 a_uv;
out vec3 v_pos;
out vec3 v_nv;
out vec3 v_uv;
uniform mat4 u_proj;
uniform mat4 u_view;
uniform mat4 u_model;
void main()
{
mat4 model_view = u_view * u_model;
mat3 normal = mat3(model_view);
vec4 view_pos = model_view * vec4(a_pos.xyz, 1.0);
v_pos = view_pos.xyz;
v_nv = normal * a_nv;
v_uv = a_uv;
gl_Position = u_proj * view_pos;
}
"""
__glsl_frag = """
#version 130
out vec4 frag_color;
in vec3 v_pos;
in vec3 v_nv;
in vec3 v_uv;
uniform sampler2DArray u_texture;
void main()
{
vec3 N = normalize(v_nv);
vec3 V = -normalize(v_pos);
float ka = 0.1;
float kd = max(0.0, dot(N, V)) * 0.9;
vec4 color = texture(u_texture, v_uv.xyz);
frag_color = vec4(color.rgb * (ka + kd), color.a);
}
"""
def __init__(self, w, h):
self.__caption = 'OpenGL Window'
self.__vp_size = [w, h]
pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 24)
self.__screen = pygame.display.set_mode(self.__vp_size, pygame.DOUBLEBUF| pygame.OPENGL)
self.__program = compileProgram(
compileShader( self.__glsl_vert, GL_VERTEX_SHADER ),
compileShader( self.__glsl_frag, GL_FRAGMENT_SHADER ),
)
self.___attrib = { a : glGetAttribLocation (self.__program, a) for a in ['a_pos', 'a_nv', 'a_uv'] }
print(self.___attrib)
self.___uniform = { u : glGetUniformLocation (self.__program, u) for u in ['u_model', 'u_view', 'u_proj'] }
print(self.___uniform)
v = [[-1,-1,1], [1,-1,1], [1,1,1], [-1,1,1], [-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1]]
n = [[0,0,1], [1,0,0], [0,0,-1], [-1,0,0], [0,1,0], [0,-1,0]]
e = [[0,1,2,3], [1,5,6,2], [5,4,7,6], [4,0,3,7], [3,2,6,7], [1,0,4,5]]
t = [[0, 0], [1, 0], [1, 1], [0, 1]]
index_array = [si*4+[0, 1, 2, 0, 2, 3][vi] for si in range(6) for vi in range(6)]
attr_array = []
for si in range(len(e)):
for i, vi in enumerate(e[si]):
attr_array += [*v[vi], *n[si], *t[i], si]
self.__no_vert = len(attr_array) // 10
self.__no_indices = len(index_array)
vertex_attributes = (ctypes.c_float * len(attr_array))(*attr_array)
indices = (ctypes.c_uint32 * self.__no_indices)(*index_array)
self.__vao = glGenVertexArrays(1)
self.__vbo, self.__ibo = glGenBuffers(2)
glBindVertexArray(self.__vao)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.__ibo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, self.__vbo)
glBufferData(GL_ARRAY_BUFFER, vertex_attributes, GL_STATIC_DRAW)
float_size = ctypes.sizeof(ctypes.c_float)
glVertexAttribPointer(self.___attrib['a_pos'], 3, GL_FLOAT, False, 9*float_size, None)
glVertexAttribPointer(self.___attrib['a_nv'], 3, GL_FLOAT, False, 9*float_size, ctypes.c_void_p(3*float_size))
glVertexAttribPointer(self.___attrib['a_uv'], 3, GL_FLOAT, False, 9*float_size, ctypes.c_void_p(6*float_size))
glEnableVertexAttribArray(self.___attrib['a_pos'])
glEnableVertexAttribArray(self.___attrib['a_nv'])
glEnableVertexAttribArray(self.___attrib['a_uv'])
glEnable(GL_DEPTH_TEST)
glUseProgram(self.__program)
glActiveTexture(GL_TEXTURE0)
sizeX, sizeY = image_size
self.tex_obj = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D_ARRAY, self.tex_obj)
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, sizeX, sizeY, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
for i in range(6):
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, sizeX, sizeY, 1, GL_RGBA, GL_UNSIGNED_BYTE, image_planes[i])
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
def run(self):
self.__starttime = 0
self.__starttime = self.elapsed_ms()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
self.__mainloop()
pygame.display.flip()
pygame.quit()
def elapsed_ms(self):
return pygame.time.get_ticks() - self.__starttime
def __mainloop(self):
proj, view, model = glm.mat4(1), glm.mat4(1), glm.mat4(1)
aspect = self.__vp_size[0]/self.__vp_size[1]
proj = glm.perspective(glm.radians(90.0), aspect, 0.1, 10.0)
view = glm.lookAt(glm.vec3(0,-3,0), glm.vec3(0, 0, 0), glm.vec3(0,0,1))
angle1 = self.elapsed_ms() * math.pi * 2 / 5000.0
angle2 = self.elapsed_ms() * math.pi * 2 / 7333.0
model = glm.rotate(model, angle1, glm.vec3(1, 0, 0))
model = glm.rotate(model, angle2, glm.vec3(0, 1, 0))
glUniformMatrix4fv(self.___uniform['u_proj'], 1, GL_FALSE, glm.value_ptr(proj) )
glUniformMatrix4fv(self.___uniform['u_view'], 1, GL_FALSE, glm.value_ptr(view) )
glUniformMatrix4fv(self.___uniform['u_model'], 1, GL_FALSE, glm.value_ptr(model) )
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glDrawElements(GL_TRIANGLES, self.__no_indices, GL_UNSIGNED_INT, None)
window = MyWindow(800, 600)
window.run()
I have my Vertex data defined like this:
struct Vertex{
glm::vec4 pos;
glm::vec2 texcoord;
glm::vec2 texcoordex;
float alpha;
float idx;
};
my problem is:
vertex buffer has read all data, but vertex shader only gets the first one pos as input, others are 0.0f
vertex shader input
layout (location = 0) in vec4 pos;
layout (location = 1) in vec2 attr;
layout (location = 2) in vec2 attrex;
layout (location = 3) in float alph;
layout (location = 4) in float id;
some code snippets
VkVertexInputBindingDescription vertex_input_bindings{
.binding = 0,
.stride = sizeof(Vertex),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
};
VkVertexInputAttributeDescription vertex_input_attributes[5]{
{
.binding = 0,
.location = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(Vertex, pos),
},
{
.binding = 0,
.location = 1,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex, texcoord),
},
{
.binding = 0,
.location = 2,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex, texcoordex),
},
{
.binding = 0,
.location = 3,
.format = VK_FORMAT_R32_SFLOAT,
.offset = offsetof(Vertex, alpha),
},
{
.binding = 0,
.location = 4,
.format = VK_FORMAT_R32_SFLOAT,
.offset = offsetof(Vertex, idx),
}};
VkPipelineVertexInputStateCreateInfo vertexInputInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.pNext = nullptr,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &vertex_input_bindings,
.vertexAttributeDescriptionCount = 5,
.pVertexAttributeDescriptions = vertex_input_attributes,
};
VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(render.cmdBuffer_[bufferIndex], 0, 1, &buffers.vertexBuf_, &offset);
How can I solve the problem? Thanks for any help.
update
I get some information from Renderdoc by capturing frame. The result shows that vertex shader doesn't output correct data.(The vertex shader is a pass.)
But Renderdoc shows that vertex buffer has correct data.
Meanwhile, the vertex shader output varies each run, and never gets right.
Is it a sync issue? Where might the mistake be.
vertex shader data from Renderdoc
// Draw one frame
bool VulkanDrawFrame(void) {
uint32_t nextIndex;
// Get the framebuffer index we should draw in
CALL_VK(vkAcquireNextImageKHR(device.device_, swapchain.swapchain_,
UINT64_MAX, render.semaphore_, VK_NULL_HANDLE,
&nextIndex));
CALL_VK(vkResetFences(device.device_, 1, &render.fence_));
VkPipelineStageFlags waitStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = nullptr,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &render.semaphore_,
.pWaitDstStageMask = &waitStageMask,
.commandBufferCount = 1,
.pCommandBuffers = &render.cmdBuffer_[nextIndex],
.signalSemaphoreCount = 0,
.pSignalSemaphores = nullptr};
CALL_VK(vkQueueSubmit(device.queue_, 1, &submit_info, render.fence_));
CALL_VK(
vkWaitForFences(device.device_, 1, &render.fence_, VK_TRUE, 100000000));
LOGI("Drawing frames......");
VkResult result;
VkPresentInfoKHR presentInfo{
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pNext = nullptr,
.swapchainCount = 1,
.pSwapchains = &swapchain.swapchain_,
.pImageIndices = &nextIndex,
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.pResults = &result,
};
vkQueuePresentKHR(device.queue_, &presentInfo);
return true;
}
// Create the pipeline
VkGraphicsPipelineCreateInfo pipelineCreateInfo{
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.stageCount = 2,
.pStages = shaderStages,
.pVertexInputState = &vertexInputInfo,
.pInputAssemblyState = &inputAssemblyInfo,
.pTessellationState = nullptr,
.pViewportState = &viewportInfo,
.pRasterizationState = &rasterInfo,
.pMultisampleState = &multisampleInfo,
.pDepthStencilState = nullptr,
.pColorBlendState = &colorBlendInfo,
.pDynamicState = &dynamicStateInfo,
.layout = gfxPipeline.layout_,
.renderPass = render.renderPass_,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = 0,
};
VkResult pipelineResult = vkCreateGraphicsPipelines(
device.device_, gfxPipeline.cache_, 1, &pipelineCreateInfo, nullptr,
&gfxPipeline.pipeline_);
I have sovled this.
The driver optimizes useless inputs. I delete operations concerning to them to simplify the debug, so the driver finds they are useless.
I have a Hand mesh which I want to animate.
I have the Skeleton which can be hierarchically animated.
My mesh is also weighted in Blender. So each vertex has 4 associated bones to be affected by.
When I apply the Animation of my Skeleton to the mesh, the hierarchy is applied correctly. (so the hierarchy of the mesh, matches the hierarchy of the Skeleton).
So far so good, now question:
the fingers look to be stretched (its like the fingers smashed by a heavy door). Why?
Note: (I didnt apply the bind pose bone Transformation Matrix explicitly, but I read about it and I believe its functionality is there, in the hierarchical Transformation I have for my Skeleton).
If you need more clarification of the steps, please ask.
vector<glm::mat4> Posture1Hand::HierarchyApplied(HandSkltn HNDSKs){
vector <glm::mat4> Matrices;
Matrices.resize(HNDSKs.GetLimbNum());
//non Hierarchical Matrices
for (unsigned int i = 0; i < Matrices.size(); i++){
Matrices[i] = newPose[i].getModelMatSkltn(HNDSKs.GetLimb(i).getLwCenter());
}
for (unsigned int i = 0; i < Matrices.size(); i++){
vector<Limb*>childeren = HNDSKs.GetLimb(i).getChildren();
for (unsigned int j = 0; j < childeren.size(); j++){
Matrices[childeren[j]->getId()] = Matrices[i] * Matrices[childeren[j]->getId()];
}
}
return Matrices;
}
Here is my getModelMatSkltn method.
inline glm::mat4 getModelMatSkltn(const glm::vec3& RotationCentre) const{//to apply the rotation on the whole heirarchy
glm::mat4 posMatrix = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
posMatrix = glm::translate(posMatrix, newPos);
glm::mat4 trMatrix = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
glm::mat4 OriginTranslate = glm::translate(trMatrix, -RotationCentre);
glm::mat4 InverseTranslate = glm::translate(trMatrix, RotationCentre);
glm::mat4 rotXMatrix = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
rotXMatrix = glm::rotate(rotXMatrix, glm::radians(newRot.x), glm::vec3(1, 0, 0));
glm::mat4 rotYMatrix = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
rotYMatrix = glm::rotate(rotYMatrix, glm::radians(newRot.y), glm::vec3(0, 1, 0));
glm::mat4 rotZMatrix = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
rotZMatrix = glm::rotate(rotZMatrix, glm::radians(newRot.z), glm::vec3(0, 0, 1));
glm::mat4 scaleMatric = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
scaleMatric = glm::scale(scaleMatric, newScale);
glm::mat4 rotMatrix = rotZMatrix*rotYMatrix*rotXMatrix;
rotMatrix = InverseTranslate*rotMatrix*OriginTranslate;
return posMatrix*rotMatrix*scaleMatric;
}
and this is how I send 20 transformation Matrix (because of 20 joints in Hand) to GPU:
void GLShader::Update(const vector trMat, const GLCamera& camera){
vector<glm::mat4> MVP; MVP.resize(trMat.size());
for (unsigned int i = 0; i < trMat.size(); i++){
MVP[i] = camera.getViewProjection()* trMat[i];
}
glUniformMatrix4fv(newUniform[TRANSFORM_U], trMat.size(), GL_FALSE, &MVP[0][0][0]);//4 floating value
}
I guess one should be familiar with calculation of vertex position in the shader in order to be able to answer the question, but I send a part of my vertex shader too.
attribute vec3 position;
attribute vec2 texCoord;
attribute vec4 weight;
attribute vec4 weightInd;
uniform mat4 transform[20];//vector of uniform for 20 number of joints in my skleton
void main(){
mat4 WMat;//weighted matrix
float w;
int Index;
for (int i=0; i<4; i++){
Index=int(weightInd[i]);
w=weight[i];
WMat += w*transform[Index];
}
gl_Position= WMat*vec4(position, 1.0);
}
I am trying to render a simple triangle with OpenGL 3.3, but when I call glDrawArrays my program crashes with a segmentation fault. The language I'm using is C++ and I use the libraries SDL, glew and glm.
I think what happens is, that the draw call tries to access data that doesn't belong to the vertex buffer I have set up.
For reasons that don't really matter I can not provide the whole source code of my program. However I can provide some relevant snippets and a trace of the OpenGL calls issued, generated with the tool Apitrace.
[...]
glClearColor(red = 0, green = 0, blue = 0.5, alpha = 1)
glClear(mask = COLOR_BUFFER_BIT)
glGenVertexArrays(n = 1, arrays = &1)
glBindVertexArray(array = 1)
glGenBuffers(n = 1, buffer = &1)
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 1)
glBufferData(target = GL_ARRAY_BUFFER, size = 72, data = blob(72), usage = GL_STATIC_DRAW)
glVertexAttribPointer(index = 0, size = 3, type = GL_FLOAT, normalized = GL_FALSE, stride = 24, pointer = NULL)
glVertexAttribPointer(index = 1, size = 3, type = GL_FLOAT, normalized = GL_FALSE, stride = 24, pointer = 0xc)
glEnableVertexAttribArray(index = 0)
glEnableVertexAttribArray(index = 1)
glCreateShader(type = GL_VERTEX_SHADER) = 1
glShaderSource(shader = 1, count = 1, string = &"#version 330
layout (location = 0) in vec3 iPosition;
layout (location = 1) in vec3 iNormal;
void main() {
gl_Position = vec4(iPosition.x, iPosition.y, iPosition.z, iNormal.z * -1.0);
}", length = NULL)
glCreateShader(type = GL_FRAGMENT_SHADER) = 2
glShaderSource(shader = 2, count = 1, string = &"#version 330
out vec4 oFragColor;
void main() {
oFragColor = vec4(1.0, 0.0, 0.0, 1.0);
}", length = NULL)
glCompileShader(shader = 1)
glGetShaderiv(shader = 1, pname = GL_COMPILE_STATUS, params = &1)
glCompileShader(shader = 2)
glGetShaderiv(shader = 2, pname = GL_COMPILE_STATUS, params = &1)
glCreateProgram() = 3
glAttachShader(program = 3, shader = 1)
glAttachShader(program = 3, shader = 2)
glBindAttribLocation(program = 3, index = 1, name = "iNormal")
glBindAttribLocation(program = 3, index = 0, name = "iPosition")
glLinkProgram(program = 3)
glGetProgramiv(program = 3, pname = GL_LINK_STATUS, params = &1)
glGetAttribLocation(program = 3, name = "iPosition") = 0
glGetAttribLocation(program = 3, name = "iNormal") = 1
glGetIntegerv(pname = GL_CURRENT_PROGRAM, params = &0)
glUseProgram(program = 3)
glBindVertexArray(array = 1)
glClear(mask = GL_COLOR_BUFFER_BIT)
glDrawArrays(mode = GL_TRIANGLES, first = 0, count = 3) //incomplete (segfault here)
As I said, I think the problem is, that the draw call tries to access data in a wrong way. I have already checked the data in the vertex buffer using glGetBufferSubData. So here is the Code i use to set up the VAO:
Mesh::Mesh(const std::vector<Triangle>& triangles): _vao(0), _vbo(0) {
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
struct Vertex {
glm::vec3 position;
glm::vec3 normal;
}
Vertex* vertecies = new Vertex[triangles.size() * 3];
// [...]
// Convert triangles to vertecies, store them in the array.
glBufferData(GL_ARRAY_BUFFER, triangles.size() * 3 * sizeof(Vertex), vertecies, GL_STATIC_DRAW);
delete[] vertecies;
//Position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(0));
//Normal
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(3 * sizeof(GL_FLOAT)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
}
I suspect the error to be in the way I call glVertexAttribPointer.
If other parts of the program are necessary to answer, leave me a comment and I'll see what I can do to provide them.
I dont see anything wrong with your code. I usually get this problem when my context isnt set correctly. For example, when I dont have GLEW set up correctly in my case. That may be the same problem for you.
I'm confused about using glMultiDrawElementsIndirect(), could anyone explain to me the meaning of the cmd struct used by that drawing command?
struct cmd:
count = ..
primCount = ..
firstIndex = ..
baseVertex = ..
baseInstance = ..
if I have three different triangle strips to draw, would that be like this?
for (int n = 0; n < 3; n++)
{
count = indexCount;
primCount = 1;
firstIndex = n * count;
baseVertex = 0;
baseInstance = n;
...
}
Setup Buffers:
protected void setupBuffers()
{
gl.glGenVertexArrays(1, vaoBuff);
gl.glBindVertexArray(vaoBuff.get(0));
gl.glGenBuffers(5, vboBuff);
//bind indirect buffer object
gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
gl.glBufferData(GL4.GL_DRAW_INDIRECT_BUFFER, instanceCount * 5 * Integer.SIZE / 8, null, GL4.GL_STATIC_DRAW);
gl.glBufferSubData(...);
//bind draw instance ID in the shader with a buffer object
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(1));
gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount * Integer.SIZE / 8, drawIndexBuff, GL4.GL_STATIC_DRAW);
gl.glVertexAttribIPointer(d_idLoc, 1, GL4.GL_UNSIGNED_INT, 0, 0);
gl.glVertexAttribDivisor(d_idLoc, 1);
gl.glEnableVertexAttribArray(d_idLoc);
//bind vertex data buffer object
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(2));
gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount / column_subdivision * vertBuffSize * Float.SIZE / 8, null, GL4.GL_STATIC_DRAW);
gl.glBufferSubData(...);
gl.glVertexAttribPointer(verPosLoc, 3, GL4.GL_FLOAT, false, 0, 0);
gl.glEnableVertexAttribArray(verPosLoc);
//bind vertex index data buffer object
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, vboBuff.get(3));
gl.glBufferData(GL4.GL_ELEMENT_ARRAY_BUFFER, instanceCount / column_subdivision * indexBuffSize * Integer.SIZE / 8, null, GL4.GL_STATIC_DRAW);
gl.glBufferSubData(...);
//bind texture coordinate data buffer object
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(4));
gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount / column_subdivision * texBuffSize * Float.SIZE / 8, null, GL4.GL_STATIC_DRAW);
gl.glBufferSubData(...);
gl.glVertexAttribPointer(tc_inLoc, 2, GL4.GL_FLOAT, false, 0, 0);
gl.glEnableVertexAttribArray(tc_inLoc);
}
drawing command:
gl.glBindVertexArray(vaoBuff.get(0));
glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
gl.glMultiDrawElementsIndirect(GL4.GL_TRIANGLE_STRIP, GL4.GL_UNSIGNED_INT, null, 3, 0);
Fixed it, there're some problems within the vertex data. The other is all correct.