我正在将固定函数(使用显示列表)OpenGL 实现转换为使用 OpenGL 现代方法(着色器)
该应用程序是一个雷达扫描转换器,它将矩形纹理映射到我的顶点网格(如果有意义的话)。纹理大小为2k * 2k
(我正在使用 Qt OpenGl 包装类)
显示列表为每个雷达辐条及其相邻辐条创建一个四边带。因此将有 2k 个四边形条带进行渲染。代码如下
glNewList(displayList, GL_COMPILE);
glEnable(GL_TEXTURE_2D);
GLuint texture = m_radarView->texture()->textureId();
glBindTexture(GL_TEXTURE_2D, texture);
for(uint azimuth = 0 ; azimuth < azimuthSamples; ++azimuth)
{
auto azimuth2 = azimuth+1;
if (azimuth2 >= azimuthSamples)
azimuth2 = 0;
glBegin(GL_QUAD_STRIP);
GLfloat atex = (azimuth * atexd) + (atexd / 2.0), atex2 = azimuth2 != 0 ? (azimuth2 * atexd) + (atexd / 2.0) : 1.0;
const QList<QPointF> &line1 = watcher->resultAt(azimuth), &line2 = watcher->resultAt(azimuth2);
for(int range = 0; range < rangeSamples; range++)
{
glTexCoord2f((rtexd * range) + (rtexd / 2.0), atex);
glVertex3f(line1.at(range).x(), line1.at(range).y(), 0.0);
glTexCoord2f((rtexd * range) + (rtexd / 2.0), atex2);
glVertex3f(line2.at(range).x(), line2.at(range).y(), 0.0);
}
glEnd();
}
glBindTexture(GL_TEXTURE_2D, 0);
glEndList();
我渲染成这样
glCallList(displayList);
这工作正常(显示任意目标放大)
所以我尝试使用现代方法着色器、VBO 和 VAO 来复制这一点
m_vao = new QOpenGLVertexArrayObject(this);
m_vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
m_vao->create();
m_vbo->setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_vbo->create();
auto numVertices = textureSize().width() * textureSize().height() * 2;
auto verticesSize = numVertices * sizeof(QVector2D);
auto textureSize = numVertices * sizeof(QVector2D);
auto textureOffset = verticesSize;
m_vao->bind();
m_vbo->bind();
//the VAO must be bound here - this is part of the VAO state
m_vbo->allocate(verticesSize + textureSize);
shaderProgram()->bind();
const int vertexLocation = 1;
shaderProgram()->enableAttributeArray(vertexLocation);
shaderProgram()->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 2);
const int texLocation = 2;
shaderProgram()->enableAttributeArray(texLocation);
shaderProgram()->setAttributeBuffer(texLocation, GL_FLOAT, textureOffset, 2);
m_vao->release();
m_vbo->release();
shaderProgram()->release();
创建顶点和纹理坐标并写入VBO(与displayList实现类似的循环
//map each cartesian point to a texture coordinate - one quad strip for each azimuth spoke
for(uint azimuth = 0 ; azimuth < azimuthSamples; ++azimuth)
{
auto azimuth2 = azimuth+1;
if (azimuth2 >= azimuthSamples)
azimuth2 = 0;
const QList<QPointF> &line1 = watcher->resultAt(azimuth), &line2 = watcher->resultAt(azimuth2);
auto atex = (azimuth * atexd) + (atexd / 2.0), atex2 = azimuth2 != 0 ? (azimuth2 * atexd) + (atexd / 2.0) : 1.0;
for (uint range = 0; range < rangeSamples; ++range)
{
vertices.append(QVector2D(line1.at(range).x(), line1.at(range).y()));
textCords.append(QVector2D((rtexd * range) + (rtexd / 2.0), atex));
vertices.append(QVector2D(line2.at(range).x(), line2.at(range).y()));
textCords.append(QVector2D((rtexd * range) + (rtexd / 2.0), atex2));
Q_ASSERT(textCords.last().x()<=1.0 && textCords.last().y()<=1.0);
}
}
m_vbo->bind();
auto verticesSize = vertices.size() * sizeof(QVector2D);
auto textureSize = textCords.size() * sizeof(QVector2D);
m_vbo->write(0, vertices.constData(), verticesSize);
m_vbo->write(verticesSize, textCords.constData(), textureSize);
m_vbo->release();
然后在渲染中
shaderProgram()->bind();
shaderProgram()->setUniformValue(shaderProgram()->uniformLocation("modelViewMatrix"), projection);
//explicitly set the texture unit
shaderProgram()->setUniformValue("bscan", 0);
texture()->bind();
m_vao->bind();
**//is this correct ? should this be in a loop ?**
glDrawArrays(GL_QUAD_STRIP, 0, textureSize().width() * textureSize().height() * 2);
m_vao->release();
shaderProgram()->release();
texture()->release();
目标放大后的结果如下所示
正如你所看到的,它有点粗糙(放大镜使用线性正确设置,纹理是8位亮度格式)
应该
glDrawArrays(GL_QUAD_STRIP, 0, textureSize().width() * textureSize().height() * 2);
这可以循环执行(每个方位角轮辐一个)?
知道是什么原因造成的吗?
这应该在循环中调用 - 不知道它是如何工作的
glDrawArrays(GL_QUAD_STRIP, 0, textureSize().width() * textureSize().height() * 2);
每个四边形条一次
auto verticesPerQuadStrip = texture()->height() * 2;
for (int i = 0; i < textureSize().width(); ++i)
glDrawArrays(GL_QUAD_STRIP, i * verticesPerQuadstrip, verticesPerQuadstrip);