Format
This commit is contained in:
parent
0a2e37a04d
commit
2100a9c221
8 changed files with 791 additions and 638 deletions
1
assignment-2b/.gitignore
vendored
1
assignment-2b/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/build
|
||||
.DS_Store
|
||||
.cache
|
||||
|
|
8
assignment-2b/CMakeLists.txt
Executable file → Normal file
8
assignment-2b/CMakeLists.txt
Executable file → Normal file
|
@ -4,6 +4,14 @@ cmake_minimum_required (VERSION 3.1)
|
|||
# Create a project called 'HW2b'
|
||||
project(HW2b)
|
||||
|
||||
# Generate the `compile_commands.json` file.
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
|
||||
|
||||
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
|
||||
${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
endif()
|
||||
|
||||
# Find OpenGL, set link library names and include paths
|
||||
find_package(OpenGL REQUIRED)
|
||||
set(OPENGL_LIBRARIES ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY})
|
||||
|
|
1
assignment-2b/compile_commands.json
Symbolic link
1
assignment-2b/compile_commands.json
Symbolic link
|
@ -0,0 +1 @@
|
|||
build/compile_commands.json
|
|
@ -1,12 +1,14 @@
|
|||
// This template code was originally written by Matt Overby while a TA for CSci5607
|
||||
// This template code was originally written by Matt Overby while a TA for
|
||||
// CSci5607
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
// The loaders are included by glfw3 (glcorearb.h) if we are not using glew.
|
||||
#include "glad/glad.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
// Includes
|
||||
#include "trimesh.hpp"
|
||||
#include "shader.hpp"
|
||||
#include "trimesh.hpp"
|
||||
#include <cstring> // memcpy
|
||||
|
||||
// Constants
|
||||
|
@ -15,33 +17,40 @@
|
|||
|
||||
class Mat4x4 {
|
||||
public:
|
||||
|
||||
float m[16];
|
||||
|
||||
// clang-format off
|
||||
Mat4x4(){ // Default: Identity
|
||||
m[0] = 1.f; m[4] = 0.f; m[8] = 0.f; m[12] = 0.f;
|
||||
m[1] = 0.f; m[5] = 1.f; m[9] = 0.f; m[13] = 0.f;
|
||||
m[2] = 0.f; m[6] = 0.f; m[10] = 1.f; m[14] = 0.f;
|
||||
m[3] = 0.f; m[7] = 0.f; m[11] = 0.f; m[15] = 1.f;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
void make_identity(){
|
||||
m[0] = 1.f; m[4] = 0.f; m[8] = 0.f; m[12] = 0.f;
|
||||
m[1] = 0.f; m[5] = 1.f; m[9] = 0.f; m[13] = 0.f;
|
||||
m[2] = 0.f; m[6] = 0.f; m[10] = 1.f; m[14] = 0.f;
|
||||
m[3] = 0.f; m[7] = 0.f; m[11] = 0.f; m[15] = 1.f;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
void print(){
|
||||
std::cout << m[0] << ' ' << m[4] << ' ' << m[8] << ' ' << m[12] << "\n";
|
||||
std::cout << m[1] << ' ' << m[5] << ' ' << m[9] << ' ' << m[13] << "\n";
|
||||
std::cout << m[2] << ' ' << m[6] << ' ' << m[10] << ' ' << m[14] << "\n";
|
||||
std::cout << m[3] << ' ' << m[7] << ' ' << m[11] << ' ' << m[15] << "\n";
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
void make_scale(float x, float y, float z) {
|
||||
make_identity();
|
||||
m[0] = x; m[5] = y; m[10] = z;
|
||||
m[0] = x;
|
||||
m[5] = y;
|
||||
m[10] = z;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,7 +61,6 @@ static inline const Vec3f operator*(const Mat4x4 &m, const Vec3f &v){
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Global state variables
|
||||
//
|
||||
|
@ -67,26 +75,33 @@ namespace Globals {
|
|||
Mat4x4 model; // not used in this assignment; included for completeness only
|
||||
Mat4x4 view;
|
||||
Mat4x4 projection;
|
||||
}
|
||||
|
||||
} // namespace Globals
|
||||
|
||||
//
|
||||
// Callbacks
|
||||
//
|
||||
static void error_callback(int error, const char* description){ fprintf(stderr, "Error: %s\n", description); }
|
||||
static void error_callback(int error, const char *description) {
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
|
||||
static void key_callback(GLFWwindow *window, int key, int scancode, int action,
|
||||
int mods) {
|
||||
// Close on escape or Q
|
||||
if (action == GLFW_PRESS) {
|
||||
switch (key) {
|
||||
case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GL_TRUE); break;
|
||||
case GLFW_KEY_Q: glfwSetWindowShouldClose(window, GL_TRUE); break;
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
case GLFW_KEY_Q:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
// ToDo: update the viewing transformation matrix according to key presses
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void framebuffer_size_callback(GLFWwindow* window, int width, int height){
|
||||
static void framebuffer_size_callback(GLFWwindow *window, int width,
|
||||
int height) {
|
||||
Globals::win_width = float(width);
|
||||
Globals::win_height = float(height);
|
||||
Globals::aspect = Globals::win_width / Globals::win_height;
|
||||
|
@ -94,45 +109,64 @@ static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
|||
glViewport(0, 0, width, height);
|
||||
|
||||
// ToDo: update the perspective matrix as the window size changes
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Function to set up geometry
|
||||
void init_scene();
|
||||
|
||||
|
||||
//
|
||||
// Main
|
||||
//
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// Load the mesh
|
||||
std::stringstream obj_file; obj_file << MY_DATA_DIR << "sibenik/sibenik.obj";
|
||||
if( !Globals::mesh.load_obj( obj_file.str() ) ){ return 0; }
|
||||
std::stringstream obj_file;
|
||||
obj_file << MY_DATA_DIR << "sibenik/sibenik.obj";
|
||||
if (!Globals::mesh.load_obj(obj_file.str())) {
|
||||
return 0;
|
||||
}
|
||||
Globals::mesh.print_details();
|
||||
|
||||
// Forcibly scale the mesh vertices so that the entire model fits within a (-1,1) volume: the code below is a temporary measure that is needed to enable the entire model to be visible in the template app, before the student has defined the proper viewing and projection matrices
|
||||
// This code should eventually be replaced by the use of an appropriate projection matrix
|
||||
// FYI: the model dimensions are: center = (0,0,0); height: 30.6; length: 40.3; width: 17.0
|
||||
// find the extremum of the vertex locations (this approach works because the model is known to be centered; a more complicated method would be required in the general case)
|
||||
// Forcibly scale the mesh vertices so that the entire model fits within a
|
||||
// (-1,1) volume: the code below is a temporary measure that is needed to
|
||||
// enable the entire model to be visible in the template app, before the
|
||||
// student has defined the proper viewing and projection matrices This code
|
||||
// should eventually be replaced by the use of an appropriate projection
|
||||
// matrix FYI: the model dimensions are: center = (0,0,0); height: 30.6;
|
||||
// length: 40.3; width: 17.0
|
||||
// find the extremum of the vertex locations (this approach works because the
|
||||
// model is known to be centered; a more complicated method would be required
|
||||
// in the general case)
|
||||
float min, max, scale;
|
||||
min = Globals::mesh.vertices[0][0]; max = Globals::mesh.vertices[0][0];
|
||||
min = Globals::mesh.vertices[0][0];
|
||||
max = Globals::mesh.vertices[0][0];
|
||||
for (int i = 0; i < Globals::mesh.vertices.size(); ++i) {
|
||||
if (Globals::mesh.vertices[i][0] < min) min = Globals::mesh.vertices[i][0];
|
||||
else if (Globals::mesh.vertices[i][0] > max) max = Globals::mesh.vertices[i][0];
|
||||
if (Globals::mesh.vertices[i][1] < min) min = Globals::mesh.vertices[i][1];
|
||||
else if (Globals::mesh.vertices[i][1] > max) max = Globals::mesh.vertices[i][1];
|
||||
if (Globals::mesh.vertices[i][2] < min) min = Globals::mesh.vertices[i][2];
|
||||
else if (Globals::mesh.vertices[i][2] > max) max = Globals::mesh.vertices[i][2];
|
||||
if (Globals::mesh.vertices[i][0] < min)
|
||||
min = Globals::mesh.vertices[i][0];
|
||||
else if (Globals::mesh.vertices[i][0] > max)
|
||||
max = Globals::mesh.vertices[i][0];
|
||||
if (Globals::mesh.vertices[i][1] < min)
|
||||
min = Globals::mesh.vertices[i][1];
|
||||
else if (Globals::mesh.vertices[i][1] > max)
|
||||
max = Globals::mesh.vertices[i][1];
|
||||
if (Globals::mesh.vertices[i][2] < min)
|
||||
min = Globals::mesh.vertices[i][2];
|
||||
else if (Globals::mesh.vertices[i][2] > max)
|
||||
max = Globals::mesh.vertices[i][2];
|
||||
}
|
||||
// work with positive numbers
|
||||
if (min < 0) min = -min;
|
||||
// scale so that the component that is most different from 0 is mapped to 1 (or -1); all other values will then by definition fall between -1 and 1
|
||||
if (max > min) scale = 1/max; else scale = 1/min;
|
||||
if (min < 0)
|
||||
min = -min;
|
||||
// scale so that the component that is most different from 0 is mapped to 1
|
||||
// (or -1); all other values will then by definition fall between -1 and 1
|
||||
if (max > min)
|
||||
scale = 1 / max;
|
||||
else
|
||||
scale = 1 / min;
|
||||
|
||||
// scale the model vertices by brute force
|
||||
Mat4x4 mscale; mscale.make_scale( scale, scale, scale );
|
||||
Mat4x4 mscale;
|
||||
mscale.make_scale(scale, scale, scale);
|
||||
for (int i = 0; i < Globals::mesh.vertices.size(); ++i) {
|
||||
Globals::mesh.vertices[i] = mscale * Globals::mesh.vertices[i];
|
||||
}
|
||||
|
@ -145,7 +179,9 @@ int main(int argc, char *argv[]){
|
|||
glfwSetErrorCallback(&error_callback);
|
||||
|
||||
// Initialize glfw
|
||||
if( !glfwInit() ){ return EXIT_FAILURE; }
|
||||
if (!glfwInit()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Ask for OpenGL 3.3
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
|
@ -156,8 +192,12 @@ int main(int argc, char *argv[]){
|
|||
// Create the glfw window
|
||||
Globals::win_width = WIN_WIDTH;
|
||||
Globals::win_height = WIN_HEIGHT;
|
||||
window = glfwCreateWindow(int(Globals::win_width), int(Globals::win_height), "HW2b", NULL, NULL);
|
||||
if( !window ){ glfwTerminate(); return EXIT_FAILURE; }
|
||||
window = glfwCreateWindow(int(Globals::win_width), int(Globals::win_height),
|
||||
"HW2b", NULL, NULL);
|
||||
if (!window) {
|
||||
glfwTerminate();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Define callbacks to handle user input and window resizing
|
||||
glfwSetKeyCallback(window, &key_callback);
|
||||
|
@ -178,12 +218,14 @@ int main(int argc, char *argv[]){
|
|||
// MY_SRC_DIR was defined in CMakeLists.txt
|
||||
// it specifies the full path to this project's src/ directory.
|
||||
mcl::Shader shader;
|
||||
std::stringstream ss; ss << MY_SRC_DIR << "shader.";
|
||||
std::stringstream ss;
|
||||
ss << MY_SRC_DIR << "shader.";
|
||||
shader.init_from_files(ss.str() + "vert", ss.str() + "frag");
|
||||
|
||||
// Initialize the scene
|
||||
init_scene();
|
||||
framebuffer_size_callback(window, int(Globals::win_width), int(Globals::win_height));
|
||||
framebuffer_size_callback(window, int(Globals::win_width),
|
||||
int(Globals::win_height));
|
||||
|
||||
// Perform some OpenGL initializations
|
||||
glEnable(GL_DEPTH_TEST); // turn hidden surfce removal on
|
||||
|
@ -203,12 +245,17 @@ int main(int argc, char *argv[]){
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Send updated info to the GPU
|
||||
glUniformMatrix4fv( shader.uniform("model"), 1, GL_FALSE, Globals::model.m ); // model transformation (always the identity matrix in this assignment)
|
||||
glUniformMatrix4fv( shader.uniform("view"), 1, GL_FALSE, Globals::view.m ); // viewing transformation
|
||||
glUniformMatrix4fv( shader.uniform("projection"), 1, GL_FALSE, Globals::projection.m ); // projection matrix
|
||||
glUniformMatrix4fv(shader.uniform("model"), 1, GL_FALSE,
|
||||
Globals::model.m); // model transformation (always the
|
||||
// identity matrix in this assignment)
|
||||
glUniformMatrix4fv(shader.uniform("view"), 1, GL_FALSE,
|
||||
Globals::view.m); // viewing transformation
|
||||
glUniformMatrix4fv(shader.uniform("projection"), 1, GL_FALSE,
|
||||
Globals::projection.m); // projection matrix
|
||||
|
||||
// Draw
|
||||
glDrawElements(GL_TRIANGLES, Globals::mesh.faces.size()*3, GL_UNSIGNED_INT, 0);
|
||||
glDrawElements(GL_TRIANGLES, Globals::mesh.faces.size() * 3,
|
||||
GL_UNSIGNED_INT, 0);
|
||||
|
||||
// Finalize
|
||||
glfwSwapBuffers(window);
|
||||
|
@ -226,7 +273,6 @@ int main(int argc, char *argv[]){
|
|||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void init_scene() {
|
||||
|
||||
using namespace Globals;
|
||||
|
@ -234,25 +280,30 @@ void init_scene(){
|
|||
// Create the buffer for vertices
|
||||
glGenBuffers(1, verts_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, verts_vbo[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size()*sizeof(mesh.vertices[0]), &mesh.vertices[0][0], GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(mesh.vertices[0]),
|
||||
&mesh.vertices[0][0], GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// Create the buffer for colors
|
||||
glGenBuffers(1, colors_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, colors_vbo[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.colors.size()*sizeof(mesh.colors[0]), &mesh.colors[0][0], GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.colors.size() * sizeof(mesh.colors[0]),
|
||||
&mesh.colors[0][0], GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// Create the buffer for normals
|
||||
glGenBuffers(1, normals_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, normals_vbo[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.normals.size()*sizeof(mesh.normals[0]), &mesh.normals[0][0], GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.normals.size() * sizeof(mesh.normals[0]),
|
||||
&mesh.normals[0][0], GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// Create the buffer for indices
|
||||
glGenBuffers(1, faces_ibo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, faces_ibo[0]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.faces.size()*sizeof(mesh.faces[0]), &mesh.faces[0][0], GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
mesh.faces.size() * sizeof(mesh.faces[0]), &mesh.faces[0][0],
|
||||
GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
// Create the VAO
|
||||
|
@ -264,20 +315,21 @@ void init_scene(){
|
|||
// location=0 is the vertex
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, verts_vbo[0]);
|
||||
glVertexAttribPointer(0, vert_dim, GL_FLOAT, GL_FALSE, sizeof(mesh.vertices[0]), 0);
|
||||
glVertexAttribPointer(0, vert_dim, GL_FLOAT, GL_FALSE,
|
||||
sizeof(mesh.vertices[0]), 0);
|
||||
|
||||
// location=1 is the color
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, colors_vbo[0]);
|
||||
glVertexAttribPointer(1, vert_dim, GL_FLOAT, GL_FALSE, sizeof(mesh.colors[0]), 0);
|
||||
glVertexAttribPointer(1, vert_dim, GL_FLOAT, GL_FALSE, sizeof(mesh.colors[0]),
|
||||
0);
|
||||
|
||||
// location=2 is the normal
|
||||
glEnableVertexAttribArray(2);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, normals_vbo[0]);
|
||||
glVertexAttribPointer(2, vert_dim, GL_FLOAT, GL_FALSE, sizeof(mesh.normals[0]), 0);
|
||||
glVertexAttribPointer(2, vert_dim, GL_FLOAT, GL_FALSE,
|
||||
sizeof(mesh.normals[0]), 0);
|
||||
|
||||
// Done setting data for the vao
|
||||
glBindVertexArray(0);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,14 @@ void main(){
|
|||
// normalize the input normal that was interpolated from the mesh vertices
|
||||
vec3 N = normalize(normal);
|
||||
|
||||
// compute a simple diffuse shading weight that is agnostic to the order in which the triangle vertices were specified
|
||||
// compute a simple diffuse shading weight that is agnostic to the order in
|
||||
// which the triangle vertices were specified
|
||||
float N_dot_L = dot(N, L);
|
||||
if ((N_dot_L) < 0.0) { N_dot_L *= -1.0; }
|
||||
if ((N_dot_L) < 0.0) {
|
||||
N_dot_L *= -1.0;
|
||||
}
|
||||
|
||||
// use a simplified ambient+diffuse shading model to define the fragment color
|
||||
vec3 result = ka * color + kd * color * N_dot_L;
|
||||
out_fragcolor = vec4(result, 1.0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
// Copyright 2016 University of Minnesota
|
||||
//
|
||||
// SHADER Uses the BSD 2-Clause License (http://www.opensource.org/licenses/BSD-2-Clause)
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// SHADER Uses the BSD 2-Clause License
|
||||
// (http://www.opensource.org/licenses/BSD-2-Clause) Redistribution and use in
|
||||
// source and binary forms, with or without modification, are permitted provided
|
||||
// that the following conditions are met:
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of
|
||||
// conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF MINNESOTA, DULUTH OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list
|
||||
// of conditions and the following disclaimer in the documentation and/or
|
||||
// other materials provided with the distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// UNIVERSITY OF MINNESOTA, DULUTH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Adapted from r3dux (http://r3dux.org).
|
||||
|
||||
|
@ -55,7 +60,10 @@ public:
|
|||
inline void init_from_files(std::string vertex_file, std::string frag_file);
|
||||
|
||||
// Init the shader from strings (must create OpenGL context first!)
|
||||
inline void init_from_strings( std::string vertex_source, std::string frag_source ){ init(vertex_source, frag_source); }
|
||||
inline void init_from_strings(std::string vertex_source,
|
||||
std::string frag_source) {
|
||||
init(vertex_source, frag_source);
|
||||
}
|
||||
|
||||
// Be sure to initialize the shader before enabling it
|
||||
inline void enable();
|
||||
|
@ -85,7 +93,6 @@ private:
|
|||
|
||||
}; // end of shader
|
||||
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
@ -95,27 +102,33 @@ GLuint Shader::compile( std::string source, GLenum type ){
|
|||
// Generate a shader id
|
||||
// Note: Shader id will be non-zero if successfully created.
|
||||
GLuint shaderId = glCreateShader(type);
|
||||
if( shaderId == 0 ){ throw std::runtime_error("\n**glCreateShader Error"); }
|
||||
if (shaderId == 0) {
|
||||
throw std::runtime_error("\n**glCreateShader Error");
|
||||
}
|
||||
|
||||
// Attach the GLSL source code and compile the shader
|
||||
const char *shaderchar = source.c_str();
|
||||
glShaderSource(shaderId, 1, &shaderchar, NULL);
|
||||
glCompileShader(shaderId);
|
||||
|
||||
// Check the compilation status and throw a runtime_error if shader compilation failed
|
||||
// Check the compilation status and throw a runtime_error if shader
|
||||
// compilation failed
|
||||
GLint shaderStatus;
|
||||
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &shaderStatus);
|
||||
if( shaderStatus == GL_FALSE ){ throw std::runtime_error("\n**glCompileShader Error"); }
|
||||
if (shaderStatus == GL_FALSE) {
|
||||
throw std::runtime_error("\n**glCompileShader Error");
|
||||
}
|
||||
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
|
||||
void Shader::init(std::string vertex_source, std::string frag_source) {
|
||||
|
||||
// Create the resource
|
||||
program_id = glCreateProgram();
|
||||
if( program_id == 0 ){ throw std::runtime_error("\n**glCreateProgram Error"); }
|
||||
if (program_id == 0) {
|
||||
throw std::runtime_error("\n**glCreateProgram Error");
|
||||
}
|
||||
glUseProgram(program_id);
|
||||
|
||||
// Compile the shaders and return their id values
|
||||
|
@ -127,74 +140,91 @@ void Shader::init(std::string vertex_source, std::string frag_source){
|
|||
glAttachShader(program_id, fragment_id);
|
||||
glLinkProgram(program_id);
|
||||
|
||||
// Once the shader program has the shaders attached and linked, the shaders are no longer required.
|
||||
// If the linking failed, then we're going to abort anyway so we still detach the shaders.
|
||||
// Once the shader program has the shaders attached and linked, the shaders
|
||||
// are no longer required. If the linking failed, then we're going to abort
|
||||
// anyway so we still detach the shaders.
|
||||
glDetachShader(program_id, vertex_id);
|
||||
glDetachShader(program_id, fragment_id);
|
||||
|
||||
// Check the program link status and throw a runtime_error if program linkage failed.
|
||||
// Check the program link status and throw a runtime_error if program linkage
|
||||
// failed.
|
||||
GLint programLinkSuccess = GL_FALSE;
|
||||
glGetProgramiv(program_id, GL_LINK_STATUS, &programLinkSuccess);
|
||||
if( programLinkSuccess != GL_TRUE ){ throw std::runtime_error("\n**Shader Error: Problem with link"); }
|
||||
if (programLinkSuccess != GL_TRUE) {
|
||||
throw std::runtime_error("\n**Shader Error: Problem with link");
|
||||
}
|
||||
|
||||
// Check the validation status and throw a runtime_error if program validation failed.
|
||||
// Does NOT work with corearb headers???
|
||||
// Check the validation status and throw a runtime_error if program validation
|
||||
// failed. Does NOT work with corearb headers???
|
||||
// glValidateProgram(program_id);
|
||||
// GLint programValidatationStatus;
|
||||
// glGetProgramiv(program_id, GL_VALIDATE_STATUS, &programValidatationStatus);
|
||||
// if( programValidatationStatus != GL_TRUE ){ throw std::runtime_error("\n**Shader Error: Problem with validation"); }
|
||||
// glGetProgramiv(program_id, GL_VALIDATE_STATUS,
|
||||
//&programValidatationStatus); if( programValidatationStatus != GL_TRUE ){
|
||||
//throw std::runtime_error("\n**Shader Error: Problem with validation"); }
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
||||
void Shader::init_from_files(std::string vertex_file, std::string frag_file) {
|
||||
|
||||
std::string vert_string, frag_string;
|
||||
|
||||
// Load the vertex shader
|
||||
std::ifstream vert_in(vertex_file, std::ios::in | std::ios::binary);
|
||||
if( vert_in ){ vert_string = (std::string((std::istreambuf_iterator<char>(vert_in)), std::istreambuf_iterator<char>())); }
|
||||
else{ throw std::runtime_error("\n**Shader Error: failed to load \""+vertex_file+"\"" ); }
|
||||
if (vert_in) {
|
||||
vert_string = (std::string((std::istreambuf_iterator<char>(vert_in)),
|
||||
std::istreambuf_iterator<char>()));
|
||||
} else {
|
||||
throw std::runtime_error("\n**Shader Error: failed to load \"" +
|
||||
vertex_file + "\"");
|
||||
}
|
||||
|
||||
// Load the fragement shader
|
||||
std::ifstream frag_in(frag_file, std::ios::in | std::ios::binary);
|
||||
if( frag_in ){ frag_string = (std::string((std::istreambuf_iterator<char>(frag_in)), std::istreambuf_iterator<char>())); }
|
||||
else{ throw std::runtime_error("\n**Shader Error: failed to load \""+frag_file+"\"" ); }
|
||||
if (frag_in) {
|
||||
frag_string = (std::string((std::istreambuf_iterator<char>(frag_in)),
|
||||
std::istreambuf_iterator<char>()));
|
||||
} else {
|
||||
throw std::runtime_error("\n**Shader Error: failed to load \"" + frag_file +
|
||||
"\"");
|
||||
}
|
||||
|
||||
init(vert_string, frag_string);
|
||||
}
|
||||
|
||||
|
||||
void Shader::enable() {
|
||||
if( program_id!=0 ){ glUseProgram(program_id); }
|
||||
else{ throw std::runtime_error("\n**Shader Error: Can't enable, not initialized"); }
|
||||
if (program_id != 0) {
|
||||
glUseProgram(program_id);
|
||||
} else {
|
||||
throw std::runtime_error("\n**Shader Error: Can't enable, not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLuint Shader::attribute(const std::string name) {
|
||||
|
||||
// Add the attribute to the map table if it doesn't already exist
|
||||
if (attributes.count(name) == 0) {
|
||||
attributes[name] = glGetAttribLocation(program_id, name.c_str());
|
||||
if( attributes[name] == -1 ){ throw std::runtime_error("\n**Shader Error: bad attribute ("+name+")"); }
|
||||
if (attributes[name] == -1) {
|
||||
throw std::runtime_error("\n**Shader Error: bad attribute (" + name +
|
||||
")");
|
||||
}
|
||||
}
|
||||
return attributes[name];
|
||||
}
|
||||
|
||||
|
||||
GLuint Shader::uniform(const std::string name) {
|
||||
|
||||
// Add the uniform to the map table if it doesn't already exist
|
||||
if (uniforms.count(name) == 0) {
|
||||
uniforms[name] = glGetUniformLocation(program_id, name.c_str());
|
||||
if( uniforms[name] == -1 ){ throw std::runtime_error("\n**Shader Error: bad uniform ("+name+")"); }
|
||||
if (uniforms[name] == -1) {
|
||||
throw std::runtime_error("\n**Shader Error: bad uniform (" + name + ")");
|
||||
}
|
||||
}
|
||||
return uniforms[name];
|
||||
}
|
||||
|
||||
|
||||
} // end namespace mcl
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -12,16 +12,22 @@ uniform mat4 model;
|
|||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
// pass the vertex color and normal information to the fragment shader (without any modification)
|
||||
void main() {
|
||||
// pass the vertex color and normal information to the fragment shader
|
||||
// (without any modification)
|
||||
color = in_color;
|
||||
normal = in_normal;
|
||||
|
||||
// determine what the vertex position will be after the model transformation and pass that information to the fragment shader, for use in the illumination calculations
|
||||
// in our case the model transformation is the identity matrix so this isn't actually necessary, but it's included here for completeness. Note that the vectors needed for the lighting calculations must be computed using the vertex locations *without* perspective warp applied
|
||||
// determine what the vertex position will be after the model transformation
|
||||
// and pass that information to the fragment shader, for use in the
|
||||
// illumination calculations in our case the model transformation is the
|
||||
// identity matrix so this isn't actually necessary, but it's included here
|
||||
// for completeness. Note that the vectors needed for the lighting
|
||||
// calculations must be computed using the vertex locations *without*
|
||||
// perspective warp applied
|
||||
position = vec3(model * in_position);
|
||||
|
||||
// apply the model, view, and projection transformations to the vertex position value that will be sent to the clipper, rasterizer, ...
|
||||
// apply the model, view, and projection transformations to the vertex
|
||||
// position value that will be sent to the clipper, rasterizer, ...
|
||||
gl_Position = (projection * view * model * in_position);
|
||||
}
|
||||
|
|
|
@ -1,31 +1,36 @@
|
|||
// Copyright 2016 University of Minnesota
|
||||
//
|
||||
// TRIMESH Uses the BSD 2-Clause License (http://www.opensource.org/licenses/BSD-2-Clause)
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// TRIMESH Uses the BSD 2-Clause License
|
||||
// (http://www.opensource.org/licenses/BSD-2-Clause) Redistribution and use in
|
||||
// source and binary forms, with or without modification, are permitted provided
|
||||
// that the following conditions are met:
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of
|
||||
// conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF MINNESOTA, DULUTH OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list
|
||||
// of conditions and the following disclaimer in the documentation and/or
|
||||
// other materials provided with the distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// UNIVERSITY OF MINNESOTA, DULUTH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef TRIMESH_HPP
|
||||
#define TRIMESH_HPP 1
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
//
|
||||
// Vector Class
|
||||
|
@ -34,8 +39,16 @@
|
|||
template <size_t D, class T> class Vec {
|
||||
public:
|
||||
// Constructors
|
||||
Vec(){ data[0]=T(0); data[1]=T(0); data[2]=T(0); }
|
||||
Vec(T x_, T y_, T z_){ data[0]=x_; data[1]=y_; data[2]=z_; }
|
||||
Vec() {
|
||||
data[0] = T(0);
|
||||
data[1] = T(0);
|
||||
data[2] = T(0);
|
||||
}
|
||||
Vec(T x_, T y_, T z_) {
|
||||
data[0] = x_;
|
||||
data[1] = y_;
|
||||
data[2] = z_;
|
||||
}
|
||||
|
||||
// Data
|
||||
T data[3];
|
||||
|
@ -44,42 +57,59 @@ public:
|
|||
T operator[](int i) const { return data[i]; }
|
||||
T &operator[](int i) { return data[i]; }
|
||||
Vec<D, T> &operator+=(const Vec<D, T> &x) {
|
||||
for(size_t i=0; i<D; ++i){ data[i] += x[i]; }
|
||||
for (size_t i = 0; i < D; ++i) {
|
||||
data[i] += x[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
double len2() const { return this->dot(*this); } // squared length
|
||||
double len() const { return sqrt(len2()); } // length
|
||||
T dot(const Vec<D, T> &v) const {
|
||||
T r(0);
|
||||
for(size_t i=0; i<D; ++i){ r += v[i] * data[i]; }
|
||||
for (size_t i = 0; i < D; ++i) {
|
||||
r += v[i] * data[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
Vec<3, T> cross(const Vec<3, T> &v) const {
|
||||
assert(D == 3); // only defined for 3 dims
|
||||
return Vec<3,T>(data[1]*v[2] - data[2]*v[1], data[2]*v[0] - data[0]*v[2], data[0]*v[1] - data[1]*v[0]);
|
||||
return Vec<3, T>(data[1] * v[2] - data[2] * v[1],
|
||||
data[2] * v[0] - data[0] * v[2],
|
||||
data[0] * v[1] - data[1] * v[0]);
|
||||
}
|
||||
void normalize() {
|
||||
double l = len(); if( l<=0.0 ){ return; }
|
||||
for(size_t i=0; i<D; ++i){ data[i] = data[i] / l; }
|
||||
double l = len();
|
||||
if (l <= 0.0) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < D; ++i) {
|
||||
data[i] = data[i] / l;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t D, class T> static inline const Vec<D,T> operator-(const Vec<D,T> &v1, const Vec<D,T> &v2){
|
||||
template <size_t D, class T>
|
||||
static inline const Vec<D, T> operator-(const Vec<D, T> &v1,
|
||||
const Vec<D, T> &v2) {
|
||||
Vec<D, T> r;
|
||||
for(size_t i=0; i<D; ++i){ r[i] = v1[i]-v2[i]; }
|
||||
for (size_t i = 0; i < D; ++i) {
|
||||
r[i] = v1[i] - v2[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template <size_t D, class T> static inline const Vec<D,T> operator*(const Vec<D,T> &v, const T &x){
|
||||
template <size_t D, class T>
|
||||
static inline const Vec<D, T> operator*(const Vec<D, T> &v, const T &x) {
|
||||
Vec<D, T> r;
|
||||
for (size_t i=0; i<D; ++i){ r[i] = v[i]*x; }
|
||||
for (size_t i = 0; i < D; ++i) {
|
||||
r[i] = v[i] * x;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef Vec<3, float> Vec3f;
|
||||
typedef Vec<3, int> Vec3i;
|
||||
|
||||
|
||||
//
|
||||
// Triangle Mesh Class
|
||||
//
|
||||
|
@ -105,8 +135,6 @@ public:
|
|||
void print_details();
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
@ -118,13 +146,20 @@ void TriMesh::print_details(){
|
|||
std::cout << "Faces: " << faces.size() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void TriMesh::need_normals(bool recompute) {
|
||||
if( vertices.size() == normals.size() && !recompute ){ return; }
|
||||
if( normals.size() != vertices.size() ){ normals.resize( vertices.size() ); }
|
||||
if (vertices.size() == normals.size() && !recompute) {
|
||||
return;
|
||||
}
|
||||
if (normals.size() != vertices.size()) {
|
||||
normals.resize(vertices.size());
|
||||
}
|
||||
std::cout << "Computing TriMesh normals" << std::endl;
|
||||
const int nv = normals.size();
|
||||
for( int i = 0; i < nv; ++i ){ normals[i][0] = 0.f; normals[i][1] = 0.f; normals[i][2] = 0.f; }
|
||||
for (int i = 0; i < nv; ++i) {
|
||||
normals[i][0] = 0.f;
|
||||
normals[i][1] = 0.f;
|
||||
normals[i][2] = 0.f;
|
||||
}
|
||||
int nf = faces.size();
|
||||
for (int f = 0; f < nf; ++f) {
|
||||
Vec3i face = faces[f];
|
||||
|
@ -133,24 +168,35 @@ void TriMesh::need_normals( bool recompute ){
|
|||
const Vec3f &p2 = vertices[face[2]];
|
||||
Vec3f a = p0 - p1, b = p1 - p2, c = p2 - p0;
|
||||
float l2a = a.len2(), l2b = b.len2(), l2c = c.len2();
|
||||
if (!l2a || !l2b || !l2c){ continue; } // check for zeros or nans
|
||||
if (!l2a || !l2b || !l2c) {
|
||||
continue;
|
||||
} // check for zeros or nans
|
||||
Vec3f facenormal = a.cross(b);
|
||||
normals[faces[f][0]] += facenormal * (1.0f / (l2a * l2c));
|
||||
normals[faces[f][1]] += facenormal * (1.0f / (l2b * l2a));
|
||||
normals[faces[f][2]] += facenormal * (1.0f / (l2c * l2b));
|
||||
}
|
||||
for (int i = 0; i < nv; i++){ normals[i].normalize(); }
|
||||
for (int i = 0; i < nv; i++) {
|
||||
normals[i].normalize();
|
||||
}
|
||||
} // end need normals
|
||||
|
||||
void TriMesh::need_colors(Vec3f default_color) {
|
||||
if( vertices.size() == colors.size() ){ return; }
|
||||
else{ colors.resize( vertices.size(), default_color ); }
|
||||
if (vertices.size() == colors.size()) {
|
||||
return;
|
||||
} else {
|
||||
colors.resize(vertices.size(), default_color);
|
||||
}
|
||||
} // end need colors
|
||||
|
||||
// Function to split a string into multiple strings, seperated by delimeter
|
||||
static void split_str( char delim, const std::string &str, std::vector<std::string> *result ){
|
||||
std::stringstream ss(str); std::string s;
|
||||
while( std::getline(ss, s, delim) ){ result->push_back(s); }
|
||||
static void split_str(char delim, const std::string &str,
|
||||
std::vector<std::string> *result) {
|
||||
std::stringstream ss(str);
|
||||
std::string s;
|
||||
while (std::getline(ss, s, delim)) {
|
||||
result->push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
bool TriMesh::load_obj(std::string file) {
|
||||
|
@ -180,13 +226,15 @@ bool TriMesh::load_obj( std::string file ){
|
|||
while (std::getline(infile, line)) {
|
||||
|
||||
std::stringstream ss(line);
|
||||
std::string tok; ss >> tok;
|
||||
std::string tok;
|
||||
ss >> tok;
|
||||
|
||||
// Vertex
|
||||
if (tok == "v") {
|
||||
|
||||
// First three location
|
||||
float x, y, z; ss >> x >> y >> z;
|
||||
float x, y, z;
|
||||
ss >> x >> y >> z;
|
||||
temp_verts.push_back(Vec3f(x, y, z));
|
||||
|
||||
// Next three colors
|
||||
|
@ -200,14 +248,19 @@ bool TriMesh::load_obj( std::string file ){
|
|||
|
||||
// Normal
|
||||
if (tok == "vn") {
|
||||
float x, y, z; ss >> x >> y >> z;
|
||||
float x, y, z;
|
||||
ss >> x >> y >> z;
|
||||
temp_normals.push_back(Vec3f(x, y, z));
|
||||
}
|
||||
|
||||
} // end loop lines
|
||||
|
||||
} // end load obj
|
||||
else { std::cerr << "\n**TriMesh::load_obj Error: Could not open file " << file << std::endl; return false; }
|
||||
else {
|
||||
std::cerr << "\n**TriMesh::load_obj Error: Could not open file " << file
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Second loop, make faces
|
||||
|
@ -219,7 +272,8 @@ bool TriMesh::load_obj( std::string file ){
|
|||
while (std::getline(infile2, line)) {
|
||||
|
||||
std::stringstream ss(line);
|
||||
std::string tok; ss >> tok;
|
||||
std::string tok;
|
||||
ss >> tok;
|
||||
|
||||
// Face
|
||||
if (tok == "f") {
|
||||
|
@ -228,7 +282,8 @@ bool TriMesh::load_obj( std::string file ){
|
|||
// Get the three vertices
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
|
||||
std::string f_str; ss >> f_str;
|
||||
std::string f_str;
|
||||
ss >> f_str;
|
||||
std::vector<std::string> f_vals;
|
||||
split_str('/', f_str, &f_vals);
|
||||
assert(f_vals.size() > 0);
|
||||
|
@ -280,7 +335,8 @@ bool TriMesh::load_obj( std::string file ){
|
|||
|
||||
// Make sure we have normals
|
||||
if (!normals.size()) {
|
||||
std::cout << "**Warning: normals not loaded so we'll compute them instead." << std::endl;
|
||||
std::cout << "**Warning: normals not loaded so we'll compute them instead."
|
||||
<< std::endl;
|
||||
need_normals();
|
||||
}
|
||||
|
||||
|
@ -288,6 +344,4 @@ bool TriMesh::load_obj( std::string file ){
|
|||
|
||||
} // end load obj
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue