Skip to content

replace polyvox with simpler implementation#2026

Merged
ksuprynowicz merged 27 commits intooverte-org:masterfrom
RTUnreal:remove_polyvox
Apr 18, 2026
Merged

replace polyvox with simpler implementation#2026
ksuprynowicz merged 27 commits intooverte-org:masterfrom
RTUnreal:remove_polyvox

Conversation

@RTUnreal
Copy link
Copy Markdown
Collaborator

@RTUnreal RTUnreal commented Jan 14, 2026

This replaces the functionality of the polyvox library, so we don't have to ship it anymore. :)

This will to introduce a bit of a breaking change, where if borders are filled in, then the faces at the border is not rendered. But considering, that polyvox already did it at some of the sides, I tought it would be better to always not render faces there, so that tiling can be done in the future. This can be changed back if needed

@RTUnreal RTUnreal added needs CR This pull request needs to be code reviewed needs QA This pull request needs to be tested labels Jan 21, 2026
Copy link
Copy Markdown
Member

@ksuprynowicz ksuprynowicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Everything looks good :)
I only have minor feedback about some of the formatting changes, let me know what you think about it.

Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp Outdated
Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp Outdated
Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp Outdated
Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp Outdated
@RTUnreal RTUnreal requested a review from ksuprynowicz January 25, 2026 11:11
Copy link
Copy Markdown
Member

@ksuprynowicz ksuprynowicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Everything looks good :)

@ksuprynowicz ksuprynowicz added CR approved This pull request has been successfully code reviewed and removed needs CR This pull request needs to be code reviewed labels Feb 13, 2026
@ksuprynowicz
Copy link
Copy Markdown
Member

I'm getting an assert in Overte_hub:

[02/20 16:13:01] [FATAL] [default] ASSERT: "isInside(index)" in file /home/ksuprynowicz/overte/overte_opt/overte/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp, line 192

@ksuprynowicz
Copy link
Copy Markdown
Member

Backtrace:

__pthread_kill_implementation 0x00007fffec29e95c
__pthread_kill_internal 0x00007fffec29e9ff
__GI_raise 0x00007fffec249cc2
__GI_abort 0x00007fffec2324ac
QMessageLogger::fatal(char const*, ...) const 0x00007ffff6a92514
qt_assert(const char *, const char *, int) 0x00007ffff6a915ae
VoxelVolume::getVoxelAt RenderablePolyVoxEntityItem.cpp:192
operator() RenderablePolyVoxEntityItem.cpp:614
loop3<…>(const glm::vec<…> &, const glm::vec<…> &, struct {...}) RenderablePolyVoxEntityItem.cpp:153
CubicSurfaceExtractorWithNormals::createMesh RenderablePolyVoxEntityItem.cpp:603
operator() RenderablePolyVoxEntityItem.cpp:1933
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
operator() RenderablePolyVoxEntityItem.cpp:1918
QtConcurrent::StoredFunctorCall0::runFunctor(void) qtconcurrentstoredfunctioncall.h:70
QtConcurrent::RunFunctionTask::run qtconcurrentrunbase.h:142
<unknown> 0x00007ffff6ae5e21
<unknown> 0x00007ffff6ae28fd
start_thread 0x00007fffec29cb7b
__GI___clone3 0x00007fffec31a7b8

@JulianGro JulianGro added needs CR This pull request needs to be code reviewed and removed CR approved This pull request has been successfully code reviewed labels Mar 20, 2026
Copy link
Copy Markdown
Member

@JulianGro JulianGro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CMake and Conan changes are trivial and fine.
Thanks for adding the additional copyright notices, or whatever we want to call them.

Would be cool if someone else could review cb49bca

Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp Outdated
@ksuprynowicz
Copy link
Copy Markdown
Member

The newest version hits an assert for me here:

