diff --git a/.gitignore b/.gitignore index 4dc7097..6f9694f 100644 --- a/.gitignore +++ b/.gitignore @@ -68,12 +68,4 @@ build */shader_ans.vert */shader_ans.frag -!assets/armadillo1.obj -!assets/bunny.obj -!assets/rb1.obj -!assets/rb2.obj -!assets/rb3.obj -!assets/rb4.obj - -task09/cppmodule.cbp -task00 \ No newline at end of file +!assets/* \ No newline at end of file diff --git a/src/util_opengl.h b/src/util_opengl.h new file mode 100644 index 0000000..7e98fa9 --- /dev/null +++ b/src/util_opengl.h @@ -0,0 +1,84 @@ +// +// Created by Nobuyuki Umetani on 2024/04/02. +// + +#ifndef UTIL_OPENGL_H_ +#define UTIL_OPENGL_H_ + +#include +#include + +namespace acg { + +std::string load_file_as_string( + const std::string &fname) { + std::ifstream inputFile1(fname.c_str()); + std::istreambuf_iterator vdataBegin(inputFile1); + std::istreambuf_iterator vdataEnd; + return {vdataBegin, vdataEnd}; +} + +int compile_shader( + const std::string &str_glsl_vert, + int shaderType) { + int id_shader = glCreateShader(shaderType); + const char *vfile = str_glsl_vert.c_str(); + glShaderSource(id_shader, 1, &vfile, nullptr); + glCompileShader(id_shader); // compile the code + + { // print if failed + GLint res; + glGetShaderiv(id_shader, GL_COMPILE_STATUS, &res); + if (res == GL_FALSE) { + if (shaderType == GL_VERTEX_SHADER) { + std::cout << "compile vertex shader failed" << std::endl; + } else if (shaderType == GL_FRAGMENT_SHADER) { + std::cout << "compile fragment shader failed" << std::endl; + } + } + } + { // show log + const GLsizei maxLength = 1024; + GLsizei length; + auto *infoLog = new GLchar[maxLength]; + glGetShaderInfoLog(id_shader, maxLength, &length, infoLog); + std::cout << "log: " << infoLog << std::endl; + delete[] infoLog; + } + return id_shader; +} + +int create_shader_program( + const std::string &str_glsl_vert, + const std::string &str_glsl_frag) { + int vShaderId = compile_shader(str_glsl_vert, GL_VERTEX_SHADER); + int fShaderId = compile_shader(str_glsl_frag, GL_FRAGMENT_SHADER); + + int id_program = glCreateProgram(); + glAttachShader(id_program, vShaderId); + glAttachShader(id_program, fShaderId); + + GLint linked; + glLinkProgram(id_program); + glGetProgramiv(id_program, GL_LINK_STATUS, &linked); + if (linked == GL_FALSE) { + std::cerr << "Link Err.\n"; + GLint maxLength = 0; + glGetProgramiv(id_program, GL_INFO_LOG_LENGTH, &maxLength); + // The maxLength includes the NULL character + std::vector infoLog(maxLength); + glGetProgramInfoLog(id_program, maxLength, &maxLength, &infoLog[0]); + for (char i: infoLog) { + std::cout << i; + } + std::cout << std::endl; + glDeleteProgram(id_program); // The program is useless now. So delete it. + return 0; + } + return id_program; +} + + +} // acg + +#endif //UTIL_OPENGL_H_ diff --git a/src/util_triangle_mesh.h b/src/util_triangle_mesh.h new file mode 100644 index 0000000..14c5922 --- /dev/null +++ b/src/util_triangle_mesh.h @@ -0,0 +1,120 @@ +// +// Created by Nobuyuki Umetani on 2024/03/12. +// + +#ifndef READ_OBJ_FILE_H_ +#define READ_OBJ_FILE_H_ + +#include +#include +#include +#include +#include +// +#include "Eigen/Dense" + +namespace acg { + +auto read_wavefrontobj_as_3d_triangle_mesh( + const std::filesystem::path &file_path) +-> std::tuple, Eigen::Matrix3Xf> { + using myMatrix3Xui = Eigen::Matrix; + std::ifstream fin; + fin.open(file_path); + if (fin.fail()) { + std::cout << "File Read Fail" << std::endl; + Eigen::Matrix b; + Eigen::Matrix3Xf a; + return std::make_tuple(b, a); + } + std::vector vtx2xyz; + std::vector tri2vtx; + constexpr unsigned int BUFF_SIZE = 256; + char buff[BUFF_SIZE]; + while (fin.getline(buff, BUFF_SIZE)) { + if (buff[0] == '#') { continue; } + if (buff[0] == 'v' && buff[1] == ' ') { + char str[256]; + float x, y, z; + std::istringstream is(buff); + is >> str >> x >> y >> z; + vtx2xyz.push_back(x); + vtx2xyz.push_back(y); + vtx2xyz.push_back(z); + } + if (buff[0] == 'f') { + std::vector vec_str; + { + std::istringstream iss(buff); + std::string s; + bool is_init = true; + while (iss >> s) { + if (is_init) { + is_init = false; + continue; + } + vec_str.push_back(s); + } + } + std::vector aI; + aI.reserve(4); + for (auto str: vec_str) { + for (char &i: str) { + if (i == '/') { + i = '\0'; + break; + } + } + int i0 = std::stoi(str); + aI.push_back(i0 - 1); + } + if (aI.size() == 3) { + tri2vtx.push_back(aI[0]); + tri2vtx.push_back(aI[1]); + tri2vtx.push_back(aI[2]); + } + if (aI.size() == 4) { + tri2vtx.push_back(aI[0]); + tri2vtx.push_back(aI[1]); + tri2vtx.push_back(aI[2]); + // + tri2vtx.push_back(aI[0]); + tri2vtx.push_back(aI[2]); + tri2vtx.push_back(aI[3]); + } + } + } + Eigen::Matrix3Xf a = Eigen::Map(vtx2xyz.data(), 3, vtx2xyz.size() / 3); + myMatrix3Xui b = Eigen::Map(tri2vtx.data(), 3, tri2vtx.size() / 3); + return std::make_tuple(b, a); +} + +auto vertex_normals_of_triangle_mesh( + const Eigen::Matrix &tri2vtx, + const Eigen::Matrix3Xf &vtx2xyz) -> Eigen::Matrix3Xf { + const auto num_vtx = vtx2xyz.size() / 3; + auto vtx2normal = std::vector(num_vtx * 3, 0.f); + for (unsigned int i_tri = 0; i_tri < tri2vtx.cols(); ++i_tri) { + const unsigned int i0 = tri2vtx(0, i_tri); + const unsigned int i1 = tri2vtx(1, i_tri); + const unsigned int i2 = tri2vtx(2, i_tri); + auto p0 = vtx2xyz.col(i0); + auto p1 = vtx2xyz.col(i1); + auto p2 = vtx2xyz.col(i2); + Eigen::Vector3f un = (p1 - p0).cross(p2 - p0).normalized(); + for (int i_dim = 0; i_dim < 3; ++i_dim) { + vtx2normal[i0 * 3 + i_dim] += un[i_dim]; + vtx2normal[i1 * 3 + i_dim] += un[i_dim]; + vtx2normal[i2 * 3 + i_dim] += un[i_dim]; + } + } + for (int i_vtx=0;i_vtx(vtx2normal.data() + i_vtx*3); + n.normalize(); + } + return Eigen::Map(vtx2normal.data(), 3, num_vtx); +} + +} // namespace acg + +#endif //READ_OBJ_FILE_H_