Lskyi

@Lskyi

  • 强推,唯一问题就是大二下计算机专业课程安排有点集中,我去年选修选了 ICS 汇编语言 面向对象,然后又包括英语体育数学建模,最后前 8 周平均每周 21 节课(不算周末上机实验的话),有毅力的可以尝试复刻。

    Post #6
  • 看文档我觉得需要格外注意 一条边界 (a boundary)一条边界边 (a boundary edge) 概念的区别,dandelion 中,一条边界上的所有边共享一个 virtual face

    举个例子就是,一个立方体上有一个洞,洞口由 20 条 boundary edge 构成,那么这个洞对应一个 virtual face,而这 20 条边靠近洞一侧的 20 条半边首尾相连成环,都隶属于那一个 virtual face。

    这也说明,一个 boundary halfedge 的 prev 和 next 是相邻的 boundary halfedge。

    你的代码中,boundary halfedge 的 next 和 prev 都成了自身了,这肯定是错的。建议使用 validate() 函数,检查自己操作完还符不符合半边网络数据结构。

    Post #2
  • 打印 122 和 123 之间是多线程程序,这意味着你的错误可能出现在 vertexshader rasterizer phongshader 三个线程中的任意一个线程上。
    建议用 debugger 使用 backtrace 查看调用堆栈排查是哪里出错。
    一个常见可能出错的地在 FragmentProcessor::worker_thread 里有个 framebuffer->set_pixel(index,fragment.depth,fragment.color); 这个需要你确保你输出的片元的 index 控制在合法范围内。

    Post #2 ❤️ 2 likes
  • depth_buffer 初值是 inf,说明这个地方没有任何东西,所以出现 inf 很正常
    其实深度映射集中问题也不大,你可以把光源相机渲染的深度图打出来看看实际是什么样,我的光源相机 far_plane 只设置成了 200.0f,看起来都够用。
    undefined|665x500, 75%
    后面的图看起来有点像 shadow acne 的问题,需要调整 shadow bias,也可以使用根据光源和法线角度(注意法线插值问题)动态调整 bias 算法之类的。此外提高深度图分辨率也可以。
    但最主要是你第一张图 cube 上都看不到 cow 的影子,我觉得你应该先把影子效果做出来再看失真问题。

    Post #2
  • 这处死循环可能是因为你在尝试 collapse 一条已经被 erase 过的边,因为我遇到过。
    具体来说,在你的代码中,一次 collapse_edge(e) 会 erase 包括 e 在内总计 3 条 edge,那如果除了 e 之外,另外两条边也在 selected_edge 里的话,就会出现这个错误。
    此外,这种错误靠 validate() 检查不出来,因为它本身已经不在网格里了。

    Post #2
  • 曲面细分对于 cube 有个整体往回缩的趋势,八个顶点突出考虑是因为旧顶点坐标计算错了往回缩的不够多。可能要看下更新顺序问题?比如要在对每条边分裂之前先计算旧顶点新坐标。
    对于新顶点的计算,如果你是将所有边分裂完之后再用你现在的算法,你应该注意到由于旁边的边已经分裂,在半边网络数据里产生了新顶点,公式里的 v3 和 v4 两个顶点与新顶点已经不邻接,你的 V3addV4 可能变成了相邻的两个新顶点相加,你应该在分裂前就计算。

    Post #2
  • 从 Eigen C5054 警告不难发现你没有升级到 dandelion 1.1.1 版本,dandelion1.1.1 同步更新的 CompilerFlags.cmake 文件对编译选项进行了调整,使得浮点隐式转换为 int 的警告被视为错误。

    Post #3
  • 而且不难发现如果改了 CMakeLists.txt 里的#debug dandelion-ray-debug #optimized dandelion-ray链接库,并且在 utils/ray.cpp 里的 generate_ray 函数在实验中没有正确实现,也会影响结果。

    Post #5 ❤️ 1 like
  • 我反汇编了自己.exe 程序发现了极为类似的代码
    屏幕截图 2024-10-16 003813|690x343, 100%
    不过我在程序运行中还从来没有进入死循环

    但是 考虑到可能是 input_vertices() 速度过快,导致从来没有进入到循环的第一个判断代码块,于是我在 RasterizerRenderer::render()(也就是渲染主线程)中,在拉起 worker 到开始 input 顶点之间,加入了 std::this_thread::sleep_for(std::chrono::seconds(2)); 这确保了 vertex_woker 存在至少一次判空的情况。
    然后复现了你遇到的 bug,程序无响应
    这个数据竞争问题可以说是相当惊人,这么看不上锁情况下对一个队列判空在 O3 下是一个不可接受的操作。

    实际上,我后来发现遇到的问题给队列判空加锁也可以解决,不需要修改头文件,但从这不难看出,在 O3 下使用多线程共享简单变量使用 std::atomic 应该是最佳实践。

    此外,原项目代码给我一种不想频繁上锁(忙等)降低性能的感觉,但这种做法在 O3 下运行似乎不是那么一回事。

    Post #3 ❤️ 2 likes