diff --git a/samples/distancefield/DistanceFieldApp.cc b/samples/distancefield/DistanceFieldApp.cc index ab87b8d55731786d4e105d28247ed00bd8f1d48d..7aac68f5c331509e0275aa7810404b40c2560cc5 100644 --- a/samples/distancefield/DistanceFieldApp.cc +++ b/samples/distancefield/DistanceFieldApp.cc @@ -101,13 +101,14 @@ void DistanceFieldApp::init() mGpuTimer = TimerQuery::create(); // bunny + if (!false) { std::ifstream file(util::pathOf(__FILE__) + "/../../data/bunny.obj"); glm::vec3 amin{std::numeric_limits<float>::max()}; glm::vec3 amax{-std::numeric_limits<float>::max()}; std::string line; - std::vector<glm::vec3> pts; + std::vector<glm::vec3> pts; while (std::getline(file, line)) { std::istringstream iss(line); @@ -120,26 +121,28 @@ void DistanceFieldApp::init() glm::vec3 v = {x, y, z}; amin = min(amin, v); amax = max(amax, v); - pts.push_back(v); + pts.push_back(v); } } - auto s = amax - amin; - amin -= s * 0.1f; - amin += s * 0.1f; - auto ms = glm::max(s.x, glm::max(s.y, s.z)); - for (auto v : pts) - { - v = (v - amin) / ms * Size; - v.x += (ms - s.x) / 2.0f; - v.y += (ms - s.y) / 2.0f; - v.z += (ms - s.z) / 2.0f; - mPoints.push_back(glm::vec4(v, 1.0f)); - } + auto s = amax - amin; + amin -= s * 0.1f; + amin += s * 0.1f; + auto ms = glm::max(s.x, glm::max(s.y, s.z)); + for (auto v : pts) + { + v = (v - amin) / ms * Size; + v.x += (ms - s.x) / 2.0f; + v.y += (ms - s.y) / 2.0f; + v.z += (ms - s.z) / 2.0f; + mPoints.push_back(glm::vec4(v, 1.0f)); + } } + // mPoints.push_back(glm::vec4(Size / 2)); + // data - if (false) + if (!!false) { // mPoints.push_back(glm::vec4(Size / 2.0f)); for (auto i = 0; i < 1000; ++i) // DEBUG @@ -170,7 +173,7 @@ void DistanceFieldApp::init() mTexIteration = Texture3D::createStorageImmutable(Size, Size, Size, GL_R32UI, 1); mTexNearestPoint = Texture3D::createStorageImmutable(Size, Size, Size, GL_R32UI, 1); - for (auto const& tex : { mTexIteration, mTexNearestPoint}) + for (auto const& tex : {mTexIteration, mTexNearestPoint}) { auto t = tex->bind(); t.setMinFilter(GL_NEAREST); @@ -214,10 +217,10 @@ void DistanceFieldApp::init() mMarchShader->configureTransformFeedback({"gPosition"}); // tweakbar - TwAddVarRW(tweakbar(), "Crust Size", TW_TYPE_FLOAT, &mCrustSize, "group=algorithm step=0.1"); + TwAddVarRW(tweakbar(), "Crust Size", TW_TYPE_FLOAT, &mCrustSize, "group=algorithm step=0.1"); - TwAddVarRW(tweakbar(), "Cut Y", TW_TYPE_FLOAT, &mCutY, "group=rendering step=0.002"); - TwAddVarRW(tweakbar(), "Y Anim", TW_TYPE_FLOAT, &mYAnim, "group=rendering step=0.002"); + TwAddVarRW(tweakbar(), "Cut Y", TW_TYPE_FLOAT, &mCutY, "group=rendering step=0.002"); + TwAddVarRW(tweakbar(), "Y Anim", TW_TYPE_FLOAT, &mYAnim, "group=rendering step=0.002"); TwAddVarRW(tweakbar(), "Show Slice", TW_TYPE_BOOLCPP, &mShowSlice, "group=rendering"); TwAddVarRW(tweakbar(), "Auto Recalc", TW_TYPE_BOOLCPP, &mRecalcEveryFrame, "group=actions"); @@ -253,16 +256,16 @@ void DistanceFieldApp::recompute() mGpuTimerStart->saveTimestamp(); // clear mClearShader->use().compute(Size / CLEAR_SHADER_SIZE, Size / CLEAR_SHADER_SIZE, Size / CLEAR_SHADER_SIZE); - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - auto nextIteration = 1u; + auto nextIteration = 1u; // init { mFeedbackQuery->begin(); mGpuTimer->begin(); auto shader = mInitShader->use(); - shader.setUniform("uNextIteration", nextIteration++); + shader.setUniform("uNextIteration", nextIteration++); auto vao = mPointVAO->bind(); vao.negotiateBindings(); // must be done before transform feedback @@ -271,20 +274,21 @@ void DistanceFieldApp::recompute() fb.begin(GL_POINTS); vao.draw(); fb.end(); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + mFeedbackQuery->end(); mGpuTimer->end(); auto time = TimerQuery::toSeconds(mGpuTimer->getResult64()); auto pts = mFeedbackQuery->getResult64(); glow::info() << "Seeds: " << pts << " (" << time * 1000 << " ms, " << (time / pts * 1000 * 1000 * 1000) << " ns/pt)"; } - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); // march { auto outputA = false; auto shader = mMarchShader->use(); - shader.setUniform("uCrustSize", mCrustSize); + shader.setUniform("uCrustSize", mCrustSize); mVAOQueueA->bind().negotiateBindings(); // must be done before transform feedback mVAOQueueB->bind().negotiateBindings(); // must be done before transform feedback @@ -300,13 +304,13 @@ void DistanceFieldApp::recompute() } { - shader.setUniform("uNextIteration", nextIteration++); + shader.setUniform("uNextIteration", nextIteration++); auto fb = (outputA ? mFeedbackA : mFeedbackB)->bind(); fb.begin(GL_POINTS); (outputA ? mVAOQueueB : mVAOQueueA)->bind().drawTransformFeedback(outputA ? mFeedbackB : mFeedbackA); fb.end(); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); if (shouldQuery) { @@ -320,8 +324,8 @@ void DistanceFieldApp::recompute() shouldQuery = true; auto pts = mFeedbackQuery->getResult64(); auto time = TimerQuery::toSeconds(mGpuTimer->getResult64()); - glow::info() << "Got " << pts << " indices at iteration " << nextIteration << " (" << time * 1000 << " ms, " - << (time / pts * 1000 * 1000 * 1000) << " ns/pt)"; + glow::info() << "Got " << pts << " indices at iteration " << nextIteration << " (" << time * 1000 + << " ms, " << (time / pts * 1000 * 1000 * 1000) << " ns/pt)"; forceSync = maxSync; (void)forceSync; @@ -332,8 +336,11 @@ void DistanceFieldApp::recompute() outputA = !outputA; - if (nextIteration > Size * 4) - break; // DEBUG + if (nextIteration > Size * 4) + { + glow::error() << "Too many iterations, aborting."; + break; // DEBUG + } } } mGpuTimerEnd->saveTimestamp(); @@ -353,7 +360,7 @@ void DistanceFieldApp::update(float elapsedSeconds) // IMPORTANT: call base function glfw::GlfwApp::update(elapsedSeconds); - mCutY += mYAnim * elapsedSeconds; + mCutY += mYAnim * elapsedSeconds; } void DistanceFieldApp::renderPass(const glow::pipeline::RenderPass& pass, float elapsedSeconds) @@ -375,8 +382,8 @@ void DistanceFieldApp::renderPass(const glow::pipeline::RenderPass& pass, float auto shader = mSliceShader->use(); shader.setUniform("uCutY", mCutY); - shader.setUniform("uCrustSize", mCrustSize); - shader.setUniform("uView", cam->getViewMatrix()); + shader.setUniform("uCrustSize", mCrustSize); + shader.setUniform("uView", cam->getViewMatrix()); shader.setUniform("uProj", cam->getProjectionMatrix()); mQuadVAO->bind().draw(); diff --git a/samples/distancefield/gs-header.glsl b/samples/distancefield/gs-header.glsl index 236fcbf6fc02b8bae83e2c3e94a2dfb69b8859c9..e995e816e761dddcdb687b56585206240eb515d5 100644 --- a/samples/distancefield/gs-header.glsl +++ b/samples/distancefield/gs-header.glsl @@ -10,6 +10,18 @@ void notifyNeighbor(int x, int y, int z, int w, int h) EmitVertex(); } +void notifyNeighbor(ivec3 ip, ivec3 is) +{ + if (any(lessThan(ip, ivec3(0))) || any(greaterThanEqual(ip, is))) + return; // out of bounds + + if (imageAtomicMax(uTexIteration, ip, uNextIteration) == uNextIteration) + return; // already emitted + + gPosition = (ip.z * is.y + ip.y) * is.x + ip.x; + EmitVertex(); +} + void notifyNeighbors(ivec3 ip) { ivec3 is = imageSize(uTexNearestPoint); diff --git a/samples/distancefield/march-shader.gsh b/samples/distancefield/march-shader.gsh index f535b645eb2b2addb21d7b122584babb2e58c60b..aaace3e5f8fd4b053a3612b75eeaaa60d370d3c7 100644 --- a/samples/distancefield/march-shader.gsh +++ b/samples/distancefield/march-shader.gsh @@ -10,7 +10,17 @@ layout(points, max_vertices = 6) out; in uint vPosition[1]; -ivec3 is = imageSize(uTexNearestPoint); +const ivec3 is = imageSize(uTexNearestPoint); +const float maxDistance = is.x + is.y + is.z; + +const ivec3 dirs[6] = ivec3[6]( + ivec3(-1, 0, 0), + ivec3(+1, 0, 0), + ivec3(0, -1, 0), + ivec3(0, +1, 0), + ivec3(0, 0, -1), + ivec3(0, 0, +1) +); void checkNeighbor(ivec3 ip, int dx, int dy, int dz, inout float refDis, inout uint ptIdx) { @@ -40,31 +50,51 @@ void main() idx / (is.x * is.y) ); - //if (imageLoad(uTexDistanceField, ip).r != dis) - // return; // wrong distance - uint ptIdx = imageLoad(uTexNearestPoint, ip).r; uint origIdx = ptIdx; - float dis = is.x + is.y + is.z; + float refDis = maxDistance; + vec3 refP = vec3(0); + + // collect candidates + float nDistances[6]; // initial dis if (origIdx < points.length()) { - vec3 currP = points[ptIdx].xyz; - dis = primitiveDistance(ip, currP); + refP = points[ptIdx].xyz; + refDis = primitiveDistance(ip, refP); } - // check nearest - checkNeighbor(ip, +1, 0, 0, dis, ptIdx); - checkNeighbor(ip, -1, 0, 0, dis, ptIdx); - checkNeighbor(ip, 0, +1, 0, dis, ptIdx); - checkNeighbor(ip, 0, -1, 0, dis, ptIdx); - checkNeighbor(ip, 0, 0, +1, dis, ptIdx); - checkNeighbor(ip, 0, 0, -1, dis, ptIdx); + // check neighbors + for (int i = 0; i < 6; ++i) + { + ivec3 np = ip + dirs[i]; + uint nIdx = imageLoad(uTexNearestPoint, np).x; + + // no change possible + if (nIdx == INVALID_POINT) + { + nDistances[i] = maxDistance; + } + else + { + vec3 nPos = points[nIdx].xyz; + float nDis = primitiveDistance(ip, nPos); // distance to ip! + + nDistances[i] = primitiveDistance(np, nPos); // distance to np! + + if (nDis < refDis) // update + { + refDis = nDis; + refP = nPos; + ptIdx = nIdx; + } + } + } // crust - if (dis > uCrustSize) + if (refDis > uCrustSize) return; // notify neighbors if changed @@ -74,6 +104,14 @@ void main() imageStore(uTexNearestPoint, ip, uvec4(ptIdx)); // notify - notifyNeighbors(ip); + for (int i = 0; i < 6; ++i) + { + ivec3 np = ip + dirs[i]; + + // only if update expected + float newDis = primitiveDistance(np, refP); + if (newDis < nDistances[i]) + notifyNeighbor(np, is); + } } }