Skip to content

Commit e0276c6

Browse files
authored
Merge pull request #208 from compas-dev/update/buffermanager
Update/buffermanager
2 parents b35b9f1 + 803b873 commit e0276c6

30 files changed

+977
-708
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
* Added `BufferManager` to handle buffer data for all the scene objects.
13+
* Added `make_texture_buffer` in `gl.py` for matrix and settings array.
14+
1215
### Changed
1316

17+
* Greatly improved performance for scenes with large number of objects.
18+
* All scene objects are rendered once in a combined buffer through single draw call.
19+
* Updated shaders to version OpenGL 330 Core Profile.
20+
* Implemented matrix and settings array as texture buffer instead of uniforms to improve performance.
21+
* Blending of transparent objects is handled in a second draw on top of the opaque objects.
22+
1423
### Removed
1524

25+
* Removed all low-level buffer related functions from `SceneObject`s, which is now handled together by `BufferManager`.
26+
* Removed redundant Shaders: `grid_shader`, `instance_shader`, `surface_shader` and `arrow_shader`.
27+
* Removed `paint_instance` from `Renderer` as it handled by a shader flag.
28+
1629

1730
## [1.3.2] 2025-03-12
1831

docs/examples/dynamic/dynamic.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
def movepoint(frame):
1212
print("frame", frame)
1313
obj.geometry.x += 0.1
14-
obj.init()
15-
obj.update()
14+
obj.update(update_data=True)
1615

1716

1817
viewer.show()

docs/examples/dynamic/dynamic_mesh.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@
1111
obj = viewer.scene.add(mesh, surfacecolor=Color.cyan(), use_vertexcolors=False)
1212

1313

14-
@viewer.on(interval=1000)
14+
@viewer.on(interval=200)
1515
def deform_mesh(frame):
1616
for v in mesh.vertices():
1717
vertex: list = mesh.vertex_attributes(v, "xyz") # type: ignore
1818
vertex[0] += random() - 0.5
1919
vertex[1] += random() - 0.5
2020
vertex[2] += random() - 0.5
2121
mesh.vertex_attributes(v, "xyz", vertex)
22-
obj.init()
23-
obj.update()
22+
obj.update(update_data=True)
2423
print(frame)
2524

2625

docs/examples/dynamic/orbiting.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
viewer.scene.add(
1919
Mesh.from_shape(sphere, u=32, v=32),
2020
facecolor=Color.cyan(),
21-
edgecolor=Color.blue(),
21+
linecolor=Color.blue(),
2222
use_vertexcolors=False,
2323
)
2424

2525

2626
@viewer.on(interval=100)
2727
def orbit(f):
28-
viewer.renderer.camera.rotation.z += 1
28+
viewer.renderer.camera.rotation.z += 0.02
2929

3030

3131
viewer.show()

docs/examples/object/points.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
viewer = Viewer()
88
for i in range(10):
99
point = Point(random() * 10, random() * 10, random() * 10)
10-
viewer.scene.add(point, pointcolor=Color(random(), random(), random()), pointsize=30)
10+
viewer.scene.add(point, pointcolor=Color(random(), random(), random()), pointsize=random() * 50)
1111

1212

1313
viewer.show()

scripts/boxes.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from compas.colors import Color
2+
from compas.geometry import Box
3+
from compas_viewer.viewer import Viewer
4+
from compas.geometry import Translation
5+
6+
viewer = Viewer()
7+
N = 10
8+
for i in range(N):
9+
for j in range(N):
10+
for k in range(N):
11+
obj = viewer.scene.add(
12+
Box(0.5, 0.5, 0.5),
13+
show_points=True,
14+
linecolor=Color.white(),
15+
pointcolor=Color(1 - i / N, 1 - j / N, 1 - k / N),
16+
pointsize=10,
17+
facecolor=Color(i / N, j / N, k / N),
18+
name=f"Box_{i}_{j}_{k}",
19+
)
20+
21+
obj.transformation = Translation.from_vector([i, j, k])
22+
23+
viewer.show()

scripts/dynamic_box.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@
33
from compas.datastructures import Mesh
44
from compas.geometry import Box
55
from compas_viewer import Viewer
6+
from compas.geometry import Translation
67

78
viewer = Viewer()
89

910
mesh = Mesh.from_shape(Box.from_width_height_depth(2, 2, 2))
10-
obj = viewer.scene.add(mesh)
11+
obj1 = viewer.scene.add(mesh)
12+
obj2 = viewer.scene.add(mesh)
13+
obj2.transformation = Translation.from_vector([5, 0, 0])
1114