__pthread_kill_implementation 0x00007fffec4a13bc
__pthread_kill_internal 0x00007fffec4a147f
__GI_raise 0x00007fffec44a942
__GI_abort 0x00007fffec4324ac
QMessageLogger::fatal(char const*, ...) const 0x00007ffff6a92514
qt_assert(const char *, const char *, int) 0x00007ffff6a915ae
VoxelVolume::getVoxelAt RenderablePolyVoxEntityItem.cpp:240
operator() RenderablePolyVoxEntityItem.cpp:894
loop3<…>(const glm::vec<…> &, const glm::vec<…> &, struct {...}) RenderablePolyVoxEntityItem.cpp:153
MarchingCubesSurfaceExtractor::createMesh RenderablePolyVoxEntityItem.cpp:883
operator() RenderablePolyVoxEntityItem.cpp:2064
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
operator() RenderablePolyVoxEntityItem.cpp:2049
QtConcurrent::StoredFunctorCall0::runFunctor(void) qtconcurrentstoredfunctioncall.h:70
QtConcurrent::RunFunctionTask::run qtconcurrentrunbase.h:142
<unknown> 0x00007ffff6ae5f01
<unknown> 0x00007ffff6ae29bd
start_thread 0x00007fffec49f469
__GI___clone3 0x00007fffec51dcf8

Index is {21, 21, 21}, valid size is {21, 21, 21} and allocated_size is {21, 21, 21}.

@ksuprynowicz
Copy link
Copy Markdown
Member

__pthread_kill_implementation 0x00007fffec4a13bc
__pthread_kill_internal 0x00007fffec4a147f
__GI_raise 0x00007fffec44a942
__GI_abort 0x00007fffec4324ac
QMessageLogger::fatal(char const*, ...) const 0x00007ffff6a92514
qt_assert(const char *, const char *, int) 0x00007ffff6a915ae
VoxelVolume::getVoxelAt RenderablePolyVoxEntityItem.cpp:240
operator() RenderablePolyVoxEntityItem.cpp:894
loop3<…>(const glm::vec<…> &, const glm::vec<…> &, struct {...}) RenderablePolyVoxEntityItem.cpp:153
MarchingCubesSurfaceExtractor::createMesh RenderablePolyVoxEntityItem.cpp:883
operator() RenderablePolyVoxEntityItem.cpp:2064
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
operator() RenderablePolyVoxEntityItem.cpp:2049
QtConcurrent::StoredFunctorCall0::runFunctor(void) qtconcurrentstoredfunctioncall.h:70
QtConcurrent::RunFunctionTask::run qtconcurrentrunbase.h:142
<unknown> 0x00007ffff6ae5f01
<unknown> 0x00007ffff6ae29bd
start_thread 0x00007fffec49f469
__GI___clone3 0x00007fffec51dcf8

@ksuprynowicz
Copy link
Copy Markdown
Member

__pthread_kill_implementation 0x00007fffec4a13bc
__pthread_kill_internal 0x00007fffec4a147f
__GI_raise 0x00007fffec44a942
__GI_abort 0x00007fffec4324ac
QMessageLogger::fatal(char const*, ...) const 0x00007ffff6a92514
qt_assert(const char *, const char *, int) 0x00007ffff6a915ae
VoxelVolume::getVoxelAt RenderablePolyVoxEntityItem.cpp:242
VoxelVolume::raycast RenderablePolyVoxEntityItem.cpp:305
operator() RenderablePolyVoxEntityItem.cpp:1338
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
RenderablePolyVoxEntityItem::findDetailedRayIntersection RenderablePolyVoxEntityItem.cpp:1338
operator() EntityTreeElement.cpp:255
operator() EntityTreeElement.h:163
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
EntityTreeElement::forEachEntity<…> EntityTreeElement.h:161
EntityTreeElement::evalDetailedRayIntersection EntityTreeElement.cpp:199
EntityTreeElement::evalRayIntersection EntityTreeElement.cpp:180
evalRayIntersectionOp EntityTree.cpp:811
std::__invoke_impl<…> invoke.h:63
std::__invoke_r<…> invoke.h:116
std::_Function_handler::_M_invoke std_function.h:292
std::function::operator() std_function.h:593
Octree::recurseElementWithOperationSorted Octree.cpp:108
Octree::recurseTreeWithOperationSorted Octree.cpp:96
operator() EntityTree.cpp:860
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
ReadWriteLockable::withReadLock<…>(struct {...} &&, bool) const ReadWriteLockable.h:124
EntityTree::evalRayIntersection EntityTree.cpp:859
EntityScriptingInterface::evalRayIntersectionWorker EntityScriptingInterface.cpp:1524
EntityScriptingInterface::evalRayIntersectionVector EntityScriptingInterface.cpp:1514
RayPick::getEntityIntersection RayPick.cpp:70
PickCacheOptimizer::update PickCacheOptimizer.h:94
PickManager::update PickManager.cpp:176
Application::update qsharedpointer_impl.h:307
Application::idle Application.cpp:1875
Application::event Application_Events.cpp:103
QApplicationPrivate::notify_helper(QObject *, QEvent *) 0x00007fffed364240
Application::notify Application_Events.cpp:61
QCoreApplication::notifyInternal2(QObject *, QEvent *) 0x00007ffff6ce9f88
QCoreApplicationPrivate::sendPostedEvents(QObject *, int, QThreadData *) 0x00007ffff6ced444
<unknown> 0x00007ffff6d48ba7
<unknown> 0x00007fffed1015ee
<unknown> 0x00007fffed10497f
g_main_context_iteration 0x00007fffed105110
QEventDispatcherGlib::processEvents(QFlags<…>) 0x00007ffff6d481ca
QEventLoop::exec(QFlags<…>) 0x00007ffff6ce88ba
QCoreApplication::exec() 0x00007ffff6cf146f
main main.cpp:850
__libc_start_call_main 0x00007fffec433f75
__libc_start_main_impl 0x00007fffec434027
_start 0x0000555555710c61

