EGL OpenGL 初始化
생성일: 2024년 11월 21일
답변에 사용된 모델 OpenAI 01 Preview by OpenAI01
생성일: 2024년 11월 21일
답변에 사용된 모델 OpenAI 01 Preview by OpenAI01
探讨错误原因
根据OpenGL错误1282(GL_INVALID_OPERATION),这个错误发生在调用glMatrixMode(GL_MODELVIEW)时。找到问题的根源,解决这个运行问题。
探索现代OpenGL
搭建EGL和OpenGL上下文后,旧式OpenGL函数如glMatrixMode和gluOrtho2D可能不可用,或者OpenGL上下文未完全初始化。
绑定API
我在代码中创建了一个OpenGL ES 2.0上下文,并通过eglBindAPI绑定了OpenGL API。这样的话,如果尝试使用桌面OpenGL函数,就会抛出GL_INVALID_OPERATION错误。
调整代码设置
现在我在调整代码以创建桌面OpenGL上下文,而不是OpenGL ES上下文。我正在反思如何合适地设置上下文属性和绑定API。
指定OpenGL上下文
在请求OpenGL 2.1上下文时,需要设置特定的属性。如果不设置版本,则默认为此版本。同时,有些实现需要特殊属性来创建兼容性配置文件上下文。
探讨解决方案
OpenGL ES 2.0 中不使用固定功能管道函数,因此需要重新编写代码或创建支持固定功能管道的 OpenGL 上下文。 Option 2 需要显著的代码更改。
纠正绑定顺序
在创建上下文之前绑定API是关键,这里目前的顺序反了过来。
顺序和属性调整问题
调整代码策略
我正在探讨将eglBindAPI(EGL_OPENGL_API)调用移到eglCreateContext调用前,并去掉EGL_CONTEXT_CLIENT_VERSION,因为它适用于OpenGL ES而不是OpenGL。
创建OpenGL上下文
我正在设置OpenGL上下文以确保eglBindAPI调用发生在任何上下文创建之前。这样做可以避免创建错误的上下文。
初始化和配置
我正在初始化用以处理图形渲染的环境。这包括调用函数来设置显示、绑定API、选择配置、创建表面和OpenGL上下文。
调整方法
我正在尝试创建OpenGL ES上下文时使用桌面OpenGL函数,可能导致错误。可以检查EGL实现是否支持创建OpenGL上下文,或替代GLU函数以确保可用性。
编写代码
我正在根据指示改写代码,提供所需的中文说明。这让我思考如何明确功能需求并确保代码的准确性。
初始化平台和环境
我正在设置 EGL 错误检测和 EGL 初始化,包括显示获取、EGL API 绑定、配置选择、Pbuffer 表面和 OpenGL 上下文创建。任务似乎复杂但关键。
渲染字符纹理
在将字符渲染为纹理时,首先查看字符是否可渲染。如果可以,则加载字符的位图并转换为纹理;否则,使用透明纹理。
调整创建画布
我在创建OpenGL上下文之前先绑定了OpenGL API,移除了与OpenGL ES相关的上下文属性,保持上下文属性为默认值。这是为了确保可以正确使用OpenGL。
# -*- coding: utf-8 -*- import os os.environ['PYOPENGL_PLATFORM'] = 'egl' import sys import ctypes import numpy as np from OpenGL.EGL import * from OpenGL.GL import * from OpenGL.GLU import * import freetype from PIL import Image from fontTools.ttLib import TTFont # 定义 EGL 错误检查函数 def check_egl_error(): error = eglGetError() if error != EGL_SUCCESS: print(f"EGL error: {error}") sys.exit(1) # 初始化 EGL def init_egl(width, height): display = eglGetDisplay(EGL_DEFAULT_DISPLAY) if display == EGL_NO_DISPLAY: print("无法获取 EGL 显示") sys.exit(1) major = ctypes.c_long() minor = ctypes.c_long() if not eglInitialize(display, ctypes.byref(major), ctypes.byref(minor)): print("无法初始化 EGL") sys.exit(1) # 绑定 OpenGL API if not eglBindAPI(EGL_OPENGL_API): print("无法绑定 OpenGL API") sys.exit(1) # 选择合适的 EGL 配置 attribs = [ EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE ] config = EGLConfig() num_configs = ctypes.c_int() if not eglChooseConfig(display, attribs, ctypes.byref(config), 1, ctypes.byref(num_configs)): print("无法选择 EGL 配置") sys.exit(1) if num_configs.value < 1: print("没有找到合适的 EGL 配置") sys.exit(1) # 创建 Pbuffer surface pbuffer_attribs = [ EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE ] surface = eglCreatePbufferSurface(display, config, pbuffer_attribs) if surface == EGL_NO_SURFACE: print("无法创建 Pbuffer Surface") sys.exit(1) # 创建 OpenGL 上下文 context_attribs = [EGL_NONE] context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs) if context == EGL_NO_CONTEXT: print("无法创建 EGL 上下文") sys.exit(1) # 使上下文当前 if not eglMakeCurrent(display, surface, surface, context): print("无法使 EGL 上下文当前") sys.exit(1) check_egl_error() return display, surface, context # 终止 EGL def terminate_egl(display, surface, context): eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) eglDestroySurface(display, surface) eglDestroyContext(display, context) eglTerminate(display) # 字符检测和字体渲染设置 text = "暨南" primary_font_path = "/mnt/lgs/Open-Sora/moviepys/input/阿里汉仪黑体.ttf" # 主字体路径 fallback_font_path = "/mnt/lgs/Open-Sora/moviepys/output/fonts/舟游黑.otf" # 备用字体路径 font_size = 100 # 字体大小 # 加载字体 try: primary_face = freetype.Face(primary_font_path) primary_face.set_char_size(font_size * 64) except IOError: print(f"无法加载主字体:{primary_font_path}") sys.exit(1) try: fallback_face = freetype.Face(fallback_font_path) fallback_face.set_char_size(font_size * 64) except IOError: print(f"无法加载备用字体:{fallback_font_path}") sys.exit(1) # 使用 fontTools 检查字体是否支持某个字符 def can_render(char, font_path): try: font = TTFont(font_path) for table in font['cmap'].tables: if ord(char) in table.cmap: return True return False except Exception as e: print(f"检查字符 '{char}' 时出错: {e}") return False # 准备字符和对应字体的列表 render_chars = [] for char in text: if can_render(char, primary_font_path): render_chars.append(('primary', char)) elif can_render(char, fallback_font_path): render_chars.append(('fallback', char)) else: print(f"字符 '{char}' 无法由主字体或备用字体渲染。使用主字体作为默认。") render_chars.append(('primary', char)) # 生成每个字符的纹理 def load_glyph(face, char): face.load_char(char, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT) bitmap = face.glyph.bitmap width, height = bitmap.width, bitmap.rows buffer = bitmap.buffer if width == 0 or height == 0: # 如果字符没有位图(例如空格),返回空纹理 texture_id = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture_id) # 创建一个1x1透明纹理 empty_image = np.zeros((1, 1, 4), dtype=np.ubyte) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, empty_image ) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) return texture_id, face.glyph.bitmap_left, face.glyph.bitmap_top, 1, 1, face.glyph.advance.x # 将灰度图转换为 RGBA image = np.array(buffer, dtype=np.ubyte).reshape(height, width) image_rgba = np.zeros((height, width, 4), dtype=np.ubyte) image_rgba[:, :, 0] = 255 # R image_rgba[:, :, 1] = 255 # G image_rgba[:, :, 2] = 255 # B image_rgba[:, :, 3] = image # A # 垂直翻转纹理数据 image_rgba = np.flipud(image_rgba) # 生成 OpenGL 纹理 texture_id = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture_id) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_rgba ) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) return texture_id, face.glyph.bitmap_left, face.glyph.bitmap_top, width, height, face.glyph.advance.x # 预加载所有字符的纹理 textures = {} for idx, (font_type, char) in enumerate(render_chars): key = f"{font_type}_{char}" if key not in textures: if font_type == 'primary': face = primary_face else: face = fallback_face textures[key] = load_glyph(face, char) # 计算文本的总宽度和最大高度 total_width = 0 max_height = 0 char_metrics = [] for font_type, char in render_chars: key = f"{font_type}_{char}" tex, left, top, w, h, advance = textures[key] char_metrics.append((tex, left, top, w, h, advance)) total_width += advance >> 6 # advance 是以1/64像素为单位 if h > max_height: max_height = h # 设置文本绘制的位置(居中) size = (1080, 1920) start_x = (size[0] - total_width) // 2 start_y = (size[1] - max_height) // 2 # 初始化 EGL display, surface, context = init_egl(size[0], size[1]) # 设置 OpenGL 视口和投影 glViewport(0, 0, size[0], size[1]) glMatrixMode(GL_PROJECTION) glLoadIdentity() # 设置 2D 投影矩阵,y 轴向下 gluOrtho2D(0, size[0], size[1], 0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() # 设置背景为透明 glClearColor(0.0, 0.0, 0.0, 0.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 启用透明度混合 glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # 开始绘制文本 glEnable(GL_TEXTURE_2D) glColor4f(1.0, 1.0, 1.0, 1.0) # 设置颜色为白色 current_x = start_x for tex, left, top, w, h, advance in char_metrics: glBindTexture(GL_TEXTURE_2D, tex) xpos = current_x + left ypos = start_y + (max_height - h) # 绘制纹理四边形 glBegin(GL_QUADS) glTexCoord2f(0, 0) glVertex2f(xpos, ypos) glTexCoord2f(1, 0) glVertex2f(xpos + w, ypos) glTexCoord2f(1, 1) glVertex2f(xpos + w, ypos + h) glTexCoord2f(0, 1) glVertex2f(xpos, ypos + h) glEnd() current_x += advance >> 6 glDisable(GL_TEXTURE_2D) # 读取像素数据 glPixelStorei(GL_PACK_ALIGNMENT, 1) data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) image = Image.frombytes("RGBA", size, data) image = image.transpose(Image.FLIP_TOP_BOTTOM) # 翻转图像以匹配 OpenGL 坐标系 # 保存图像 output_path = "/mnt/lgs/Open-Sora/gstreamers/output/opengl_rendered_text.png" image.save(output_path) print(f"OpenGL 渲染结果已保存为 {output_path}") # 清理资源 for tex in textures.values(): glDeleteTextures(tex[0]) # 终止 EGL terminate_egl(display, surface, context)
主要修改如下:
调整 EGL 上下文的创建顺序:在创建 OpenGL 上下文之前,先绑定 OpenGL API。将 eglBindAPI(EGL_OPENGL_API)
调用移动到了 eglCreateContext
之前。
修改上下文属性:创建 OpenGL 上下文时,移除了 EGL_CONTEXT_CLIENT_VERSION
属性,因为它适用于 OpenGL ES。现在的上下文属性仅为 [EGL_NONE]
,以获取默认的 OpenGL 上下文。
确保使用正确的 OpenGL API:通过在绑定 API 时明确使用 EGL_OPENGL_API
,确保创建的是桌面版 OpenGL 上下文,而非 OpenGL ES。
这些修改确保了创建的 OpenGL 上下文支持固定功能管线,因此可以使用 glMatrixMode
、glLoadIdentity
、gluOrtho2D
等函数,从而避免了 GL_INVALID_OPERATION
错误。
希望这些修改能解决您的问题。如有其他疑问,请随时提出!