我画了一个有10000个顶点(100x100)的三角形网格,它将是一个草地.我使用了gldrawelements().我看了一整天,仍然无法理解如何计算这个法线.每个顶点是否有自己的法线或每个三角形都有自己的法线?有人能指出我正确的方向如何编辑我的代码以合并法线?
struct vertices {
GLfloat x;
GLfloat y;
GLfloat z;
}vertices[10000];
GLuint indices[60000];
/*
99..9999
98..9998
........
01..9901
00..9900
*/
void CreateEnvironment() {
int count=0;
for (float x=0;x<10.0;x+=.1) {
for (float z=0;z<10.0;z+=.1) {
vertices[count].x=x;
vertices[count].y=0;
vertices[count].z=z;
count++;
}
}
count=0;
for (GLuint a=0;a<99;a++){
for (GLuint b=0;b<99;b++){
GLuint v1=(a*100)+b;indices[count]=v1;count++;
GLuint v2=(a*100)+b+1;indices[count]=v2;count++;
GLuint v3=(a*100)+b+100;indices[count]=v3;count++;
}
}
count=30000;
for (GLuint a=0;a<99;a++){
for (GLuint b=0;b<99;b++){
indices[count]=(a*100)+b+100;count++;//9998
indices[count]=(a*100)+b+1;count++;//9899
indices[count]=(a*100)+b+101;count++;//9999
}
}
}
void ShowEnvironment(){
//ground
glPushMatrix();
GLfloat GroundAmbient[]={0.0,0.5,0.0,1.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,GroundAmbient);
glEnableClientState(GL_VERTEX_ARRAY);
glIndexPointer( GL_UNSIGNED_BYTE, 0, indices ); …
Run Code Online (Sandbox Code Playgroud) 我的方法是分别计算平行于轴X和Y的两个切向量.然后计算叉积以找到法向量.
切线向量由两条最近段上的中点交叉的线给出,如下图所示.
我想知道是否有更直接的计算,或者在CPU周期方面更便宜.
正如标题所说,我想通过使用相邻像素的叉积来计算给定深度图像的表面法线.我想使用Opencv并避免使用PCL,但是我并不真正理解这个过程,因为我的知识在这个主题上非常有限.因此,如果有人可以提供一些提示,我将不胜感激.这里要提到的是除了深度图像和相应的rgb图像之外我没有任何其他信息,所以没有K
相机矩阵信息.
因此,假设我们有以下深度图像:
并且我想在相应的点找到具有相应深度值的法向量,如下图所示:
如何使用相邻像素的叉积来做到这一点?我不介意法线是否高度准确.
谢谢.
更新:
好吧,我试图关注@ timday的答案并将他的代码移植到Opencv.使用以下代码:
Mat depth = <my_depth_image> of type CV_32FC1
Mat normals(depth.size(), CV_32FC3);
for(int x = 0; x < depth.rows; ++x)
{
for(int y = 0; y < depth.cols; ++y)
{
float dzdx = (depth.at<float>(x+1, y) - depth.at<float>(x-1, y)) / 2.0;
float dzdy = (depth.at<float>(x, y+1) - depth.at<float>(x, y-1)) / 2.0;
Vec3f d(-dzdx, -dzdy, 1.0f);
Vec3f n = normalize(d);
normals.at<Vec3f>(x, y) = n;
}
}
imshow("depth", depth / 255);
imshow("normals", normals);
Run Code Online (Sandbox Code Playgroud)
我得到正确的结果如下(我不得不更换double …
编辑:你可能想从"编辑3"开始,因为我已经解决了很多这个问题
这是我应用于icosphere的普通立方体贴图的屏幕截图:
我的立方体贴图icosphere的切线是使用以下代码生成的.m_indices
在一个std::vector
索引中std::vector
的顶点m_vertices
.
std::vector<glm::vec3> storedTan(m_vertices.size(),glm::vec3(0,0,0));
// tangents
for(int i = 0; i < m_indices.size(); i+=3)
{
int i1 = m_indices[i];
int i2 = m_indices[i+1];
int i3 = m_indices[i+2];
VertexData v1 = m_vertices[i1];
VertexData v2 = m_vertices[i2];
VertexData v3 = m_vertices[i3];
glm::vec3 p1 = glm::vec3(v1.position[0],v1.position[1],v1.position[2]);
glm::vec3 p2 = glm::vec3(v2.position[0],v2.position[1],v2.position[2]);
glm::vec3 p3 = glm::vec3(v3.position[0],v3.position[1],v3.position[2]);
glm::vec3 t1 = glm::vec3(v1.tcoords[0],v1.tcoords[1],v1.tcoords[2]);
glm::vec3 t2 = glm::vec3(v2.tcoords[0],v2.tcoords[1],v2.tcoords[2]);
glm::vec3 t3 = glm::vec3(v3.tcoords[0],v3.tcoords[1],v3.tcoords[2]);
std::function<glm::vec2(glm::vec3)> get_uv = [=](glm::vec3 STR)
{
float sc, …
Run Code Online (Sandbox Code Playgroud) 我听说我应该使用法线而不是颜色,因为颜色已被弃用.(这是真的吗?)法线与光的反射有关,但我找不到清晰直观的解释.什么是正常的?
我目前正在为Unity3D创建一个地形,专门用于运行应用程序的内存不足的移动设备.允许大小为15.000 x 15.000千米且高度为-1.000米到10.000米的地形,并且它的唯一限制是硬盘上的空间.
现在一切都运行正常,除了不正确地计算不同网格之间的法线(每个网格具有细分级别).这是两张可视化问题的图片:
问题仅发生在从一个细分级别到另一个细分级别的转换上.如果两个网格具有相同的级别,则效果很好.我首先想到在计算法线时我会错过一些面孔,但似乎它们都包含在计算中.
每张脸的正常计算:
Vector3 u = vertices[item.Face1] - vertices[item.Face0];
Vector3 v = vertices[item.Face2] - vertices[item.Face0];
Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
fn.Normalize();
Run Code Online (Sandbox Code Playgroud)
在计算顶点周围的每个面的法线之后,我将所有面法线添加到顶点法线并对其进行标准化.结果显示在图片中,正如您在背景和网格本身中看到的那样,只要没有不同的细分级别,它就可以工作.
/// <summary>
/// This is a static indicies array which contains all indicies
/// for all possible meshes.
/// </summary>
private static readonly Int32[] // Subdivision
[] // All borders
[] …
Run Code Online (Sandbox Code Playgroud) 我想在OpenGL ES 2.0中显示网格模型,它清楚地显示了实际的网格,所以我不希望在每个基元/三角形上有平滑的阴影.我能想到的唯一两个选择是
它必须是这样的吗?为什么我不能简单地阅读原语并且不指定任何法线,并且以某种方式让OpenGL ES 2.0在每张脸上做出平坦的阴影?
我正在尝试导出蒙皮网格.由于某些原因,如果我将一个皮肤簇添加到网格中,FbxSDK会破坏段边缘的法线.没有皮肤,一切看起来都很好.
码:
FbxLayerElementNormal *layerElementNormal = FbxLayerElementNormal::Create(mesh, "");
layerElementNormal->SetMappingMode(FbxLayerElement::eByControlPoint);
layerElementNormal->SetReferenceMode(FbxLayerElement::eDirect);
for (int vertIndex = 0; vertIndex < vertexCount; ++vertIndex)
{
PackedNormal normal = vertices[vertIndex].normal;
double x,y,z;
x = (( (normal.data) & 0xFF) / 127.5f - 1.0f);
y = ((((normal.data) >> 8 ) & 0xFF) / 127.5f - 1.0f);
z = ((((normal.data) >> 16) & 0xFF) / 127.5f - 1.0f);
layerElementNormal->GetDirectArray().Add(FbxVector4(x,-y,z));
}
layer->SetNormals(layerElementNormal);
Run Code Online (Sandbox Code Playgroud)
我尝试了不同的映射mods(例如eByPolygonVertex
)和参考mods,但到目前为止没有任何帮助.如果网格具有皮肤簇,则看起来像法线一样被完全忽略.我评论了上面的代码,皮肤模型看起来像左图上的一个.
我还尝试了不同的3D软件(Maya 2015,Maya 2013和3ds Max 2013)来检查导出的模型,但所有这些都给了我相同的结果.
PS此问题会影响任何蒙皮网格.
编辑 似乎这个问题是FBX管道中的一个错误:Autodesk论坛.为了绕过这个问题,我需要"传输属性".有人能帮忙吗?
我在网上看了很长时间,找不到这个问题的答案。为简单起见,让我们假设我需要完全平滑一组连接面的法线。我想找到一组向量之间的实际几何平分线,忽略重复的法线并保持三角形汤的准确性。基本上,它需要:
我似乎找到的最常见的法线平滑公式是,通过将法线向量相加并除以三来简单地平均它们;例子:
normalize((A + B + C) / 3);
Run Code Online (Sandbox Code Playgroud)
当然除以三是没有用的,这已经代表了人们提出的天真、自以为是的蛮力平均法的氛围;与此有关的问题还在于,即使是三角形汤和平行法线,它也会把时间弄得一团糟。
我似乎发现的另一个评论是保留初始“面”法线,因为它们来自生成它们的常见交叉乘法运算,因为这样它们(有点)相对于三角形的面积加权。在某些情况下,这可能是您想要做的事情,但是我需要纯平分线,因此面积不能影响公式,即使考虑到它,它仍然会被三角汤弄乱。
我看到了一个提到的方法,它说对相邻面之间的角度进行加权,但我似乎无法正确实施该公式 - 要么是那样,要么不是我想要的。然而,这对我来说很难说,因为我找不到一个简洁的解释,而且我的头脑因所有这些浪费的头脑风暴而变得麻木。
有人知道通用公式吗?如果有任何帮助,我正在使用 C++ 和 DirectX11。
编辑:这里有一些类似的问题,描述了一些方法;
还有这篇文章:http : //www.bytehazard.com/articles/vertnorm.html
不幸的是,我尝试的实现不起作用,我找不到关于哪个公式实际上是我需要的一个清晰、简洁的声明。经过反复试验,我终于发现按角度加权是正确的方法,只是我无法正确实现它;因为它现在似乎正在工作,所以我将在下面添加我的实现作为答案。
许多映射技术(包括法线凹凸贴图,视差贴图等)都需要特殊的每顶点切线空间(切线,法线,副法线/比特).
这显然意味着,我的模型不仅要出口的顶点位置,纹理坐标和每个顶点的法线近似,而且切空间的基向量(通常是一个tangent
),因为另外一个可以直接在着色器中使用cross(tangent, normal)
.
请注意,position,normal,uv和tangents实际上是以下列方式相互依赖的(您必须知道关于顶点的所有其他内容以准备切线基础).
position -> normal -> tangents
uv ->
Run Code Online (Sandbox Code Playgroud)
现在 - 在现代3D游戏/渲染引擎中如何处理这类事情?
它们实际上是为每个顶点提供法线,切线和uv坐标还是可以在运行时以某种方式计算它们?它们应该是模型数据的一部分还是应该是仅运行时属性?
我也知道,当使用Direct3D10+
几何着色器时,实际上可以在运行时准备法线和切线(显然,因为我们可以访问每个三角形中的顶点) - 是否值得或者这些东西是否应该总是预先计算?