@ksuprynowicz
Copy link
Copy Markdown
Member

It looks like it's missing smooth normals:
overte-snap-by-X74hc595-on-2026-03-29_23-25-08
Current master branch:
image

@ksuprynowicz
Copy link
Copy Markdown
Member

__pthread_kill_implementation 0x00007fffec4a13bc
__pthread_kill_internal 0x00007fffec4a147f
__GI_raise 0x00007fffec44a942
__GI_abort 0x00007fffec4324ac
QMessageLogger::fatal(char const*, ...) const 0x00007ffff6a92514
qt_assert(const char *, const char *, int) 0x00007ffff6a915ae
MarchingCubesSurfaceExtractor::createMesh RenderablePolyVoxEntityItem.cpp:984
operator() RenderablePolyVoxEntityItem.cpp:2114
ReadWriteLockable::withReadLock<…>(struct {...} &&) const ReadWriteLockable.h:109
operator() RenderablePolyVoxEntityItem.cpp:2099
QtConcurrent::StoredFunctorCall0::runFunctor(void) qtconcurrentstoredfunctioncall.h:70
QtConcurrent::RunFunctionTask::run qtconcurrentrunbase.h:142
<unknown> 0x00007ffff6ae5f01
<unknown> 0x00007ffff6ae29bd
start_thread 0x00007fffec49f469
__GI___clone3 0x00007fffec51dcf8

@ksuprynowicz
Copy link
Copy Markdown
Member

Works perfectly now :)
I just need to test it with neighboured voxels
overte-snap-by-X74hc595-on-2026-03-30_22-04-36

@ksuprynowicz
Copy link
Copy Markdown
Member

Master branch:
overte-snap-by-X74hc595-on-2026-04-04_20-40-51

2026:
overte-snap-by-X74hc595-on-2026-04-04_20-40-53

@ksuprynowicz
Copy link
Copy Markdown
Member

I tested a bit more and noticed an issue with meshing. Maybe there's different threshold?
Original:
overte-snap-by-X74hc595-on-2026-04-12_11-28-46
overte-snap-by-X74hc595-on-2026-04-12_11-29-29

This PR:
overte-snap-by-X74hc595-on-2026-04-12_11-28-47
overte-snap-by-X74hc595-on-2026-04-12_11-29-31

@RTUnreal
Copy link
Copy Markdown
Collaborator Author

RTUnreal commented Apr 18, 2026

import itertools

def rotr_edge(a):
    assert a in range(12)
    if a == 0: return 1
    elif a == 1: return 2
    elif a == 2: return 3
    elif a == 3: return 0
    elif a == 4: return 5
    elif a == 5: return 6
    elif a == 6: return 7
    elif a == 7: return 4
    elif a == 8: return 9
    elif a == 9: return 10
    elif a == 10: return 11
    elif a == 11: return 8
    assert False

def rotr_vert(a):
    assert a in range(8), f"{a}"
    if a == 0: return 1
    elif a == 1: return 2
    elif a == 2: return 3
    elif a == 3: return 0
    elif a == 4: return 5
    elif a == 5: return 6
    elif a == 6: return 7
    elif a == 7: return 4
    assert False

