无法将法线添加到.obj网格

安东尼

我已经在Blender中创建了一个形状(已经确保对三角剖分并添加了法线),并已将其导出为.obj格式以在openframeworks项目中使用。我还编写了一个小类来解析此.obj文件。形状绘制得很完美,但是我似乎无法正确使用法线。

导出仅包含顶点,法线和面。如.obj格式所指示:我将顶点添加到网格中,并使用提供的索引绘制面。法线和法线索引以类似的方式提供。由下图所示,我没有正确应用它们。

在此处输入图片说明

这是我的模型加载器脚本:

modelLoader.h

#ifndef _WAVEFRONTLOADER
#define _WAVEFRONTLOADER

#include "ofMain.h"

class waveFrontLoader {

public:

ofMesh mesh;

waveFrontLoader();
~waveFrontLoader();

void loadFile(char *fileName);
ofMesh generateMesh();

private:

typedef struct
{
    ofIndexType v1,v2,v3;
    ofIndexType vn1,vn2,vn3;
}
Index;

std::vector<ofVec3f> vertices;
std::vector<ofVec3f> normals;
std::vector<Index> indices;

void parseLine(char *line);
void parseVertex(char *line);
void parseNormal(char *line);
void parseFace(char *line);
};

#endif

modelLoader.cpp

#include "waveFrontLoader.h"

waveFrontLoader::waveFrontLoader()
{

}

void waveFrontLoader::loadFile(char *fileName)
{
ifstream file;
char line[255];

//open file in openframeworks data folder
file.open(ofToDataPath(fileName).c_str());

if (file.is_open())
{
    while (file.getline(line,255))
    {
        parseLine(line);
    }
}
}

void waveFrontLoader::parseLine(char *line)
{
//If empty, don't do anything with it
if(!strlen(line))
{
    return;
}

//get line type identifier from char string
char *lineType = strtok(strdup(line), " ");

//parse line depending on type
if (!strcmp(lineType, "v")) // Vertices
{
    parseVertex(line);
}
else if (!strcmp(lineType, "vn")) // Normals
{
    parseNormal(line);
}
else if (!strcmp(lineType, "f")) // Indices (Faces)
{
    parseFace(line);
}
}

void waveFrontLoader::parseVertex(char *line)
{
float x;
float y;
float z;

vertices.push_back(ofVec3f(x,y,z));

//get coordinates from vertex line and assign
sscanf(line, "v %f %f %f", &vertices.back().x, &vertices.back().y, &vertices.back().z);
}

void waveFrontLoader::parseNormal(char *line)
{
float x;
float y;
float z;

normals.push_back(ofVec3f(x,y,z));

//get coordinates from normal line and assign
sscanf(line, "vn %f %f %f", &normals.back().x, &normals.back().y, &normals.back().z);
}

void waveFrontLoader::parseFace(char *line)
{
indices.push_back(Index());

//get vertex and normal indices
sscanf(line, "f %d//%d %d//%d %d//%d",
       &indices.back().v1,
       &indices.back().vn1,
       &indices.back().v2,
       &indices.back().vn2,
       &indices.back().v3,
       &indices.back().vn3);
}

ofMesh waveFrontLoader::generateMesh()
{
//add vertices to mesh
for (std::vector<ofVec3f>::iterator i = vertices.begin(); i != vertices.end(); ++i)
{
    mesh.addVertex(*i);
}

//add indices to mesh
for (std::vector<Index>::iterator i = indices.begin(); i != indices.end(); ++i)
{
    // -1 to count from 0
    mesh.addIndex((i->v1) - 1);
    mesh.addIndex((i->v2) - 1);
    mesh.addIndex((i->v3) - 1);

    mesh.addNormal(normals[(i->vn1) - 1]);
    mesh.addNormal(normals[(i->vn2) - 1]);
    mesh.addNormal(normals[(i->vn3) - 1]);

}

return mesh;
}

waveFrontLoader::~waveFrontLoader()
{

}

我也尝试过添加这样的法线(这很有意义,因为它是每张脸的一个法线):

mesh.addNormal(normals[(i->vn1) - 1]);

我还尝试了每绘制两个三角形仅添加一次法线,并尝试在索引之前添加索引和法线。这些都不起作用。

testApp.h

#pragma once

#include "ofMain.h"
#include "waveFrontLoader.h"

class testApp : public ofBaseApp{

public:
    void setup();
    void update();
    void draw();
    void exit();

    waveFrontLoader *objectLoader;
    ofMesh mesh;
    ofEasyCam camera;
    ofLight light;
};

testApp.cpp

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);

ofBackground(10, 10, 10);

camera.setDistance(10);
light.setPosition(10,30,-25);

objectLoader = new waveFrontLoader();
objectLoader->loadFile("test.obj");
mesh = objectLoader->generateMesh();
}

