如何解决如何使用PyOpenGL渲染文本?
我正在学习现代的openGL,目前我在呈现文本时遇到了麻烦。我正在使用C ++中的tutorial,但是我正在尝试在python中实现。
这是我的代码:
from OpenGL.GL import *
from OpenGL.glu import *
from OpenGL.GL import shaders
import glfw
import freetype
import glm
import numpy as np
from PIL import Image
import math
import time
class CharacterSlot:
def __init__(self,texture,glyph):
self.texture = texture
self.textureSize = (glyph.bitmap.width,glyph.bitmap.rows)
if isinstance(glyph,freetype.GlyphSlot):
self.bearing = (glyph.bitmap_left,glyph.bitmap_top)
self.advance = glyph.advance.x
elif isinstance(glyph,freetype.BitmapGlyph):
self.bearing = (glyph.left,glyph.top)
self.advance = None
else:
raise RuntimeError('unkNown glyph type')
def _get_rendering_buffer(xpos,ypos,w,h,zfix=0.0):
return np.asarray([
xpos,ypos - h,zfix,0.0,1.0,xpos,xpos + w,1.0
],np.float32)
VERTEX_SHADER = """
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos,vec2 tex>
out vec2 TexCoords;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vertex.xy,1.0);
TexCoords = vertex.zw;
}
"""
FRAGMENT_SHADER = """
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
vec4 sampled = vec4(1.0,texture(text,TexCoords).r);
color = vec4(textColor,1.0) * sampled;
}
"""
shaderProgram = None
Characters = dict()
VBO = None
VAO = None
def initliaze():
global VERTEXT_SHADER
global FRAGMENT_SHADER
global shaderProgram
global Characters
global VBO
global VAO
#compiling shaders
vertexshader = shaders.compileShader(VERTEX_SHADER,GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER,GL_FRAGMENT_SHADER)
#creating shaderProgram
shaderProgram = shaders.compileProgram(vertexshader,fragmentshader)
#get projection
#problem
shader_projection = glGetUniformlocation(shaderProgram,"projection")
projection = glm.ortho(0.0,640,640)
gluniformMatrix4fv(shader_projection,1,GL_FALSE,glm.value_ptr(projection));
#disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
face = freetype.Face("Vera.ttf")
face.set_char_size( 48*64 )
#load first 128 characters of ASCII set
for i in range(0,128):
face.load_char(chr(i))
glyph = face.glyph
#generate texture
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D,texture)
glTexImage2D(GL_TEXTURE_2D,GL_RGB,glyph.bitmap.width,glyph.bitmap.rows,GL_UNSIGNED_BYTE,glyph.bitmap.buffer)
#texture options
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
#Now store character for later use
Characters[chr(i)] = CharacterSlot(texture,glyph)
glBindTexture(GL_TEXTURE_2D,0);
#configure VAO/VBO for texture quads
VAO = glGenVertexArrays(1)
glBindVertexArray(VAO)
VBO = glGenBuffers(1);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,6 * 4,None,GL_DYNAMIC_DRAW);
glEnabLevertexAttribArray(0);
glVertexAttribPointer(0,4,GL_FLOAT,0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
def render_text(window,text,x,y,scale,color):
global shaderProgram
global Characters
global VBO
global VAO
face = freetype.Face("Vera.ttf")
face.set_char_size(48*64)
gluniform3f(glGetUniformlocation(shaderProgram,"textColor"),color[0]/255,color[1]/255,color[2]/255)
glActiveTexture(GL_TEXTURE0);
for c in text:
ch = Characters[c]
w,h = ch.textureSize
w = w*scale
h = w*scale
vertices = _get_rendering_buffer(x,h)
#render glyph texture over quad
glBindTexture(GL_TEXTURE_2D,ch.texture);
#update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferSubData(GL_ARRAY_BUFFER,len(vertices),vertices)
glBindBuffer(GL_ARRAY_BUFFER,0);
#render quad
glDrawArrays(GL_TRIANGLES,6);
#Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.advance+6)*scale;
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D,0);
glfwSwapBuffers(window);
glfwPollEvents();
def main():
glfw.init()
window = glfw.create_window(640,"EXAMPLE PROGRAM",None)
glfw.make_context_current(window)
initliaze()
while not glfw.window_should_close(window):
glfw.poll_events()
glClearColor(0,1);
glClear(GL_COLOR_BUFFER_BIT);
render_text(window,'hello',(100,100,100))
glfw.terminate()
if __name__ == '__main__':
main()
到目前为止,我可以分两部分来面对麻烦。 initliaze()中的第一个问题是以下部分的错误。
shader_projection = glGetUniformlocation(shaderProgram,glm.value_ptr(projection));
我已注释掉上面的部分以忽略。第二个问题是在 render_text()函数中,以下部分出现了错误。
gluniform3f(glGetUniformlocation(shaderProgram,color[2]/255)
更多地方可能存在问题。我不明白为什么文本渲染会如此困难。我在这里想念什么?
解决方法
您没有通过glUseProgram
安装着色器程序:
shaderProgram = shaders.compileProgram(vertexshader,fragmentshader)
glUseProgram(shaderProgram) # <---
glBufferData
的第二个参数和glBufferSubData
的第三个参数的大小为以字节为单位:
glBufferData(GL_ARRAY_BUFFER,6 * 4,None,GL_DYNAMIC_DRAW)
glBufferData(GL_ARRAY_BUFFER,6 * 4 * 4,GL_DYNAMIC_DRAW)
glBufferSubData(GL_ARRAY_BUFFER,len(vertices),vertices)
glBufferSubData(GL_ARRAY_BUFFER,vertices.nbytes,vertices)
顶点属性由一个二维顶点坐标(x,y)和一个二维纹理坐标组成。从顶点属性数据数组中删除zfix
。此外,您必须翻转纹理坐标的第二部分(否则文本将上下颠倒)
def _get_rendering_buffer(xpos,ypos,w,h,zfix=0.0):
return np.asarray([
xpos,ypos - h,xpos,1,xpos + w,0
],np.float32)
glVertexAttribIPointer
的 stride 参数必须以字节为单位。如果 stride 为0,则将通用顶点属性理解为紧密包装在数组中。因此,在您的情况下,步幅必须为16或0:
glVertexAttribPointer(0,4,GL_FLOAT,GL_FALSE,0)
glVertexAttribPointer(0,None)
face.load_char(chr(i))
生成具有彩色通道的图像(每个像素1字节)。使用内部格式和格式GL_RED
而不是GL_RGB
来生成二维纹理图像:
glTexImage2D(GL_TEXTURE_2D,GL_RED,glyph.bitmap.width,glyph.bitmap.rows,GL_UNSIGNED_BYTE,glyph.bitmap.buffer)
在绘制文本之前,必须绑定顶点数组:
glBindVertexArray(VAO)
for c in text:
# [...]
glDrawArrays(GL_TRIANGLES,6)
增加x
时会出现错字,您必须使用>>
运算符而不是+
运算符:
x += (ch.advance+6)*scale
x += (ch.advance>>6)*scale
和计算h
时的另一种错字:
h = w*scale
h = h*scale
您必须启用Alpha blending:
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
在NDC(规范化设备坐标)中,左下角是(-1,-1),右上角是(1、1)。以这种方式设置正交投影,使窗口的左上角位于(0,0):
projection = glm.ortho(0.0,640,0.0,640)
projection = glm.ortho(0,0)
文本的参考点在底部。因此,您必须将x坐标设置为大于文本高度:
render_text(window,'hello',(100,100,100))
render_text(window,20,50,(255,100))
查看完整的示例(我使用了其他字体):
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL import shaders
import glfw
import freetype
import glm
import numpy as np
from PIL import Image
import math
import time
fontfile = "Vera.ttf"
#fontfile = r'C:\source\resource\fonts\gnu-freefont_freesans\freesans.ttf'
class CharacterSlot:
def __init__(self,texture,glyph):
self.texture = texture
self.textureSize = (glyph.bitmap.width,glyph.bitmap.rows)
if isinstance(glyph,freetype.GlyphSlot):
self.bearing = (glyph.bitmap_left,glyph.bitmap_top)
self.advance = glyph.advance.x
elif isinstance(glyph,freetype.BitmapGlyph):
self.bearing = (glyph.left,glyph.top)
self.advance = None
else:
raise RuntimeError('unknown glyph type')
def _get_rendering_buffer(xpos,np.float32)
VERTEX_SHADER = """
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos,vec2 tex>
out vec2 TexCoords;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vertex.xy,1.0);
TexCoords = vertex.zw;
}
"""
FRAGMENT_SHADER = """
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
vec4 sampled = vec4(1.0,1.0,texture(text,TexCoords).r);
color = vec4(textColor,1.0) * sampled;
}
"""
shaderProgram = None
Characters = dict()
VBO = None
VAO = None
def initliaze():
global VERTEXT_SHADER
global FRAGMENT_SHADER
global shaderProgram
global Characters
global VBO
global VAO
#compiling shaders
vertexshader = shaders.compileShader(VERTEX_SHADER,GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER,GL_FRAGMENT_SHADER)
#creating shaderProgram
shaderProgram = shaders.compileProgram(vertexshader,fragmentshader)
glUseProgram(shaderProgram)
#get projection
#problem
shader_projection = glGetUniformLocation(shaderProgram,"projection")
projection = glm.ortho(0,0)
glUniformMatrix4fv(shader_projection,glm.value_ptr(projection))
#disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
face = freetype.Face(fontfile)
face.set_char_size( 48*64 )
#load first 128 characters of ASCII set
for i in range(0,128):
face.load_char(chr(i))
glyph = face.glyph
#generate texture
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D,texture)
glTexImage2D(GL_TEXTURE_2D,glyph.bitmap.buffer)
#texture options
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
#now store character for later use
Characters[chr(i)] = CharacterSlot(texture,glyph)
glBindTexture(GL_TEXTURE_2D,0)
#configure VAO/VBO for texture quads
VAO = glGenVertexArrays(1)
glBindVertexArray(VAO)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER,VBO)
glBufferData(GL_ARRAY_BUFFER,GL_DYNAMIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0,None)
glBindBuffer(GL_ARRAY_BUFFER,0)
glBindVertexArray(0)
def render_text(window,text,x,y,scale,color):
global shaderProgram
global Characters
global VBO
global VAO
face = freetype.Face(fontfile)
face.set_char_size(48*64)
glUniform3f(glGetUniformLocation(shaderProgram,"textColor"),color[0]/255,color[1]/255,color[2]/255)
glActiveTexture(GL_TEXTURE0)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
glBindVertexArray(VAO)
for c in text:
ch = Characters[c]
w,h = ch.textureSize
w = w*scale
h = h*scale
vertices = _get_rendering_buffer(x,h)
#render glyph texture over quad
glBindTexture(GL_TEXTURE_2D,ch.texture)
#update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER,VBO)
glBufferSubData(GL_ARRAY_BUFFER,vertices)
glBindBuffer(GL_ARRAY_BUFFER,0)
#render quad
glDrawArrays(GL_TRIANGLES,6)
#now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.advance>>6)*scale
glBindVertexArray(0)
glBindTexture(GL_TEXTURE_2D,0)
glfw.swap_buffers(window)
glfw.poll_events()
def main():
glfw.init()
window = glfw.create_window(640,"EXAMPLE PROGRAM",None)
glfw.make_context_current(window)
initliaze()
while not glfw.window_should_close(window):
glfw.poll_events()
glClearColor(0,1)
glClear(GL_COLOR_BUFFER_BIT)
render_text(window,100))
glfw.terminate()
if __name__ == '__main__':
main()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。