Я создал форму в 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;
}