def mirroru_edge(a):
    assert a in range(12)
    if a == 0: return 4
    elif a == 1: return 5
    elif a == 2: return 6
    elif a == 3: return 7
    elif a == 4: return 0
    elif a == 5: return 1
    elif a == 6: return 2
    elif a == 7: return 3
    elif a == 8: return 8
    elif a == 9: return 9
    elif a == 10: return 10
    elif a == 11: return 11
    assert False

def mirroru_vert(a):
    assert a in range(8)
    if a == 0: return 4
    elif a == 1: return 5
    elif a == 2: return 6
    elif a == 3: return 7
    elif a == 4: return 0
    elif a == 5: return 1
    elif a == 6: return 2
    elif a == 7: return 3
    assert False

def ltoi(l):
    assert all(map(lambda i: i in range(8), l))
    r = 0
    for i in l:
        r = r|(1<<i)
    return r

def itol(v):
    assert v in range(256)
    r = []
    for i in range(8):
        if v&1 != 0:
            r.append(i)
        v = v>>1
    return r

def list_group(v,rot=4,mirror=True):
    out = []
    e = []
    for _ in range(rot):
        out.append(v)
        v,e = apply_trans(rotr_vert, rotr_edge, v, e)
    if mirror:
        v,e = apply_trans(mirroru_vert, mirroru_edge, v, e)
        for _ in range(rot):
            out.append(v)
            v,e = apply_trans(rotr_vert, rotr_edge, v, e)
    return out

RESULTS = [None for _ in range(256)]

def add_res(v, e, expect_dup = False):
    global RESULTS

    assert expect_dup or RESULTS[ltoi(v)] is None
    assert all(map(lambda a: a in range(12), e))

    RESULTS[ltoi(v)] = e + [-1] * (16 - len(e))

def apply_trans(dv, de, v, e):
    return list(map(dv,v)), list(map(de, e))


def repeat_group(v,e,rot=4,mirror=True, expect_dup_mirror=False):
    assert len(e) % 3 == 0
    for _ in range(rot):
        add_res(v,e)
        v,e = apply_trans(rotr_vert, rotr_edge, v, e)

    if mirror:
        v,e = apply_trans(mirroru_vert, mirroru_edge, v, e)
        e = list(itertools.chain.from_iterable(map(lambda t: [t[0],t[2],t[1]], [e[i:i+3] for i in range(0, len(e), 3)])))
        for _ in range(rot):
            add_res(v,e, expect_dup=expect_dup_mirror)
            v,e = apply_trans(rotr_vert, rotr_edge, v, e)


#print(itol(min(map(lambda v:ltoi(v), list_group([0,1,4,5,3,6])))))
#exit(0)

