c++ - 需要帮助了解如何使用 2D/3D 字形
问题描述
这是我想帮助理解的代码片段
for (i = 0; i < samplesX; i++)
for (j = 0; j < samplesY; j++)
{
newI = DIM * i / samplesX;
newJ = DIM * j / samplesY;
idx = (round(newJ) * DIM) + round(newI);
if (color_dir == 1 && draw_vecs == 1) {
direction_to_color(vx[idx], vy[idx], color_dir);
}
if (color_dir == 1 && draw_vecs == 2) {
direction_to_color(fx[idx], fy[idx], color_dir);
}
else if (color_dir == 2) {
scalar = rho[idx];
set_colormap(scalar, min, max, clampLow, clampHigh);
}
else if (color_dir == 3) {
scalar = sqrt(vx[idx] * vx[idx] + vy[idx] * vy[idx]);
set_colormap(scalar, min, max, clampLow, clampHigh);
}
else if (color_dir == 4) {
scalar = sqrt(fx[idx] * fx[idx] + fy[idx] * fy[idx]);
set_colormap(scalar, min, max, clampLow, clampHigh);
}
/*if (draw_vecs == 1) {
glVertex2f(wn + (fftw_real)newI * wn, hn + (fftw_real)newJ * hn);
glVertex2f((wn + (fftw_real)newI * wn) + vec_scale * vx[idx], (hn + (fftw_real)newJ * hn) + vec_scale * vy[idx]);
}
else if (draw_vecs == 2) {
glVertex2f(wn + (fftw_real)newI * wn, hn + (fftw_real)newJ * hn);
glVertex2f((wn + (fftw_real)newI * wn) + vec_scale * fx[idx], (hn + (fftw_real)newJ * hn) + vec_scale * fy[idx]);
}*/
if (draw_vecs == 1) {
glVertex2f(wn + (fftw_real)i * wn, hn + (fftw_real)j * hn);
glVertex2f((wn + (fftw_real)i * wn) + vec_scale * vx[idx], (hn + (fftw_real)j * hn) + vec_scale * vy[idx]);
}
else if (draw_vecs == 2) {
glVertex2f(wn + (fftw_real)i * wn, hn + (fftw_real)j * hn);
glVertex2f((wn + (fftw_real)i * wn) + vec_scale * fx[idx], (hn + (fftw_real)j * hn) + vec_scale * fy[idx]);
}
}
glEnd();
}
据我所知,目前所做的是显示这些二维线/箭头(刺猬),它们在 2D 中可视化力/速度,如下图所示。
可悲的是,我对线性代数、微积分和计算机图形学的理解一般到此为止,我在剖析这篇文章时遇到了麻烦。
理想情况下,我想了解这一点,也想了解如何获取这个预先存在的代码,并添加可以显示其他两种字形类型的功能,这些字形类型显示矢量和/或标量字段,例如
- 三维圆锥
- 三维椭球
如果我在这里遗漏了什么,请告诉我!
上述代码段中包含的一些变量:
const int DIM = 50; //size of simulation grid
int color_dir = 0; //use direction color-coding or not
float scalar;
int newI, newJ;
float temp;
float vec_scale = 1000; //scaling of hedgehogs
int draw_vecs = 1; //draw the vector field or not
解决方案
你那里的代码片段本来可以写得更简单(也需要一些有根据的猜测一些变量和函数的含义)。
让我们分解一下。
前两行很容易理解,它们是迭代二维数组的标准节
for (i = 0; i < samplesX; i++)
for (j = 0; j < samplesY; j++)
i
并且j
正在运行索引,它将遍历 中的每个离散坐标元组(i,j) ∈ [i, samplesX) × [j, samplesY)
。接下来的两行将 2D 索引重新映射到一个新的值范围,特别是[i, samplesX)×[j, samplesY) → [0, DIM)×[0, DIM)
. 缺少的信息是,什么类型DIM
。它会使它成为某种浮点类型。
newI = DIM * i / samplesX;
newJ = DIM * j / samplesY;
下一行很容易出错。它将newI
andnewJ
转换为一维数组的运行一维索引,由i
和寻址j
。
为什么这是有问题的?因为在转换到 DIM 空间时,信息可能已经丢失。这种信息丢失可能会导致安全漏洞(!),事实上,谷歌Chrome、Android等项目使用的渲染库Skia最近也出现了这种漏洞;这篇文章值得一读:https ://googleprojectzero.blogspot.com/2019/02/the-curious-case-of-convexity-confusion.html
实现这一点的正确方法是让 DIM 为整数并对其执行定点运算,最终截断小数位。但我离题了。下一个块本质上是执行一个穷人的查找表查找。vx``vy
并且fx``fy
是一些扁平的二维数组,通过一维索引访问,并direction_to_color
映射到一个可能调用的值glColor
;可能也是如此set_colormap
。这是对 OpenGL 的不好使用。
i
从和j
到DIM
然后查找的整个重新映射只是纹理查找的糟糕实现。OpenGL 已经有了纹理。只需加载为纹理坐标数组并启用纹理。
最后,对于每个脊椎,进行两次调用glVertex
,一次调用位于网格中心上的起始点(wn, hn)
到偏移位置(wn, hn) + (i, j)
。
我对该代码的判断:完全垃圾!所有这一切都可以更优雅地完成,即使是在 1994 年使用 OpenGL-1.0 时,似乎已经为它编写了代码。如果您想实现自己的向量场图,请不要以此为起点。
如今,我们拥有带着色器的可编程 GPU。可以完成的所有这些操作都是几行着色器代码。
推荐阅读
- c - 如果键相同,则将链接列表添加到 BST
- jquery - jQuery DataTables 不适用于水平滚动
- marklogic - 仅通过传递部分节点名称获取子节点的 XPath
- bash - 如何根据 bash 中的 3 个(或更多)换行符将文本文件拆分为 2 个部分
- wsdl - 在 Sabre GetReservation 文件上运行 wsdl 工具时出错
- python - Celery --pool=threads -- 这是做什么的以及如何正确使用它?
- python - 主线程错误上的 Flask 函数返回无效
- javascript - 如何在另一个 Vue 项目中使用 Vue Web 组件(由 Vue-CLI 3 生成)?
- elasticsearch - uri [/test/] 和方法 [POST] 的 HTTP 方法不正确,允许:[PUT、HEAD、DELETE、GET]
- java - 以编程方式识别 ant 任务是否已完成