15+
obj3 = viewer.scene.add(mesh)
16+
obj3.transformation = Translation.from_vector([-5, 0, 0])
17+
18+
obj1.opacity = 0.7
1219

1320
@viewer.on(interval=100)
1421
def deform_mesh(frame):
@@ -18,7 +25,19 @@ def deform_mesh(frame):
1825
vertex[1] += (random() - 0.5) * 0.1
1926
vertex[2] += (random() - 0.5) * 0.1
2027
mesh.vertex_attributes(v, "xyz", vertex)
21-
obj.update()
28+
29+
obj1.transformation = Translation.from_vector([random() - 0.5, random() - 0.5, random() - 0.5])
30+
obj3.transformation *= Translation.from_euler_angles([0.05, 0, 0])
31+
32+
# Three objects share the same geometry data, but updated differently
33+
# obj1 should move around and deform
34+
obj1.update(update_transform=True, update_data=True)
35+
36+
# obj2 will not move but will deform
37+
obj2.update(update_transform=False, update_data=True)
38+
39+
# obj3 will rotate but not deform
40+
obj3.update(update_transform=True, update_data=False)
2241

2342

2443
viewer.show()

scripts/group.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@
2222
box1 = box1.transformed(Translation.from_vector([0, 5, 0]))
2323
box2 = box2.transformed(Translation.from_vector([0, 5, 0]))
2424
group3 = viewer.scene.add([[box1], box2])
25+
group3.transformation = Translation.from_vector([0, 0, 5])
2526
viewer.show()

src/compas_viewer/gl.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def make_index_buffer(data, dynamic=False):
9090
return vbo
9191

9292

93-
def update_vertex_buffer(data, buffer):
93+
def update_vertex_buffer(data, buffer, offset=0):
9494
"""Update a vertex buffer with new data.
9595
9696
Parameters
@@ -99,12 +99,14 @@ def update_vertex_buffer(data, buffer):
9999
A flat list of floats.
100100
buffer : int
101101
The ID of the buffer.
102+
offset : int
103+
Byte offset into the buffer where the update should start.
102104
"""
103105
n = len(data)
104106
size = n * ct.sizeof(ct.c_float)
105107
data = (ct.c_float * n)(*data)
106108
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, buffer)
107-
GL.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, size, data)
109+
GL.glBufferSubData(GL.GL_ARRAY_BUFFER, offset, size, data)
108110
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)
109111

110112

@@ -124,3 +126,51 @@ def update_index_buffer(data, buffer):
124126
GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, buffer)
125127
GL.glBufferSubData(GL.GL_ELEMENT_ARRAY_BUFFER, 0, size, data)
126128
GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0)
129+
130+
131+
def make_texture_buffer(data, internal_format=GL.GL_RGBA32F):
132+
"""Make a texture buffer from the given data.
133+
134+
Parameters
135+
----------
136+
data : numpy.ndarray
137+
A numpy array of floats.
138+
internal_format : GLenum, optional
139+
The internal format for the texture buffer. Default is GL.GL_RGBA32F.
140+
141+
Returns
142+
-------
143+
int
144+
The texture ID.
145+
"""
146+
# Create buffer
147+
buffer = GL.glGenBuffers(1)
148+
GL.glBindBuffer(GL.GL_TEXTURE_BUFFER, buffer)
149+
150+
GL.glBufferData(GL.GL_TEXTURE_BUFFER, data.nbytes, data, GL.GL_STATIC_DRAW)
151+
152+
# Create texture
153+
texture = GL.glGenTextures(1)
154+
GL.glBindTexture(GL.GL_TEXTURE_BUFFER, texture)
155+
GL.glTexBuffer(GL.GL_TEXTURE_BUFFER, internal_format, buffer)
156+
157+
return texture
158+
159+
160+
def update_texture_buffer(data, texture, offset=0):
161+
"""Update a texture buffer with new data.
162+
163+
Parameters
164+
----------
165+
data : numpy.ndarray
166+
A numpy array of floats.
167+
texture : int
168+
The texture ID.
169+
offset : int
170+
Byte offset into the buffer where the update should start.
171+
"""
172+
GL.glBindTexture(GL.GL_TEXTURE_BUFFER, texture)
173+
buffer = GL.glGetTexLevelParameteriv(GL.GL_TEXTURE_BUFFER, 0, GL.GL_TEXTURE_BUFFER_DATA_STORE_BINDING)
174+
GL.glBindBuffer(GL.GL_TEXTURE_BUFFER, buffer)
175+
GL.glBufferSubData(GL.GL_TEXTURE_BUFFER, offset, data.nbytes, data)
176+
GL.glBindBuffer(GL.GL_TEXTURE_BUFFER, 0)

0 commit comments

Comments
 (0)