add_res([],[])
add_res(itol(255), [])
repeat_group([0], [0,8,3])
repeat_group([0, 1], [3,1,8, 8,1,9])
repeat_group([0, 4], [3,0,4, 3,4,7], mirror=False)
repeat_group([0, 5], [3,4,8, 3,5,4, 3,0,5, 0,9,5])
repeat_group([0, 6], [0,8,3, 5,6,10], expect_dup_mirror=True)
repeat_group([0, 2], [0,8,1, 1,8,10, 3,10,8, 3,2,10], rot=2)
repeat_group([0, 1, 2], [8,10,9, 3,10,8, 3,2,10])
repeat_group([0, 1, 2, 3], [8,10,9, 8,11,10], rot=1)
repeat_group([0, 1, 4], [3,1,7, 7,9,4, 9,7,1])
repeat_group([0, 2, 4], [10,4,7, 2,10,7, 3,2,7, 10,1,4, 1,0,4])
repeat_group([1, 2, 4], [2,10,7, 7,8,2, 8,0,2, 7,10,9, 4,7,9])
repeat_group([0, 1, 2, 4], [2,10,9, 2,9,7, 2,7,3, 7,9,4])
repeat_group([0, 3, 4], [11,4,7, 11,2,4, 2,0,4])
repeat_group([1, 3, 4], [0,3,8, 2,7,11, 1,9,4, 2,1,7, 7,1,4])
repeat_group([0, 1, 3, 4], [2,7,11, 1,9,4, 2,1,7, 7,1,4])
#repeat_group([0, 1, 6], [3,6,8, 3,10,6, 1,10,3, 6,5,8, 8,5,9])
repeat_group([0, 1, 6], [3,6,8, 3,1,6, 1,10,6, 6,9,8, 6,5,9])
repeat_group([0, 1, 2, 6], [3,9,8, 3,2,9, 2,6,9, 9,6,5])
repeat_group([1, 2, 3, 4], [3,8,0, 11,4,7, 11,9,4, 11,10,9])
repeat_group([0, 1, 2, 3, 4], [11,4,7, 11,9,4, 11,10,9])
repeat_group([0, 1, 4, 5], [3,5,7, 3,1,5], mirror=False)
repeat_group([0, 2, 4, 5], [0,9,1, 3,5,7, 3,2,5, 2,10,5])
#repeat_group([1, 2, 4, 5], [0,7,8, 2,10,5, 0,5,7, 5,0,2])
repeat_group([1, 2, 4, 5], [2,10,0, 0,10,8, 8,10,7, 7,10,5])
repeat_group([0, 1, 2, 4, 5], [3,5,7, 3,10,5, 3,2,10])
repeat_group([1, 3, 4, 5], [3,8,0, 7,11,2, 2,1,7, 1,5,7])
repeat_group([0, 1, 3, 4, 5], [1,5,7, 11,2,7, 7,2,1])
repeat_group([2, 3, 4, 5], [7,11,5, 5,11,10, 3,8,1, 1,8,9], mirror=False)
repeat_group([0, 1, 3, 5, 6], [8,11,4, 4,11,6, 1,10,2])
repeat_group([1, 2, 3, 4, 5], [3,8,0, 11,5,7, 11,10,5])
repeat_group([0, 1, 2, 3, 4, 5], [11,5,7, 11,10,5])
repeat_group([0, 2, 4, 6], [3,6,7, 3,2,6, 1,0,4, 1,4,5], rot=2, mirror=False)
repeat_group([0, 1, 2, 4, 6], [9,4,5, 3,6,7, 3,2,6])
repeat_group([1, 3, 4, 6], [3,8,0, 2,1,10, 11,6,7, 9,4,5], rot=2, mirror=False)
repeat_group([0, 1, 3, 4, 6], [1,10,2, 9,4,5, 11,6,7])
repeat_group([0, 1, 2, 3, 4, 6], [11,6,7, 9,4,5], rot=2)
repeat_group([0, 1, 2, 4, 5, 6], [3,6,7, 3,2,6], mirror=False)
#repeat_group([0, 1, 3, 4, 5, 6], [11,1,7, 11,2,1, 7,1,10, 7,10,6])
repeat_group([0, 1, 3, 4, 5, 6], [11,6,7, 1,10,2])
repeat_group([0, 2, 3, 4, 5, 6], [11,6,7, 0,9,1], mirror=False)
repeat_group([0, 1, 2, 3, 4, 5, 6], [11,6,7])


done = all(map(lambda x: x is not None, RESULTS))
if done:
    print("{ ", end='')
    for el in RESULTS:
        print("{ ", end='')
        for ii, i in enumerate(el):
              if ii > 0:
                  print(", ", end='')
              print(i, end='')
        print(" },")
    print("}")
else:
    print(RESULTS, sum(map(lambda x: int(x is not None), RESULTS)), done)

    next_none = next((i for i, x in enumerate(RESULTS) if x is None))

    print(next_none, itol(next_none))

If there is an interest, here is the script I used to generate the new table (the commented-out repeat_group calls are my attempt at a table).

@ksuprynowicz
Copy link
Copy Markdown
Member

The newest version works perfectly :)
Normals are also very nice improvement over stable branch:
Original:
overte-snap-by-X74hc595-on-2026-04-18_16-11-31

PR 2026:
overte-snap-by-X74hc595-on-2026-04-18_16-11-33

@ksuprynowicz ksuprynowicz added QA approved This pull request has been successfully tested and removed needs QA This pull request needs to be tested labels Apr 18, 2026
Copy link
Copy Markdown
Member

@ksuprynowicz ksuprynowicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
There's one typo, but all is good otherwise :)

Comment thread libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp Outdated
@ksuprynowicz ksuprynowicz merged commit 0523faf into overte-org:master Apr 18, 2026
5 checks passed
@RTUnreal RTUnreal deleted the remove_polyvox branch April 18, 2026 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs CR This pull request needs to be code reviewed QA approved This pull request has been successfully tested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants