mirror of
https://github.com/ssloy/tinyraytracer.git
synced 2024-04-18 07:30:54 +08:00
111 lines
2.9 KiB
C++
111 lines
2.9 KiB
C++
#include <iostream>
|
|
#include <cassert>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include "model.h"
|
|
|
|
// fills verts and faces arrays, supposes .obj file to have "f " entries without slashes
|
|
Model::Model(const char *filename) : verts(), faces() {
|
|
std::ifstream in;
|
|
in.open (filename, std::ifstream::in);
|
|
if (in.fail()) {
|
|
std::cerr << "Failed to open " << filename << std::endl;
|
|
return;
|
|
}
|
|
std::string line;
|
|
while (!in.eof()) {
|
|
std::getline(in, line);
|
|
std::istringstream iss(line.c_str());
|
|
char trash;
|
|
if (!line.compare(0, 2, "v ")) {
|
|
iss >> trash;
|
|
Vec3f v;
|
|
for (int i=0;i<3;i++) iss >> v[i];
|
|
verts.push_back(v);
|
|
} else if (!line.compare(0, 2, "f ")) {
|
|
Vec3i f;
|
|
int idx, cnt=0;
|
|
iss >> trash;
|
|
while (iss >> idx) {
|
|
idx--; // in wavefront obj all indices start at 1, not zero
|
|
f[cnt++] = idx;
|
|
}
|
|
if (3==cnt) faces.push_back(f);
|
|
}
|
|
}
|
|
std::cerr << "# v# " << verts.size() << " f# " << faces.size() << std::endl;
|
|
|
|
Vec3f min, max;
|
|
get_bbox(min, max);
|
|
}
|
|
|
|
// Moller and Trumbore
|
|
bool Model::ray_triangle_intersect(const int &fi, const Vec3f &orig, const Vec3f &dir, float &tnear) {
|
|
Vec3f edge1 = point(vert(fi,1)) - point(vert(fi,0));
|
|
Vec3f edge2 = point(vert(fi,2)) - point(vert(fi,0));
|
|
Vec3f pvec = cross(dir, edge2);
|
|
float det = edge1*pvec;
|
|
if (det<1e-5) return false;
|
|
|
|
Vec3f tvec = orig - point(vert(fi,0));
|
|
float u = tvec*pvec;
|
|
if (u < 0 || u > det) return false;
|
|
|
|
Vec3f qvec = cross(tvec, edge1);
|
|
float v = dir*qvec;
|
|
if (v < 0 || u + v > det) return false;
|
|
|
|
tnear = edge2*qvec * (1./det);
|
|
return tnear>1e-5;
|
|
}
|
|
|
|
|
|
int Model::nverts() const {
|
|
return (int)verts.size();
|
|
}
|
|
|
|
int Model::nfaces() const {
|
|
return (int)faces.size();
|
|
}
|
|
|
|
void Model::get_bbox(Vec3f &min, Vec3f &max) {
|
|
min = max = verts[0];
|
|
for (int i=1; i<(int)verts.size(); ++i) {
|
|
for (int j=0; j<3; j++) {
|
|
min[j] = std::min(min[j], verts[i][j]);
|
|
max[j] = std::max(max[j], verts[i][j]);
|
|
}
|
|
}
|
|
std::cerr << "bbox: [" << min << " : " << max << "]" << std::endl;
|
|
}
|
|
|
|
const Vec3f &Model::point(int i) const {
|
|
assert(i>=0 && i<nverts());
|
|
return verts[i];
|
|
}
|
|
|
|
Vec3f &Model::point(int i) {
|
|
assert(i>=0 && i<nverts());
|
|
return verts[i];
|
|
}
|
|
|
|
int Model::vert(int fi, int li) const {
|
|
assert(fi>=0 && fi<nfaces() && li>=0 && li<3);
|
|
return faces[fi][li];
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& out, Model &m) {
|
|
for (int i=0; i<m.nverts(); i++) {
|
|
out << "v " << m.point(i) << std::endl;
|
|
}
|
|
for (int i=0; i<m.nfaces(); i++) {
|
|
out << "f ";
|
|
for (int k=0; k<3; k++) {
|
|
out << (m.vert(i,k)+1) << " ";
|
|
}
|
|
out << std::endl;
|
|
}
|
|
return out;
|
|
}
|
|
|