//--------------------------------------------------------------
void testApp::update()
{

}

//--------------------------------------------------------------
void testApp::draw()
{
camera.begin();
light.enable();
mesh.draw();
light.disable();
camera.end();
}

void testApp::exit()
{
delete objectLoader;
}
克比克

我认为这可能是索引错误,因为您的位置索引和常规数组不对应。通常,在使用OpenGL创建顶点缓冲区时,所有顶点属性(位置,法线,texcoord等)数组的长度必须相同。因此,当三角形定义为索引[0,1,2]时,它将使用位置[v0,v1,v2]和法线[n0,n1,n2]。

让我们以一个多维数据集为例来查看代码中发生的事情。

多维数据集.obj文件将包含:

- 8 positions, lets call them v0 to v7
- 6 normals, lets call them n0 to n5
- 12 faces/triangles of format v//n v//n v//n, called f0 to f11

在您的generateMesh()代码中,您将提交以下内容的顶点数组:

[ v0, v1, v2, v3, v4, v5, v6, v7 ] // length of 8

索引数组:

[ f0.a, f0.b, f0.c, .... f11.a, f11.b, f11.c ] // length of 36

和一个普通的数组

[ n0, n0, n0, n0, n0, n0, n1, n1, n1, ... n5, n5, n5 ] // length of 36.

在此示例中,三角形索引值的位置范围为[0到7],法线的范围为[0到5]。这适用于您提交的顶点,但是您提交的法线的范围是[0到31]。

尝试使用以下代码生成ofMesh,该代码将统一的顶点数组与相应的顶点和法线索引组装在一起:

ofMesh waveFrontLoader::generateMesh()
{
    int indexCount = 0;
    for (std::vector<Index>::iterator i = indices.begin(); i != indices.end(); ++i)
    {
        // add face of positions, -1 to count from 0
        mesh.addVertex(vertices[(i->v1) - 1]);
        mesh.addVertex(vertices[(i->v2) - 1]);
        mesh.addVertex(vertices[(i->v3) - 1]);

        // add face of normals, -1 to count from 0
        mesh.addNormal(normals[(i->vn1) - 1]);
        mesh.addNormal(normals[(i->vn2) - 1]);
        mesh.addNormal(normals[(i->vn3) - 1]);

        // in this code we are defining our vertex arrays 
        // according to the indices, so they will always
        // be [0 to n]
        mesh.addIndex( indexCount++ );
        mesh.addIndex( indexCount++ );
        mesh.addIndex( indexCount++ );   
    }
}

现在很明显,此函数不会导致数组的大小最小(在多维数据集示例中,数组中有32个顶点,但其中只有24个具有唯一的位置/法线对),但是可以进行快速测试以查看是否为引起问题。

一种更复杂的方法是使用std :: map或std :: set来检查position + normal + etc组合是否已存在,并使用这些现有索引而不是向数组添加冗余数据。在多维数据集示例中,这将导致前两个面是使用4个顶点的索引[0、1、2、1、2、3],而不是使用6个顶点的索引[0、1、2、3、4、5],

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

无法将网格添加到extjs中的div

来自分类Dev

将边缘添加到Openmesh网格

来自分类Dev

将圆角添加到网格

来自分类Dev

将行添加到网格视图

来自分类Dev

将网格添加到ItemsControl的ItemsPanelTemplate

来自分类Dev

将圆角添加到网格

来自分类Dev

将按钮网格添加到 JPanel

来自分类Dev

将网格标题添加到Android网格卡

来自分类Dev

ExtJS 6.2无法将插件添加到内部网格-TypeError:视图未定义

来自分类Dev

三.js | 无法将动态文本几何体添加到 3d 网格

来自分类Dev

如何将.obj模型添加到JME

来自分类Dev

如何将.obj模型添加到JME

来自分类Dev

将递增 ID 添加到数组中的 obj

来自分类Dev

将事件添加到简单网格的行

来自分类Dev

将垂直滚动条添加到WPF网格

来自分类Dev

动态将行/列添加到网格

来自分类Dev

如何将类添加到剑道网格表头?

来自分类Dev

Ext.js将列添加到属性网格

来自分类Dev

将视图或按钮链接添加到Kendo网格

来自分类Dev

javafx将按钮添加到网格窗格

来自分类Dev

将网格添加到R中的“ ecdfplot”

来自分类Dev

如何将滚动条添加到网格

来自分类Dev

动态将行添加到extjs中的网格

来自分类Dev

可以将记录计数添加到分页网格吗?

来自分类Dev

将列线添加到CSS网格系统

来自分类Dev

动态将行添加到ListView中的网格

来自分类Dev

如何将新列添加到Bootstrap网格?

来自分类Dev

将排序功能添加到动态创建的网格

来自分类Dev

以编程方式将DataTemplate添加到网格