-
Notifications
You must be signed in to change notification settings - Fork 137
Using Inbuilt Datastructures #893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Sorry, for the delay, it took me some time to figure out where to use Vec and VecView. There is another class called Pool, I think since it's using unique_ptrs, we can't replace it with Vec, but I'm not sure, could you @pca006132, help me out with this? |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #893 +/- ##
==========================================
- Coverage 91.84% 87.67% -4.17%
==========================================
Files 37 66 +29
Lines 4976 9448 +4472
Branches 0 1024 +1024
==========================================
+ Hits 4570 8284 +3714
- Misses 406 1164 +758 ☔ View full report in Codecov by Sentry. |
src/manifold/src/quickhull.cpp
Outdated
@@ -32,33 +32,11 @@ double defaultEps() { return 0.0000001; } | |||
ConvexHull QuickHull::getConvexHull(const std::vector<glm::dvec3>& pointCloud, | |||
bool CCW, bool useOriginalIndices, | |||
double epsilon) { | |||
VertexDataSource vertexDataSource(pointCloud); | |||
manifold::Vec<glm::dvec3> vertexDataSource(pointCloud); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elalish I vaguely recall you said we should move the quickhull thing into the manifold
namespace right?
If we move the namespace, we don't need this manifold::
namespace specifier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, will this change the timing? You are copying the points into a Vec
. Should we modify the input pointCloud
to VecView
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elalish I vaguely recall you said we should move the quickhull thing into the
manifold
namespace right?If we move the namespace, we don't need this
manifold::
namespace specifier.
That was regarding removing the namespace for quickhull right? So, should I also wrap the code in namespace manifold?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, will this change the timing? You are copying the points into a
Vec
. Should we modify the inputpointCloud
toVecView
?
I tried modifying the input 'pointCloud' to VecView, but it was showing the error that VecView had a protected constructor. I can try to surpass that though, I'll give it one more try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, optimizedVertexBuffer
is a unique_ptr
so, it won't be compatible with VecView
right?, so when I'm calling
vertices = manifold::VecView<glm::dvec3>(*optimizedVertexBuffer);
it won't work right?
There was a problem hiding this comment.
8000 Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Just change the namespace for quickhull to manifold.
- Can you show me the modification and error message about protected constructor?
optimizedVertexBuffer
is an internal buffer, you wantVec
for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I'll change the namespace
[ 14%] Building CXX object src/manifold/CMakeFiles/manifold.dir/src/manifold.cpp.o
cd /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/build/src/manifold && /usr/bin/c++ -Dmanifold_EXPORTS -I/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/include -I/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/utilities/include -I/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/build/_deps/glm-src -I/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/collider/include -I/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/polygon/include -O3 -DNDEBUG -fPIC -Werror -Wall -Wno-unused -Wno-array-bounds -Wno-stringop-overflow -Wno-alloc-size-larger-than -DMANIFOLD_EXCEPTIONS=1 -Winvalid-pch -include /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/build/src/manifold/CMakeFiles/manifold.dir/cmake_pch.hxx -MD -MT src/manifold/CMakeFiles/manifold.dir/src/manifold.cpp.o -MF CMakeFiles/manifold.dir/src/manifold.cpp.o.d -o CMakeFiles/manifold.dir/src/manifold.cpp.o -c /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/manifold.cpp
/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/manifold.cpp: In static member function ‘static manifold::Manifold manifold::Manifold::Hull(const std::vector<glm::vec<3, float, glm::packed_highp> >&)’:
/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/manifold.cpp:927:13: error: use of deleted function ‘manifold::QuickHull::QuickHull()’
927 | QuickHull qh;
| ^~
In file included from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/manifold.cpp:23:
/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/quickhull.h:637:7: note: ‘manifold::QuickHull::QuickHull()’ is implicitly deleted because the default definition would be ill-formed:
637 | class QuickHull {
| ^~~~~~~~~
/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/quickhull.h:637:7: error: ‘constexpr manifold::VecView::VecView() [with T = glm::vec<3, double, glm::packed_highp>]’ is protected within this context
In file included from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/utilities/include/vec.h:24,
from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/utilities/include/utils.h:27,
from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/utilities/include/sparse.h:21,
from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/collider/include/collider.h:18,
from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/impl.h:18,
from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/boolean3.h:16,
from /home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/manifold/src/manifold.cpp:19:
/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/src/utilities/include/vec_view.h:109:3: note: declared protected here
109 | VecView() = default;
| ^~~~~~~
make[2]: *** [src/manifold/CMakeFiles/manifold.dir/build.make:208: src/manifold/CMakeFiles/manifold.dir/src/manifold.cpp.o] Error 1
make[2]: Leaving directory '/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/build'
make[1]: *** [CMakeFiles/Makefile2:538: src/manifold/CMakeFiles/manifold.dir/all] Error 2
make[1]: Leaving directory '/home/kushal/gitrepo/GSOC/manfioldAlgov2/manifold/build'
make: *** [Makefile:159: all] Error 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of modification all I'm doing is since we want to make pointCloud VecView, I make some Vec's VecView's for the code to compile (without incorrect function definitions) but this error persists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just looked at it, this QuickHull
class is just something that holds all data in the QuickHull
algorithm. You can move the getConvexHull
functions out into a standalone function, and construct QuickHull
within that function. You should initialize VecView
in the constructor of the QuickHull
class, so we do not have to default-construct the VecView
(which doesn't make sense, you can treat this VecView
as a reference, you should not have null references).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I'll commit the changes I've made to the Mesh structure first and then I'll work on this, to separate the commits
For the pool thing, just change the inner |
So, at just one place it actually uses the erase function call of vector, should I just work around that by manually erasing it by iterating the Vec (since the inbuilt call was O(n) anyway), or should I modify our implementation of Vec to add a erase implementation? [Also, note this won't add a massive overhead, this is only called when the hull algorithm fails to solve a horizon edge] |
Also, regarding the HalfEdge datastructure, since most of the parameters are the same except one, I decided to add the inbuilt structure in the new structure as a variable, but since our HalfEdge structure stores Also, I feel that despite it using almost the same variables, we cannot afford to remove the implementations structure, because it uses functions to disable the edges when not in use [and I think this disabling might be the reason this implementation gives such a good performance in terms of speed]. |
Manual erasing and switching to How does the disabling of edges work? Is it just a marker per edge, or a more complex/efficient structure? If the former, you can probably just add a parallel vector. |
Alright I'll switch to int. |
I don't understand this part, can you elaborate a bit or maybe just show some pseudocode?
Adding erase method to our |
We actually use a similar system - we set a halfedge to |
I'm just using our HalfEdge implementation as a variable inside the HalfEdge implementation of the algortihm:
|
I don't understand why you still need the old halfedge data structure there. The two fields left are a next index (which manifold's halfedge data structure already has) and manifold's halfedge data structure. |
https://github.com/elalish/manifold/blob/e01d31611ed5894094cc89005db89b1ca2f417bf/src/manifold/src/shared.h#L123C1-L132C3 |
oh sorry, I forgot that we assume that the halfedge data structure is for triangular mesh, and the next id is always computable from the current id (using the next function) it is very likely that the halfedge here also has this property. |
Do you mean the |
They disable all three halfedges around the face, so this should not be an issue. |
Ya, but they also change the order of the HalfEdges right? so we would need a next variable (they do so to avoid rearranging everytime as far I understand) |
I see. I think this is fine for now. In the future if we have time we should look at how to avoid those halfedge reordering, so we can directly use as our halfedge data structure. |
Also, I've made the change for the VecView (the error I was having) and Vec for Pool, could you go through them once as well when you have time |
src/manifold/src/quickhull.h
Outdated
if (data.size() == 0) { | ||
return std::unique_ptr<std::vector<size_t>>(new std::vector<size_t>()); | ||
return std::unique_ptr<manifold::Vec<size_t>>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::make_unique<manifold::Vec<size_t>>()
src/manifold/src/quickhull.h
Outdated
new std::vector<glm::dvec3>(*o.optimizedVertexBuffer)); | ||
vertices = VertexDataSource(*optimizedVertexBuffer); | ||
new manifold::Vec<glm::dvec3>(*o.optimizedVertexBuffer)); | ||
vertices = manifold::Vec<glm::dvec3>(*optimizedVertexBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you just use vertices = *optimizedVertexBuffer
?
I've made the changes @elalish and @pca006132 , could you review this once. I will start working on profiling, so that we can plan further. |
The compilation error is probably caused by missing include, instead of conditional compilation. |
src/manifold/src/quickhull.h
Outdated
class ConvexHull { | ||
public: | ||
Vec<Halfedge> halfedges; | ||
std::vector<glm::dvec3> vertices; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found that I forgot to change this to Vec
.
src/manifold/src/quickhull.h
Outdated
std::vector<size_t> horizonEdgesData; | ||
Vec<size_t> newFaceIndices; | ||
Vec<size_t> newHalfedgeIndices; | ||
std::vector<std::unique_ptr<Vec<size_t>>> disabledFacePointVectors; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe reorder this to make std::vector
at the start/end? Just make it a bit more consistent...
src/manifold/src/quickhull.h
Outdated
Vec<size_t> newHalfedgeIndices; | ||
std::vector<std::unique_ptr<Vec<size_t>>> disabledFacePointVectors; | ||
Vec<size_t> visibleFaces; | ||
Vec<size_t> horizonEdgesData; | ||
struct FaceData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and maybe move this struct definition to the start of the outer class.
HalfEdgeMesh getConvexHullAsMesh(const double* vertexData, size_t vertexCount, | ||
bool CCW, double eps = defaultEps()); | ||
// Convex hull of the point cloud as halfEdge vector and vertex vector | ||
ConvexHull getConvexHullAsMesh(const Vec<glm::dvec3>& pointCloud, bool CCW, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Questions: Is it useful to keep CCW here? Can we pass the mesh epsilon from our mesh function?
No need to fix it in this PR, just food for thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the original implementation handled CCW, so I decided to handle it as well, if we don't plan to use CCW in the future, I can go ahead and remove it.
I think we should be able to use the mesh epsilon as well, we can test that in the next PR, and look at the results.
#include <limits> | ||
|
||
namespace manifold { | ||
|
||
double defaultEps() { return 0.0000001; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we change to kTolerance
? After the double precision PR the epsilon will be much smaller though, we should see how this default epsilon affects precision and runtime.
We can do it in a later PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what kTolerance
is here, I will look into it, but it's possible that the epsilon value was chosen to improve speed, we can look into it while assessing speed in the next PR.
|
||
std::unique_ptr<Vec<size_t>> QuickHull::getIndexVectorFromPool() { | ||
auto r = indexVectorPool.get(); | ||
r->resize(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This resize actually causes reallocation, so currently the pool is pretty much useless. We should try and see if this pool actually helps (by implementing an alternative resize function in vec.h
to avoid it from shrinking) or we can remove it all together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway, it seems that the pool magically helps despite this resize will cause reallocation, and changing this resize to something that does not perform reallocation will not help. I guess it is about the size of Face
and allocating empty unique pointers...
Should further investigate later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I had experimented with this as well, changing it seemed to affect the speed negatively, but I wasn't sure as to why. Let's look into it in the next PR as well.
One potential direction for optimization is to look at splitting |
That's an excellent idea, I think I'll just push a final commit making the modifications that you suggested, then we should move to a new PR, where we can start discussing these points related to optimization, because otherwise these two PR's will get mixed up, and we'll loose track of our ideas. So, once this PR get's merged I'll open another PR where I'll add the tracy headers, and then we can look into various optimizations there, does that sound alright? |
I've made the changes that were suggested. I'm also testing this code on the Thingi10K dataset again, just in case we modified something incorrectly leading to bugs. I'll update once it's done. |
Ok, so this comes as a surprise to me, but while testing, this test case file |
So, to clarify it wasn't a timeout, it was a segfault, I apologize for that miscommunication, I've identified that it's occurring in |
Alright, so it's one of d9edae6 or 76d4126 that caused the issue. The former wasn't compiling on my system, but the latter is the first time the file |
Interesting. To start you can call the ismanifold method to check if the halfedge vector is wrong. I am busy these two days so I cannot debug this for now, sorry about that. |
No problem, I had some spare time and tried to understand the code as much as I could, and I noticed that when you're reordering the halfedges, you've assumed that all faces are valid (and there will be no disabled faces, which is not the case). I've added return when the face is disabled or the halfedge is disabled and since the all the faces are not being considered now, I used j from 0 incrementing it by 3 instead of the face_index*3. Good news is that it is working on all cases now, with the same accuracy. |
src/manifold/src/quickhull.cpp
Outdated
// for each halfedge) | ||
for_each(autoPolicy(mesh.halfedges.size()), countAt(0_uz), | ||
countAt(mesh.halfedges.size()), [&](size_t i) { | ||
if (mesh.halfedges[i].pairedHalfedge < 0) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part will not work when run in parallel. You can change the autoPolicy to ExecutionPolicy::Seq for now and optimize that later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I realized I hadn't handled for parallel execution. I've made the changes now.
I've checked it again on the dataset, it's working correctly. I think the PR is ready to merge now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job working together on this! If it's not too onerous, it would be great to include the test object that caught this error in our TEST
set, but let's do that as a follow-on.
Vec<int> faceMap(mesh.faces.size()); | ||
|
||
// reorder halfedges | ||
// Since all faces are not used now (so we should start from 0 and just |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit confusing to read. I think this means 'some faces are disabled and should not go into the halfedge vector'.
if (mesh.halfedges[i].pairedHalfedge < 0) return; | ||
if (mesh.faces[mesh.halfedges[i].face].isDisabled()) return; | ||
if (AtomicAdd(counts[mesh.halfedges[i].face], 1) > 0) return; | ||
int currIndex = AtomicAdd(j, 3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Atomic works here, but typically I would avoid this kind of frequent atomic updates to the same variable as it is quite expensive. If you think about it, the CPU must synchronize all access to this variable, and it is quite frequent. Anyway, just food for thought and I should have actual benchmark data supporting my claim (or the null hypothesis, i.e. atomic add is good enough).
And it is nice that you can figure this out! This is the interesting thing about parallel programming!
// remove unused vertices | ||
for_each(autoPolicy(halfedges.size() / 3), countAt(0_uz), | ||
countAt(halfedges.size() / 3), [&](size_t i) { | ||
AtomicAdd(counts[halfedges[3 * i].startVert], 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Food for thought: maybe atomic set will be better for performance, and we don't need the transform iterator later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find the function for atomic set, could you tell me what to use?
he.endVert = counts[he.endVert]; | ||
}); | ||
// setting face id | ||
for (size_t index = 0; index < halfedges.size(); index++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parallel? and combine with the loop before?
@@ -52,6 +52,7 @@ bool isMeshConvex(manifold::Manifold hullManifold, double epsilon = 0.0000001) { | |||
|
|||
// If any vertex lies on the opposite side of the normal direction | |||
if (distance > epsilon) { | |||
std::cout << distance << std::endl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this?
} < 10000 /td> | ||
} | ||
if (change_flag == 1) | ||
tf.pointsOnPositiveSide->resize(tf.pointsOnPositiveSide->size() - 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use pop_back()
, I forgot to fix this.
@@ -478,6 +478,35 @@ Manifold::Impl::Impl(const Mesh& mesh, const MeshRelationD& relation, | |||
Finish(); | |||
} | |||
|
|||
void Manifold::Impl::Hull(const std::vector<glm::vec3>& vertPos) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw why are we taking std::vector
here? shouldn't we take VecView
?
oops, we can address the comments in the next PR I guess |
oops, sorry @pca006132! Yeah, let's address in the next PR - this discussion is getting too long to keep track of. |
Yeah I agree with @elalish, it's gotten a bit hard to keep track of the conversation. I'll open another PR, where I will add the tracy headers and do some of the changes you suggested, then we can look into it further. |
That's a great idea, it's a testcase where the algorithm disables some faces, so adding that case will ensure we've handled disabling the faces correctly. |
@@ -598,7 +598,6 @@ class Quality { | |||
* @brief Custom Exceptions | |||
* @{ | |||
*/ | |||
#ifdef MANIFOLD_DEBUG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should still keep #ifdef MANIFOLD_EXCEPTIONS
right?, because otherwise std::logic_error and such errors won't be defined (as won't be included).
HalfEdgeMesh getConvexHullAsMesh(const double* vertexData, size_t vertexCount, | ||
bool CCW, double eps = defaultEps()); | ||
// Convex hull of the point cloud as halfEdge vector and vertex vector | ||
ConvexHull getConvexHullAsMesh(const Vec<glm::dvec3>& pointCloud, bool CCW, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the original implementation handled CCW, so I decided to handle it as well, if we don't plan to use CCW in the future, I can go ahead and remove it.
I think we should be able to use the mesh epsilon as well, we can test that in the next PR, and look at the results.
#include <limits> | ||
|
||
namespace manifold { | ||
|
||
double defaultEps() { return 0.0000001; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what kTolerance
is here, I will look into it, but it's possible that the epsilon value was chosen to improve speed, we can look into it while assessing speed in the next PR.
|
||
std::unique_ptr<Vec<size_t>> QuickHull::getIndexVectorFromPool() { | ||
auto r = indexVectorPool.get(); | ||
r->resize(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I had experimented with this as well, changing it seemed to affect the speed negatively, but I wasn't sure as to why. Let's look into it in the next PR as well.
src/manifold/src/quickhull.cpp
Outdated
// for each halfedge) | ||
for_each(autoPolicy(mesh.halfedges.size()), countAt(0_uz), | ||
countAt(mesh.halfedges.size()), [&](size_t i) { | ||
if (mesh.halfedges[i].pairedHalfedge < 0) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I realized I hadn't handled for parallel execution. I've made the changes now.
// remove unused vertices | ||
for_each(autoPolicy(halfedges.size() / 3), countAt(0_uz), | ||
countAt(halfedges.size() / 3), [&](size_t i) { | ||
AtomicAdd(counts[halfedges[3 * i].startVert], 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find the function for atomic set, could you tell me what to use?
Removed VertexDatapool class and used Vec and VecView instead.