OpenGL开发
跳到导航
跳到搜索
目录
实例化OpenGL绘图简述
高效实例化OpenGL开发绘图在科研上的应用还是比较广泛,这部分的开发我们在这里做个简单示例说明,如果您有特殊应用请联系我们做更多应用。
为实现显卡并发高效绘图,例如应用于千万量级原子体系绘图,需要使用glDrawElementsInstanced或glDrawArraysInstanced API,主要涉及GLSL,VBO,VAO等的正确使用。
注意事项:
- shaders应该创建于特定的program id下
- VBO,VAO的显存使用和program没有关系,但顶点属性的定义(vertex attribe location)必须和shader中的location一致
- 可以多个VAO共享一个VBO
- 要实现更高效绘图,还需要进行culling、遮挡等处理
例子
GLSL语言在不同厂家显卡有些不同,例如在Intel显卡上存在if/else解析不完整,会造成属性丢失,因此尽量少用if/else,在编译shaders代码里可以用glGetAttribLocation,glGetUniformLocation进行验证。
Vertex shader
#version 330
layout (location = 0) in vec3 vertexpos;
layout (location = 1) in vec3 vertexnor;
layout (location = 2) in vec4 objoffset;
layout (location = 3) in vec3 objcolor;
out vec3 in_col;
uniform mat4 modelview;
uniform mat4 projection;
uniform vec3 light_pos;
uniform vec3 light_col;
void main() {
vec3 mnor=normalize(modelview*vec4(vertexnor,0.0)).xyz;
vec4 mpos=modelview*vec4(vertexpos.x*objoffset.w+objoffset.x,vertexpos.y*objoffset.w+objoffset.y,vertexpos.z*objoffset.w+objoffset.z, 1.0);
gl_Position = projection*mpos;
float li=dot(mnor,light_pos);
if (li<0.0){
//li=0.0;
in_col=vec3(0,0,0);
return;
}
in_col=objcolor*(light_col*li);
}
fragment shader
#version 330
out vec4 FragColor;
in vec3 in_col;
void main()
{
FragColor=vec4(in_col,1.0);
//col = vec4(vec_col.x*vec_nor.x,vec_col.y*vec_nor.y,vec_col.z*vec_nor.z,1.0);
}
编译shaders
void MyGL_VAO::CreateShaders(wxString fnvs, wxString fnfs)
{
wxString srcVShaderCode;
{
wxString sfn=fnvs;//MySysUtil::FindAppFile("mgishader.vs");
wxArrayString lines;
bee_gettextfilecontent(&lines,sfn,false,false);
srcVShaderCode=bee_strings2string(lines,"\n");
}
const char *psrcV=srcVShaderCode.c_str().AsChar();
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &psrcV, NULL);
glCompileShader(vertex);
GLint success;
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
wxString serr=infoLog;
beeDebug("** Failed to compile vshader: %ls\n",WSTR2CSTR(serr));
}
else{
beeLog("## vectex shader compiled\n");
}
//fragment shader
wxString srcFShaderCode;
{
wxString sfn=fnfs;//MySysUtil::FindAppFile("mgishader.fs");
wxArrayString lines;
bee_gettextfilecontent(&lines,sfn,false,false);
srcFShaderCode=bee_strings2string(lines,"\n");
}
const char *psrcF=srcFShaderCode.c_str().AsChar();
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &psrcF, NULL);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
wxString serr=infoLog;
beeDebug("** Failed to compile fshader: %ls\n",WSTR2CSTR(serr));
}
else{
beeLog("## fragment shader compiled\n");
}
//attach shader and link
glAttachShader(m_id_program, vertex);
glAttachShader(m_id_program, fragment);
glLinkProgram(m_id_program);
glGetProgramiv(m_id_program, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(m_id_program, 512, NULL, infoLog);
wxString serr=infoLog;
beeDebug("** failed to attach shader: %ls\n",WSTR2CSTR(serr));
}
else{
beeLog("## shader attached\n");
}
m_iloc_attr_vertex=glGetAttribLocation(m_id_program, "vertexpos");
m_iloc_attr_normal=glGetAttribLocation(m_id_program,"vertexnor");
m_iloc_attr_translation_scale=glGetAttribLocation(m_id_program,"objoffset");
m_iloc_attr_color=glGetAttribLocation(m_id_program,"objcolor");
beeDebug("# vertex location: %d\n",m_iloc_attr_vertex);
beeDebug("# normal location: %d\n", m_iloc_attr_normal);
beeDebug("# offset location: %d\n",m_iloc_attr_translation_scale);
beeDebug("# color location: %d\n",m_iloc_attr_color);
m_iloc_uniform_projection=glGetUniformLocation(m_id_program,"projection");
m_iloc_uniform_modelview=glGetUniformLocation(m_id_program,"modelview");
beeDebug("# projection loc: %d\n",m_iloc_uniform_projection);
beeDebug("# modelview loc: %d\n",m_iloc_uniform_modelview);
m_iloc_uniform_light_pos=glGetUniformLocation(m_id_program,"light_pos");
m_iloc_uniform_light_col=glGetUniformLocation(m_id_program,"light_col");
m_iloc_uniform_light_amb_col=glGetUniformLocation(m_id_program,"light_amb_col");
beeDebug("# light pos loc: %d\n",m_iloc_uniform_light_pos);
beeDebug("# light color loc: %d\n",m_iloc_uniform_light_col);
beeDebug("# light amber color loc: %d\n",m_iloc_uniform_light_amb_col);
//release
glDeleteShader(vertex);
glDeleteShader(fragment);
glReleaseShaderCompiler();
}
VBO
如果使用glDrawElementsInstanced,VBO里就得有一个GL_ELEMENT_ARRAY_BUFFER,也就是EBO,三角形顶点序号序列,对于3D绘图需要在vertex shader里有一个vertex normal属性,用于光照计算。
void MyGL_VBO::Create(vector <GLfloat> &vertices, vector <GLfloat> &normals, vector <GLushort> &indices)
{
//vertexes create vbo ;
glGenBuffers(1, &m_ibuffer_vertex);
glBindBuffer(GL_ARRAY_BUFFER, m_ibuffer_vertex);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(GLfloat), &vertices[0], GL_STATIC_DRAW);
//create ibo, triangles indexes;
glGenBuffers(1, &m_ibuffer_indeces);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibuffer_indeces);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(GLushort),&indices[0], GL_STATIC_DRAW);
m_nIndecies=indices.size();
//vertexes normal
glGenBuffers(1,&m_ibuffer_normal);
glBindBuffer(GL_ARRAY_BUFFER, m_ibuffer_normal);
glBufferData(GL_ARRAY_BUFFER, normals.size()*sizeof(GLfloat),&normals[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
}
VAO
VAO可以理解为VBO的包装,附加每个实例的属性,例如这里一个球体有N顶点,每个原子表示为一个球,每个原子只有一位置、大小、颜色、纹理,通过glVertexAttribDivisor来指定每个球体的属性位置
配置Instance属性的顺序为:
- glBindBuffer 绑定显存地址
- glEnableVertexAttribArray 启用某个属性
- glVertexAttribPointer 指定属性地址,最后两个参数是内存步长和偏移
- glVertexAttribDivisor 拆分
例如一个原子包含位置3个float,大小1个float,(这里代码的位置和大小合并为一个4个float的属性),颜色三个float,所有原子都独立的属性数据,也即每个原子7个float,所有原子的属性是序列排列的,那么这里的glVertexAttribPointer 最后两个参数是7*sizeof(float),位置的偏移量为0,颜色的偏移量为4*sizeof(float),
void MyGL_VAO::Create(MyGL_VBO *pVBO, int ninstance)
{
m_pVBO=pVBO;
//gen vao
glGenVertexArrays(1, &m_id_vao);
glBindVertexArray(m_id_vao);
//create ibo, triangles indexes;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pVBO->m_ibuffer_indeces);
glBindBuffer(GL_ARRAY_BUFFER, m_pVBO->m_ibuffer_vertex);
glEnableVertexAttribArray(m_iloc_attr_vertex);
glVertexAttribPointer(m_iloc_attr_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0);
//vertexes normal
//glGenBuffers(1,&m_sphere_nbuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_pVBO->m_ibuffer_normal);
glEnableVertexAttribArray(m_iloc_attr_normal);
glVertexAttribPointer(m_iloc_attr_normal, 3, GL_FLOAT, GL_FALSE, 0, 0);
//instance color, i.e one color for each atom
AllocInstancesMemory(ninstance);
//must unbind vao first
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
m_nInstances=ninstance;
}
void MyGL_VAO::AllocInstancesMemory(int ninstance)
{
if(ninstance>m_nInstances_allocated){
if(m_id_buffer_instance_data!=0){
//beeDebug("## call delete m_id_buffer_instance_data\n");
glDeleteBuffers(1,&m_id_buffer_instance_data);
m_id_buffer_instance_data=0;
}
glGenBuffers(1, &m_id_buffer_instance_data);
glBindBuffer(GL_ARRAY_BUFFER, m_id_buffer_instance_data);
glBufferData(GL_ARRAY_BUFFER,ninstance*(4+3)*sizeof(GLfloat),NULL,GL_STATIC_DRAW);
glEnableVertexAttribArray(m_iloc_attr_translation_scale);
glVertexAttribPointer(m_iloc_attr_translation_scale, 4, GL_FLOAT, GL_FALSE,7*sizeof(GLfloat), 0);
glVertexAttribDivisor(m_iloc_attr_translation_scale, 1);
glEnableVertexAttribArray(m_iloc_attr_color);
glVertexAttribPointer(m_iloc_attr_color, 3, GL_FLOAT, GL_FALSE, 7*sizeof(GLfloat), (void *)(4*sizeof(GLfloat)));
glVertexAttribDivisor(m_iloc_attr_color, 1);
m_nInstances_allocated=ninstance;
}
m_nInstances=ninstance;
}
使用VAO
void MyGL_VAO::Draw(float *fLightPosition, float *fLightColor)
{
if(m_pVBO==NULL || m_id_program==0 || m_nInstances==0 || m_id_vao==0) return;
glUseProgram(m_id_program);
glBindVertexArray(m_id_vao);
glUniform3fv(m_iloc_uniform_light_pos,1,fLightPosition);
glUniform3fv(m_iloc_uniform_light_col,1,fLightColor);
glUniform3fv(m_iloc_uniform_light_amb_col,1,fLightColor);
GLfloat m[16];
glGetFloatv(GL_MODELVIEW_MATRIX,m);
glUniformMatrix4fv(m_iloc_uniform_modelview,1,GL_FALSE,m);
glGetFloatv(GL_PROJECTION_MATRIX,m);
glUniformMatrix4fv(m_iloc_uniform_projection,1,GL_FALSE,m);
glDrawElementsInstanced(GL_TRIANGLES,m_pVBO->m_nIndecies,GL_UNSIGNED_SHORT,NULL,m_nInstances);
glBindVertexArray(0);
glUseProgram(0);
}