Genesis icon indicating copy to clipboard operation
Genesis copied to clipboard

Visualization Bug - AttributeError: function 'glGetUniformLocation' not found

Open Bardia323 opened this issue 11 months ago โ€ข 40 comments

Visualizing the elastic dragon example on Windows:

(venv) PS S:\Tools\genesis> py .\elastic_dragon.py --vis
[Genesis] [21:41:21] [INFO] Running on [NVIDIA GeForce RTX 3090 Ti] with backend gs.cuda. Device memory: 23.99 GB.
[Genesis] [21:41:22] [DEBUG] [Taichi] version 1.7.2, llvm 15.0.1, commit 0131dce9, win, python 3.10.5
[Genesis] [21:41:22] [DEBUG] [Taichi] Starting on arch=cuda
[Genesis] [21:41:22] [INFO] ๐Ÿš€ Genesis initialized. ๐Ÿ”– version: 0.2.0, ๐ŸŒฑ seed: None, ๐Ÿ“ precision: '32', ๐Ÿ› debug: False, ๐ŸŽจ theme: 'dark'.
[Genesis] [21:41:22] [INFO] Scene <2463c84> created.
[Genesis] [21:41:22] [INFO] Adding <gs.PBD3DEntity>. idx: 0, uid: <e6ec9b0>, morph: <gs.morphs.Mesh(file='S:\Tools\genesis\venv\lib\site-packages\genesis\assets\meshes/dragon/dragon.obj')>, material: <gs.PBD.Elastic>.
[Genesis] [21:41:22] [DEBUG] Remeshed file (`.rm`) found in cache.
[Genesis] [21:41:23] [INFO] Building scene <2463c84>...
[Genesis] [21:41:25] [INFO] Compiling simulation kernels...
[Genesis] [21:41:30] [INFO] Building visualizer...
Traceback (most recent call last):
  File "S:\Tools\genesis\elastic_dragon.py", line 58, in <module>
    main()
  File "S:\Tools\genesis\elastic_dragon.py", line 49, in main
    scene.build()
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\utils\misc.py", line 38, in wrapper
    return method(self, *args, **kwargs)
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\engine\scene.py", line 556, in build
    self._visualizer.build()
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\vis\visualizer.py", line 101, in build
    self._context.build(self._scene)
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\vis\rasterizer_context.py", line 70, in build
    self.jit = JITRenderer(self._scene, [], [])
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\ext\pyrender\jit_render.py", line 201, in __init__
    self.gen_func_ptr()
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\ext\pyrender\jit_render.py", line 354, in gen_func_ptr
    self.gl = GLWrapper()
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\ext\pyrender\numba_gl_wrapper.py", line 24, in __init__
    load_func("glGetUniformLocation", GLint, GLuint, GLvoidp)
  File "S:\Tools\genesis\venv\lib\site-packages\genesis\ext\pyrender\numba_gl_wrapper.py", line 52, in load_func
    func_ptr = GL.platform.ctypesloader.buildFunction(
  File "S:\Tools\genesis\venv\lib\site-packages\OpenGL\platform\ctypesloader.py", line 96, in buildFunction
    return functionType( (name, dll), )
AttributeError: function 'glGetUniformLocation' not found
[Genesis] [21:41:30] [INFO] ๐Ÿ’ค Exiting Genesis and caching compiled kernels...

causes an AttributeError. Works fine without the --vis flag.

Bardia323 avatar Dec 19 '24 02:12 Bardia323

I met the same problem

qiyashandian avatar Dec 19 '24 03:12 qiyashandian

same problem here

r530044129 avatar Dec 19 '24 03:12 r530044129

Is everyone here using Windows?

YilingQiao avatar Dec 19 '24 03:12 YilingQiao

Is everyone here using Windows?

Here is win11

r530044129 avatar Dec 19 '24 03:12 r530044129

same problem using win11

Awilekong avatar Dec 19 '24 03:12 Awilekong

Same problem here as well. I use win 11 and made sure all the dependencies are installed.
Following the topic.

agenel avatar Dec 19 '24 05:12 agenel

https://genesis-world.readthedocs.io/en/latest/user_guide/overview/installation.html Based on our test, rendering is not supported on Windows due to OpenGL issues. It would be super appreciated if someone could find a solution. Otherwise, Linux or macOS are the only platforms supporting rasterization.

zhenjia-xu avatar Dec 19 '24 05:12 zhenjia-xu

https://genesis-world.readthedocs.io/en/latest/user_guide/overview/installation.html Based on our test, rendering is not supported on Windows due to OpenGL issues. It would be super appreciated if someone could find a solution. Otherwise, Linux or macOS are the only platforms supporting rasterization.

I added a small try/except feature in the 'load_func()' function in numba_gl_wrapper.py. Here is the list of libraries that can be loaded successfully or not.

Failed to load glGetUniformLocation: function 'glGetUniformLocation' not found
Failed to load glUniformMatrix4fv: function 'glUniformMatrix4fv' not found
Failed to load glUniform1i: function 'glUniform1i' not found
Failed to load glUniform1f: function 'glUniform1f' not found
Failed to load glUniform2f: function 'glUniform2f' not found
Failed to load glUniform3fv: function 'glUniform3fv' not found
Failed to load glUniform4fv: function 'glUniform4fv' not found
Failed to load glBindVertexArray: function 'glBindVertexArray' not found
Failed to load glActiveTexture: function 'glActiveTexture' not found
Loaded glBindTexture successfully.
Loaded glEnable successfully.
Loaded glDisable successfully.
Loaded glBlendFunc successfully.
Loaded glPolygonMode successfully.
Loaded glCullFace successfully.
Failed to load glDrawElementsInstanced: function 'glDrawElementsInstanced' not found
Failed to load glDrawArraysInstanced: function 'glDrawArraysInstanced' not found
Failed to load glUseProgram: function 'glUseProgram' not found
Loaded glFlush successfully.
Loaded glReadPixels successfully.
Failed to load glBindBuffer: function 'glBindBuffer' not found
Failed to load glBufferData: function 'glBufferData' not found
Failed to load glBufferSubData: function 'glBufferSubData' not found 

Another thing I noticed is the way of the definition of the functions(or objects).

glFlush: an example of the function that loads successfully <OpenGL.platform.baseplatform.glFlush object at 0x000001AF92DDEB90> glGetUniformLocation: an example of the function cannot load OpenGL.lazywrapper.lazy( 'glGetUniformLocation' )

I hope it helps.

agenel avatar Dec 19 '24 06:12 agenel

I met the same problem in Win10.

I found that in pyrender/numba_gl_wrapper.py/load_func, the variable dll pointed at 'C:\WINDOWS\system32\opengl32.dll', which we know that windows only support OpenGL until version 1.1, but what we need is OpenGL2.0 or later. so is there anyone know, how to change the default OpenGL version that dll = GL.platform.PLATFORM.GL pointed at?

Another interesting thing is, the following code can work:

python
>>> from OpenGL.GL import glGetUniformLocation as a
>>> from OpenGL.GL import glActiveTexture as b
>>> a
OpenGL.lazywrapper.lazy( 'glGetUniformLocation' )
>>> b
<OpenGL.platform.baseplatform.glActiveTexture object at 0x000002845FD4C550>

So I wonder if there's a way that we just import those function directly instead of load them from load_func?

QixuanAI avatar Dec 19 '24 07:12 QixuanAI

Same Problem.

Based on our test, rendering is not supported on Windows due to OpenGL issues.

Hope someone can solve it!!!!

Physics-Lee avatar Dec 19 '24 07:12 Physics-Lee

Lame. I spent a while trying to get this to run. This is the blocking error.

Should put a warning on the repo that it doesn't work on windows 11 currently

TheSeanLavery avatar Dec 19 '24 07:12 TheSeanLavery

We can make a workaround, but simpler and slower, for Windows visualization by modifying elastic_dragon.py --vis to render a GIF using matplotlib instead of OpenGL.
  1. Add imports at top:
import matplotlib.pyplot as plt, imageio, io
  1. Disable OpenGL viewer:
show_viewer=False
  1. Replace simulation loop visualization:
for i in range(horizon):
    scene.step()

with

if args.vis:
    # Pre-create figure once
    fig = plt.figure(figsize=(8, 8), dpi=100)
    ax = fig.add_subplot(111, projection='3d')
    frames = []

    for i in range(horizon):
        scene.step()
        if i % 20 == 0:
            # Get positions and update scatter plot
            pos = scene.get_state()._solvers_state[5]._pos.cpu().numpy()
            ax.clear()  # Clear previous frame
            ax.scatter(pos[:, 0], pos[:, 1], pos[:, 2], c='red', s=1)

            # Capture frame directly to memory
            buf = io.BytesIO()
            fig.savefig(buf, format='png')
            buf.seek(0)
            frames.append(imageio.imread(buf))
            buf.close()

    plt.close()
    imageio.mimsave('simulation.gif', frames, fps=10)

Katehuuh avatar Dec 19 '24 08:12 Katehuuh

Lame. I spent a while trying to get this to run. This is the blocking error.

Should put a warning on the repo that it doesn't work on windows 11 currently

the compatibility matrix here on the docs does say that windows viewer is not supported. however adding camera is not supported also image

barius avatar Dec 19 '24 09:12 barius

I met the same problem in Win10.

I found that in pyrender/numba_gl_wrapper.py/load_func, the variable dll pointed at 'C:\WINDOWS\system32\opengl32.dll', which we know that windows only support OpenGL until version 1.1, but what we need is OpenGL2.0 or later. so is there anyone know, how to change the default OpenGL version that dll = GL.platform.PLATFORM.GL pointed at?

Another interesting thing is, the following code can work:

python
>>> from OpenGL.GL import glGetUniformLocation as a
>>> from OpenGL.GL import glActiveTexture as b
>>> a
OpenGL.lazywrapper.lazy( 'glGetUniformLocation' )
>>> b
<OpenGL.platform.baseplatform.glActiveTexture object at 0x000002845FD4C550>

So I wonder if there's a way that we just import those function directly instead of load them from load_func?

the OpenGL.lazywrapper.lazy( 'glGetUniformLocation' ) upon calling raises NullFunctionError: Attempt to call an undefined function glGetUniformLocation, check for bool(glGetUniformLocation) before calling, seems like the lazy wrapper can't find the symbol during runtime

barius avatar Dec 19 '24 09:12 barius

same problem, GPU:nvidiaRTX3070ti C:\Users\32653\PycharmProjects\PythonProject.venv\Scripts\python.exe C:\Users\32653\PycharmProjects\PythonProject\main.py [Genesis] [19:00:39] [INFO] โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ [Genesis] [19:00:39] [INFO] โ”‚โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆ Genesis โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‰โ”ˆโ”‚ [Genesis] [19:00:39] [INFO] โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ [Genesis] [19:00:39] [INFO] Running on [Intel64 Family 6 Model 154 Stepping 3, GenuineIntel] with backend gs.cpu. Device memory: 31.68 GB. [Genesis] [19:00:39] [INFO] ๐Ÿš€ Genesis initialized. ๐Ÿ”– version: 0.2.0, ๐ŸŒฑ seed: None, ๐Ÿ“ precision: '32', ๐Ÿ› debug: False, ๐ŸŽจ theme: 'dark'. [Genesis] [19:00:39] [INFO] Scene <1c2da54> created. [Genesis] [19:00:39] [INFO] Adding <gs.RigidEntity>. idx: 0, uid: , morph: <gs.morphs.Plane>, material: <gs.materials.Rigid>. [Genesis] [19:00:39] [INFO] Adding <gs.RigidEntity>. idx: 1, uid: , morph: <gs.morphs.MJCF(file='C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\assets\xml/franka_emika_panda/panda.xml')>, material: <gs.materials.Rigid>. [Genesis] [19:00:40] [INFO] Building scene <1c2da54>... [Genesis] [19:00:52] [INFO] Compiling simulation kernels... [Genesis] [19:01:07] [INFO] Building visualizer... Traceback (most recent call last): File "C:\Users\32653\PycharmProjects\PythonProject\main.py", line 10, in scene.build() File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\utils\misc.py", line 38, in wrapper return method(self, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\engine\scene.py", line 556, in build self._visualizer.build() File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\vis\visualizer.py", line 101, in build self._context.build(self._scene) File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\vis\rasterizer_context.py", line 70, in build self.jit = JITRenderer(self._scene, [], []) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\ext\pyrender\jit_render.py", line 201, in init self.gen_func_ptr() File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\ext\pyrender\jit_render.py", line 354, in gen_func_ptr self.gl = GLWrapper() ^^^^^^^^^^^ File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\ext\pyrender\numba_gl_wrapper.py", line 24, in init load_func("glGetUniformLocation", GLint, GLuint, GLvoidp) File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\genesis\ext\pyrender\numba_gl_wrapper.py", line 52, in load_func func_ptr = GL.platform.ctypesloader.buildFunction( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\32653\PycharmProjects\PythonProject.venv\Lib\site-packages\OpenGL\platform\ctypesloader.py", line 96, in buildFunction return functionType( (name, dll), ) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: function 'glGetUniformLocation' not found [Genesis] [19:01:08] [INFO] ๐Ÿ’ค Exiting Genesis and caching compiled kernels.

Jamesyang-jpg avatar Dec 19 '24 11:12 Jamesyang-jpg

I have made some attempts, personally think it should be the problem of PyOpenGL library, PyOpenGL installed directly on 64-bit windows by pip will lack dll files, this problem can be solved, so that PyOpenGL can run normally in other programs. However, the source code seems to use ctypes to load 32-bit dll files, 64-bit python will not find the file, but install 32-bit python will not be able to use "pip install genesis-world", perhaps on linux to solve these problems.

Diaode1 avatar Dec 19 '24 12:12 Diaode1

https://genesis-world.readthedocs.io/en/latest/user_guide/overview/installation.html Based on our test, rendering is not supported on Windows due to OpenGL issues. It would be super appreciated if someone could find a solution. Otherwise, Linux or macOS are the only platforms supporting rasterization.

I added a small try/except feature in the 'load_func()' function in numba_gl_wrapper.py. Here is the list of libraries that can be loaded successfully or not.

Failed to load glGetUniformLocation: function 'glGetUniformLocation' not found
Failed to load glUniformMatrix4fv: function 'glUniformMatrix4fv' not found
Failed to load glUniform1i: function 'glUniform1i' not found
Failed to load glUniform1f: function 'glUniform1f' not found
Failed to load glUniform2f: function 'glUniform2f' not found
Failed to load glUniform3fv: function 'glUniform3fv' not found
Failed to load glUniform4fv: function 'glUniform4fv' not found
Failed to load glBindVertexArray: function 'glBindVertexArray' not found
Failed to load glActiveTexture: function 'glActiveTexture' not found
Loaded glBindTexture successfully.
Loaded glEnable successfully.
Loaded glDisable successfully.
Loaded glBlendFunc successfully.
Loaded glPolygonMode successfully.
Loaded glCullFace successfully.
Failed to load glDrawElementsInstanced: function 'glDrawElementsInstanced' not found
Failed to load glDrawArraysInstanced: function 'glDrawArraysInstanced' not found
Failed to load glUseProgram: function 'glUseProgram' not found
Loaded glFlush successfully.
Loaded glReadPixels successfully.
Failed to load glBindBuffer: function 'glBindBuffer' not found
Failed to load glBufferData: function 'glBufferData' not found
Failed to load glBufferSubData: function 'glBufferSubData' not found 

Another thing I noticed is the way of the definition of the functions(or objects).

glFlush: an example of the function that loads successfully <OpenGL.platform.baseplatform.glFlush object at 0x000001AF92DDEB90> glGetUniformLocation: an example of the function cannot load OpenGL.lazywrapper.lazy( 'glGetUniformLocation' )

I hope it helps.

The reason you're unable to find certain OpenGL functions, such as glGetUniformLocation, in the opengl32.dll export table on Windows is that the opengl32.dll provided by Microsoft is typically outdated and only supports basic functionality. Microsoft doesn't actively maintain or update OpenGL, as they focus more on DirectX for graphics programming.

As is shown below, opengl32.dll at C:\Windows\System32 on Windows 11 24H2 only has limited api sets. glGetUniformLocation is not found. image

Instead, modern OpenGL functionality is provided through GPU drivers from vendors like Nvidia or AMD. These drivers include their own implementations of OpenGL, often providing support for newer versions and extensions.

DearVa avatar Dec 19 '24 13:12 DearVa

same problem using win11

Linus-Civil avatar Dec 19 '24 13:12 Linus-Civil

same problem using win11

y9hack337 avatar Dec 19 '24 15:12 y9hack337

same problem using win11

Eigenoperator avatar Dec 19 '24 15:12 Eigenoperator

same problem using win11 so which example in here can we run on windows 11 ?

wwdok avatar Dec 19 '24 16:12 wwdok

maybe should try wglGetProcAddress to get the opengl func ptr

0x000-0 avatar Dec 19 '24 16:12 0x000-0

image

Using glfw making it works now...

DearVa avatar Dec 19 '24 16:12 DearVa

image

Using glfw making it works now...

Hello. It stops there. Or the viewer Or the viewer doesn't show up if I'm not using the camera.

image

iadolgov avatar Dec 19 '24 19:12 iadolgov

image

Using glfw making it works now...

In this way, although the image cannot be obtained directly at present, the particle position of some routines has actually been generated and can be visualized by plt ๅ›พ็‰‡ ๅ›พ็‰‡ Test program code:

`import torch import matplotlib.pyplot as plt import genesis as gs

all_particles = []

def main(): ########################## init ########################## gs.init()

########################## create a scene ##########################

scene = gs.Scene(
    sim_options=gs.options.SimOptions(
        dt=4e-3,
        substeps=10,
    ),
    sph_options=gs.options.SPHOptions(
        lower_bound=(-0.5, -0.5, 0.0),
        upper_bound=(0.5, 0.5, 1),
        particle_size=0.01,
    ),
    vis_options=gs.options.VisOptions(
        visualize_sph_boundary=True,
    ),
    show_viewer=True,
)

########################## entities ##########################
plane = scene.add_entity(
    morph=gs.morphs.Plane(),
)

liquid = scene.add_entity(
    # viscous liquid
    # material=gs.materials.SPH.Liquid(mu=0.02, gamma=0.02),
    material=gs.materials.SPH.Liquid(),
    morph=gs.morphs.Box(
        pos=(0.0, 0.0, 0.65),
        size=(0.4, 0.4, 0.4),
    ),
    surface=gs.surfaces.Default(
        color=(0.4, 0.8, 1.0),
        vis_mode='particle',
    ),
)

########################## build ##########################
scene.build()

gs.tools.run_in_another_thread(fn=run_sim, args=(scene, False, liquid))

#scene.viewer.start()

def run_sim(scene, enable_vis, liquid): global all_particles i = 0 while True: i += 1

    scene.step()
    particles = liquid.get_particles()
    # print(particles)
    '''
    [-4.8954931e-01  3.9647943e-01  2.0921452e-02]
    [-2.9889485e-01 -3.5985804e-01  2.3578152e-03]
    [-3.0421656e-01  5.0000000e-01  9.5947198e-06]
    '''

    all_particles.append(particles)
    if i > 10:
        break

if enable_vis:
    scene.viewer.stop()

main() while True: if len(all_particles) == 10: for particles in all_particles: fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter(particles[:, 0], particles[:, 1], particles[:, 2]) ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') plt.show()

    plt.show()`

Diaode1 avatar Dec 20 '24 02:12 Diaode1

same problem here

hougd7 avatar Dec 20 '24 04:12 hougd7

same problem here

chenfei8888 avatar Dec 20 '24 11:12 chenfei8888

Can be workarounded using MESA.

image

Short answer

  • Download Mesa OpenGL32.dll from here: https://github.com/lightningterror/mesa3D-Windows/releases (not the official source, but avoid compiling it by yourself).
  • Put it so that it is found before Windows/System32/openGL32.dll. If you use python venv, you can put it in venv/script.
  • Comment the gs.raise_exception in venv\Lib\site-packages\genesis\vis\viewer.py line 67

Long answer

OpenGL is not strickly speaking a library. It is a spec which is implemented by some other parties, especially by GPU vendors in the driver. Historically, Windows has implemented this library at the begining, but stopped at OpenGL 1.2. That's why glGetUniformLocation symbole is not present in windows's OpenGL.dll as glGetUniformLocation has been introducedd in OpenGL 2.x

MESA is a CPU implementation of OpenGL spec. Meaning, it defines and implement all the symboles but the code will be executed on CPU, instead of GPU. Meaning performences will lower.

Real fix would be to load OpenGL symboles from the GPU driver instead of Windows OpenGL32.dll. In C/C++ this is done typically using GLEW. However, I don't know how to proceed in python.

borokov avatar Dec 20 '24 13:12 borokov

same issue with win 11, cuda 12.4, rtx4090 - if the camera/viewer is the part unsupported on windows, how can I run a simulation using genesis and access the data (via spout lookup to the same gpu memory address, ideally) so that I can render it in a separate process? all the example code for simulations (SPH, etc) includes the scene.build() line, which is what triggers the aforementioned issue. how should we run a simulation without using scene.build()?

lakeheck avatar Dec 20 '24 15:12 lakeheck

Could we rely on PyOpenGLโ€™s Automatic Loading? Based on an earlier comment A straightforward โ€œfixโ€ in Python is to rely on PyOpenGL to load extensions for you. Once youโ€™ve created a modern OpenGL context (for example, using GLFW and specifying a minimum core profile version like 3.3), you can:

import glfw from OpenGL.GL import glGetUniformLocation, glUseProgram, ...

Create a window and context

glfw.init() glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) window = glfw.create_window(800, 600, "OpenGL Window", None, None) glfw.make_context_current(window)

Now PyOpenGL will be able to load modern functions

location = glGetUniformLocation(some_program, b"uniformName")

Under the hood, PyOpenGL uses the current context and calls wglGetProcAddress to load entry points for functions not found in opengl32.dll. This typically means you donโ€™t have to do any manual symbol loading yourself, as PyOpenGL mimics what GLEW does in C/C++.

Another option is to get the pointers manually Using wglGetProcAddress with ctypes If you really want to replicate GLEW-like behavior manually:

First, ensure you have a valid, current OpenGL context created by something like GLFW or any other windowing toolkit that can provide a modern context.

Import the necessary functions and DLLs:

import ctypes

Load the system OpenGL library

opengl32 = ctypes.windll.opengl32

Get the wglGetProcAddress function

wglGetProcAddress = opengl32.wglGetProcAddress wglGetProcAddress.restype = ctypes.c_void_p wglGetProcAddress.argtypes = [ctypes.c_char_p]

After making the context current:

func_ptr = wglGetProcAddress(b"glGetUniformLocation") if not func_ptr: raise RuntimeError("Failed to load glGetUniformLocation!")

Once you have the function pointer, you convert it into a callable Python function using ctypes.CFUNCTYPE. For example:

Define a Python signature for glGetUniformLocation

GLGetUniformLocationType = ctypes.CFUNCTYPE( ctypes.c_int, # return type GLint ctypes.c_uint, # GLuint program ctypes.c_char_p # const GLchar *name )

glGetUniformLocation = GLGetUniformLocationType(func_ptr)

Now you can call glGetUniformLocation just like a normal Python function

location = glGetUniformLocation(program, b"myUniform")

This mimics what GLEW does in C/C++: querying the driver for a function pointer and then wrapping it for convenient use.

A valid context is needed because wglGetProcAddress only works when thereโ€™s a current OpenGL context that supports the requested function. If you call it before making the context current or if you have an incompatible context (e.g., too old), it will return None.

Maybe I'm misunderstanding the implementation here but why can't we just use a more modern method to load PyOpenGL. PyOpenGLโ€™s extension loading process is very similar to what GLEW does, but itโ€™s done automatically after you create a modern context and import from OpenGL.GL. Thatโ€™s why the real fix is usually just to create a proper modern OpenGL context, then rely on PyOpenGLโ€™s from OpenGL.GL import ... approach instead of manually loading symbols.

Can anyone clarify why we can't just do something like: import OpenGL.GL as GL from OpenGL.GL import glGetUniformLocation

Instead of manually loading?

supraxylon avatar Dec 20 '24 16:12 supraxylon