diff --git a/CMakeLists.txt b/CMakeLists.txt index a4acf44..8c5ef4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,12 @@ include_directories(${OPENMESH_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/vendor) # add executable add_executable(asteroidgen src/main.cpp - src/gen.cpp + src/Application.cpp + src/Polygoniser.cpp + src/TextureMapper.cpp +# src/TexturePainter.cpp +# src/gen.cpp + vendor/stb_impl.cpp vendor/mersenne-twister.cpp vendor/OpenNL_psm.c vendor/glad.c diff --git a/ToDo.txt b/ToDo.txt new file mode 100644 index 0000000..94896da --- /dev/null +++ b/ToDo.txt @@ -0,0 +1,21 @@ +LIB: +- improve marching cube +- create patches +- use lscm + +- mesh cleanup + +- profile texture generation +- improve polygonizer + +- use glm::noise or stb noise? +- view dependent progressive mesh + +- vertex color? + +GUI: +- Skybox: http://ogldev.atspace.co.uk/www/tutorial25/tutorial25.html +- Progress +- Arcball +- PBR https://learnopengl.com/#!PBR/Lighting +- save \ No newline at end of file diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..c8da35f Binary files /dev/null and b/icon.png differ diff --git a/shader/standard.fragment.glsl b/shader/standard.fragment.glsl new file mode 100644 index 0000000..4f69434 --- /dev/null +++ b/shader/standard.fragment.glsl @@ -0,0 +1,64 @@ +#version 330 core + +// Interpolated values from the vertex shaders +in vec2 UV; +in vec3 Position_worldspace; +in vec3 Normal_cameraspace; +in vec3 EyeDirection_cameraspace; +in vec3 LightDirection_cameraspace; + +// Ouput data +out vec3 color; + +// Values that stay constant for the whole mesh. +uniform sampler2D tAlbedo; +uniform mat4 MV; +uniform vec3 LightPosition_worldspace; + +void main(){ + + // Light emission properties + // You probably want to put them as uniforms + vec3 LightColor = vec3(1,1,1); + float LightPower = 400.0f; + + // Material properties + vec3 MaterialDiffuseColor = texture( tAlbedo, UV ).rgb; + vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor; + vec3 MaterialSpecularColor = vec3(0.03,0.03,0.03); + + // Distance to the light + float distance = length( LightPosition_worldspace - Position_worldspace ); + + // Normal of the computed fragment, in camera space + vec3 n = normalize( Normal_cameraspace ); + // Direction of the light (from the fragment to the light) + vec3 l = normalize( LightDirection_cameraspace ); + // Cosine of the angle between the normal and the light direction, + // clamped above 0 + // - light is at the vertical of the triangle -> 1 + // - light is perpendicular to the triangle -> 0 + // - light is behind the triangle -> 0 + float cosTheta = clamp( dot( n,l ), 0,1 ); + + // Eye vector (towards the camera) + vec3 E = normalize(EyeDirection_cameraspace); + // Direction in which the triangle reflects the light + vec3 R = reflect(-l,n); + // Cosine of the angle between the Eye vector and the Reflect vector, + // clamped to 0 + // - Looking into the reflection -> 1 + // - Looking elsewhere -> < 1 + float cosAlpha = clamp( dot( E,R ), 0,1 ); + + color = + // Ambient : simulates indirect lighting + MaterialAmbientColor + + // Diffuse : "color" of the object + MaterialDiffuseColor * LightColor * LightPower * cosTheta / (distance*distance) + + + // Specular : reflective highlight, like a mirror + MaterialSpecularColor * LightColor * LightPower * pow(cosAlpha,5) / (distance*distance); + + +} diff --git a/shader/standard.vertex.glsl b/shader/standard.vertex.glsl new file mode 100644 index 0000000..9b82ff8 --- /dev/null +++ b/shader/standard.vertex.glsl @@ -0,0 +1,44 @@ +#version 330 core + +// Input vertex data, different for all executions of this shader. +in vec3 vPosition; +in vec2 vTexCoord; +in vec3 vNormal; + +// Output data ; will be interpolated for each fragment. +out vec2 UV; +out vec3 Position_worldspace; +out vec3 Normal_cameraspace; +out vec3 EyeDirection_cameraspace; +out vec3 LightDirection_cameraspace; + +// Values that stay constant for the whole mesh. +uniform mat4 MVP; +uniform mat4 V; +uniform mat4 M; +uniform vec3 LightPosition_worldspace; + +void main(){ + + // Output position of the vertex, in clip space : MVP * position + gl_Position = MVP * vec4(vPosition,1); + + // Position of the vertex, in worldspace : M * position + Position_worldspace = (M * vec4(vPosition,1)).xyz; + + // Vector that goes from the vertex to the camera, in camera space. + // In camera space, the camera is at the origin (0,0,0). + vec3 vertexPosition_cameraspace = ( V * M * vec4(vPosition,1)).xyz; + EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace; + + // Vector that goes from the vertex to the light, in camera space. M is ommited because it's identity. + vec3 LightPosition_cameraspace = ( V * vec4(LightPosition_worldspace,1)).xyz; + LightDirection_cameraspace = LightPosition_cameraspace + EyeDirection_cameraspace; + + // Normal of the the vertex, in camera space + Normal_cameraspace = ( V * M * vec4(vNormal,0)).xyz; // Only correct if ModelMatrix does not scale the model ! Use its inverse transpose if not. + + // UV of the vertex. No special space for this one. + UV = vTexCoord; +} + diff --git a/src/Application.cpp b/src/Application.cpp new file mode 100644 index 0000000..09236dd --- /dev/null +++ b/src/Application.cpp @@ -0,0 +1,736 @@ +#include "Application.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +using glm::vec3; +using glm::uvec3; +using std::map; +using std::vector; + +void calculateNormals(const vector &vtx, vector &tri, + vector &normals) { + normals.clear(); + normals.resize(vtx.size(), vec3(0)); + for (size_t i = 0; i < tri.size(); i++) { + int a = tri[i].x, b = tri[i].y, c = tri[i].z; + vec3 faceNormal = normalize( + glm::cross(vtx[b] - vtx[a], vtx[c] - vtx[a])); + normals[a] += faceNormal; + normals[b] += faceNormal; + normals[c] += faceNormal; + } + for (size_t i = 0; i < normals.size(); i++) + normals[i] = glm::normalize(normals[i]); + +} + +void moveToMean(vector &vtx) { + vec3 mean(0); + for (size_t i = 0; i < vtx.size(); i++) { + mean += vtx[i]; + } + mean *= vec3(1.f / vtx.size()); + for (size_t i = 0; i < vtx.size(); i++) { + vtx[i] -= mean; + } +} + +void smooth(vector &vtx, const vector &tri) { + vector cogs(vtx.size(), vec3(0.f)); + vector valence(vtx.size(), 0); + + for (size_t iTri = 0; iTri < tri.size(); iTri++) { + const uvec3 &idx = tri[iTri]; + for (size_t iE = 0; iE < 3; iE++) { + valence[idx[iE]] += 2; + cogs[idx[iE]] += vtx[idx[(iE + 1) % 3]]; + cogs[idx[iE]] += vtx[idx[(iE + 2) % 3]]; + } + } + /* + for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) { + cog[0] = cog[1] = cog[2] = valence = 0.0; + + for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) { + cog += mesh.point(*vv_it); + ++valence; + } + cogs.push_back(cog / valence); + } + for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); v_it != v_end; + ++v_it, ++cog_it) + if (!mesh.is_boundary(*v_it)) + mesh.set_point(*v_it, *cog_it); + + */ + for (size_t i = 0; i < vtx.size(); i++) { +// vtx[i] = vtx[i] * vec3(0.8) +// + cogs[i] * vec3(0.2f / valence[i]); + vtx[i] = cogs[i] * vec3(1.f / valence[i]); + } +} + +void saveAttrib(std::ostream &out, const char *prefix, vector &elements) { + for (size_t i = 0; i < elements.size(); i++) { + out << prefix << elements[i].x << " " << elements[i].y << " " + << elements[i].z << "\n"; + } +} + +void saveAttrib(std::ostream &out, const char *prefix, + vector &elements) { + for (size_t i = 0; i < elements.size(); i++) { + out << prefix << elements[i].x << " " << elements[i].y << "\n"; + } +} + +void saveFaces(std::ostream &out, const vector &tris, size_t attribs) { + for (size_t i = 0; i < tris.size(); i++) { + out << "f"; + + for (size_t j = 0; j < 3; j++) { + int v = tris[i][j] + 1; + out << " " << v; + if (attribs > 1) + out << "/" << v; + if (attribs > 2) + out << "/" << v; + out << " "; + } + + out << "\n"; + } +} + +void calculateEdges(const vector &vtx, vector &tri, + vector &edges) { + edges.clear(); + map, uint32_t> edgeMap; + for (size_t iTri = 0; iTri < tri.size(); iTri++) { + uvec3 idx = tri[iTri]; + for (size_t k = 0; k < 3; k++) { + int a = idx[k]; + int b = idx[(k + 1) % 3]; + glm::uvec4 edge1(std::min(a, b), std::max(a, b), iTri, 0); + auto it1 = edgeMap.find(std::make_pair(edge1.x, edge1.y)); + if (it1 != edgeMap.end()) { + edges[it1->second].z = iTri; + } else { + edges.push_back(edge1); + } + } + } +} + +void computeTangentBasis(vector & vertices, vector & uvs, + vector & normals, vector & tangents, + vector & bitangents) { + + for (size_t i = 0; i < vertices.size(); i += 3) { + + // Shortcuts for vertices + vec3 & v0 = vertices[i + 0]; + vec3 & v1 = vertices[i + 1]; + vec3 & v2 = vertices[i + 2]; + + // Shortcuts for UVs + glm::vec2 & uv0 = uvs[i + 0]; + glm::vec2 & uv1 = uvs[i + 1]; + glm::vec2 & uv2 = uvs[i + 2]; + + // Edges of the triangle : postion delta + vec3 deltaPos1 = v1 - v0; + vec3 deltaPos2 = v2 - v0; + + // UV delta + glm::vec2 deltaUV1 = uv1 - uv0; + glm::vec2 deltaUV2 = uv2 - uv0; + + float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x); + vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r; + vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r; + // Set the same tangent for all three vertices of the triangle. + // They will be merged later, in vboindexer.cpp + tangents.push_back(tangent); + tangents.push_back(tangent); + tangents.push_back(tangent); + + // Same thing for binormals + bitangents.push_back(bitangent); + bitangents.push_back(bitangent); + bitangents.push_back(bitangent); + + } +} + +static bool glck(const char* call) { + int err = glGetError(); + if (err == 0) { + return true; + } else { + switch (err) { + case GL_INVALID_VALUE: + printf("GL_INVALID_VALUE: %s\n", call); + break; + case GL_INVALID_ENUM: + printf("GL_INVALID_ENUM: %s\n", call); + break; + case GL_INVALID_OPERATION: + printf("GL_INVALID_OPERATION: %s\n", call); + break; + default: + printf("UNKNOWN Error: %s\n", call); + } + return false; + } +} + +#define GLCK(a) {a; assert(glck(#a));} + +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) { + Application::instance().KeyCallback(window, key, scancode, action, mods); +} + +static void mouse_button_callback(GLFWwindow* window, int button, int action, + int mods) { + Application::instance().MouseButtonCallback(window, button, action, mods); + +} +static void scroll_callback(GLFWwindow* window, double xoffset, + double yoffset) { + Application::instance().ScrollCallback(window, xoffset, yoffset); +} + +static void char_callback(GLFWwindow* window, unsigned int c) { + Application::instance().CharCallback(window, c); +} + +Application::Application() : + window(0), density(), densityIsolevel(0.2), polygonizer(density, + densityIsolevel), textureSize(512), texturemapper(density, + textureSize), programId(0), vPositionLoc(-1), vTexCoordLoc(-1), vNormalLoc( + -1), meteoridCount(1000), meteroidMinRadius(0.005), meteroidMaxRadius( + 0.2), meteroidSizeExponent(2048), densityFrequency(2), densityOctave( + 2), densityScale(1.0f), resolution(0.1), viewDistance(3.0f), fpsMode( + false) { + init(); +} + +Application::~Application() { + shutdown(); +} + +Application &Application::instance() { + static Application app; + return app; +} + +void Application::init() { + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + + window = glfwCreateWindow(1200, 800, "Procedural Asteroid Generator", NULL, + NULL); + if (!window) { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + GLFWimage icon; + int n; + icon.pixels = stbi_load("icon.png", &icon.width, &icon.height, &n, 4); + if (icon.pixels) { + glfwSetWindowIcon(window, 1, &icon); + stbi_image_free(icon.pixels); + } else + std::cout << "Failed to load icon.png" << std::endl; + + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetScrollCallback(window, scroll_callback); + glfwSetKeyCallback(window, key_callback); + glfwSetCharCallback(window, char_callback); + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + glfwSwapInterval(1); + + std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; + std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) + << std::endl; + std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl; + std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl; + + ImGui_ImplGlfwGL3_Init(window, false); + + GLCK(glGenVertexArrays(1, &vertexArrayId)) + GLCK(glGenBuffers(1, &vPositionId)) + GLCK(glGenBuffers(1, &vTexCoordId)) + GLCK(glGenBuffers(1, &vNormalId)) + GLCK(glGenBuffers(1, &indexBufferId)) + + GLCK(glGenTextures(1, &tAlbedoId)) + GLCK(glGenTextures(1, &tNormalId)) + GLCK(glGenTextures(1, &tRoughnessId)) + GLCK(glGenTextures(1, &tMetalicId)) + + loadShader(); + updateVertexArrayObject(); + generateAsteroid(); + uploadMesh(); +} + +void Application::shutdown() { + ImGui_ImplGlfwGL3_Shutdown(); + + GLCK(glDeleteBuffers(1, &vPositionId)) + GLCK(glDeleteBuffers(1, &vTexCoordId)) + GLCK(glDeleteBuffers(1, &vNormalId)) + GLCK(glDeleteBuffers(1, &indexBufferId)) + GLCK(glDeleteVertexArrays(1, &vertexArrayId)) + + glfwDestroyWindow(window); + glfwTerminate(); +} + +void Application::KeyCallback(GLFWwindow* window, int key, int scancode, + int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) + glfwSetWindowShouldClose(window, GLFW_TRUE); + if (ImGui::IsMouseHoveringAnyWindow()) + ImGui_ImplGlfwGL3_KeyCallback(window, key, scancode, action, mods); + else { + if (key == GLFW_KEY_TAB && action == GLFW_RELEASE) { + toogleFpsMode(); + } + } +} + +void Application::MouseButtonCallback(GLFWwindow* window, int button, + int action, int mods) { + ImGui_ImplGlfwGL3_MouseButtonCallback(window, button, action, mods); +} +void Application::ScrollCallback(GLFWwindow* window, double xoffset, + double yoffset) { + if (ImGui::IsMouseHoveringAnyWindow()) + ImGui_ImplGlfwGL3_ScrollCallback(window, xoffset, yoffset); + else + viewDistance -= yoffset * viewDistance * 0.1; +} +void Application::CharCallback(GLFWwindow* window, unsigned int c) { + + ImGui_ImplGlfwGL3_CharCallback(window, c); +} + +void Application::toogleFpsMode() { + if (fpsMode) { + fpsMode = false; + } else { + fpsMode = true; + fpsTrafo = glm::lookAt(vec3(0, 0, viewDistance), vec3(0, 0, 0), + vec3(0, 1, 0)); + } +} + +void Application::generateAsteroid() { + std::srand(123); + + if (density.getImpacts().size() == 0) + density.addRandomImpacts(1000, 0.2, 0.01, 0.005, 0.2, 4096); + //density.saveCrossSection("density.png", 512); + + polygonizer.polygonize(resolution); + { + std::ofstream out("stage1.obj"); + saveAttrib(out, "v ", polygonizer.vertices); + saveFaces(out, polygonizer.indices, 1); + } + + smooth(polygonizer.vertices, polygonizer.indices); + { + std::ofstream out("stage2.obj"); + saveAttrib(out, "v ", polygonizer.vertices); + saveFaces(out, polygonizer.indices, 1); + } + calculateNormals(polygonizer.vertices, polygonizer.indices, normals); + { + std::ofstream out("stage3.obj"); + saveAttrib(out, "v ", polygonizer.vertices); + saveAttrib(out, "vn ", normals); + saveFaces(out, polygonizer.indices, 2); + } + + vector edges; + std::cout << "Vertices: " << polygonizer.vertices.size() << std::endl; + std::cout << "Triangles: " << polygonizer.indices.size() << std::endl; + + texturemapper.map(polygonizer.vertices, normals, polygonizer.indices); + moveToMean(texturemapper.vertices); + + { + std::ofstream out("stage4.obj"); + saveAttrib(out, "v ", texturemapper.vertices); + saveAttrib(out, "vn ", texturemapper.normals); + saveAttrib(out, "vt ", texturemapper.texcoords); + saveFaces(out, texturemapper.indices, 3); + } +} + +bool Application::bindVertexAttrib(GLuint id, GLint loc, GLuint size) { + if (loc < 0) + return false; + GLCK(glBindBuffer(GL_ARRAY_BUFFER, id)) + GLCK(glEnableVertexAttribArray(loc)) + GLCK(glVertexAttribPointer(loc, // attribute + size,// size + GL_FLOAT,// type + GL_FALSE,// normalized? + 0,// stride + (void* ) 0// array buffer offset + )) + return true; +} + +void Application::updateVertexArrayObject() { + GLCK(glBindVertexArray(vertexArrayId)) + + if (vPositionLoc >= 0) + GLCK(glDisableVertexAttribArray(vPositionLoc)) + if (vNormalLoc >= 0) + GLCK(glDisableVertexAttribArray(vNormalLoc)) + if (vTexCoordLoc >= 0) + GLCK(glDisableVertexAttribArray(vTexCoordLoc)) + + bindVertexAttrib(vPositionId, vPositionLoc, 3); + bindVertexAttrib(vNormalId, vNormalLoc, 3); + bindVertexAttrib(vTexCoordId, vTexCoordLoc, 2); + + GLCK(glBindVertexArray(0)) +} + +GLuint Application::loadProgram(const std::string &name) { + + // Create the shaders + GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + // Read the Vertex Shader code from the file + std::string VertexShaderCode; + std::string vertex_file_path = "shader/" + name + ".vertex.glsl"; + std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); + if (VertexShaderStream.is_open()) { + std::string Line = ""; + while (getline(VertexShaderStream, Line)) + VertexShaderCode += "\n" + Line; + VertexShaderStream.close(); + } else { + std::cout << "Failed to open " << vertex_file_path << std::endl; + return 0; + } + + // Read the Fragment Shader code from the file + std::string FragmentShaderCode; + std::string fragment_file_path = "shader/" + name + ".fragment.glsl"; + std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); + if (FragmentShaderStream.is_open()) { + std::string Line = ""; + while (getline(FragmentShaderStream, Line)) + FragmentShaderCode += "\n" + Line; + FragmentShaderStream.close(); + } else { + std::cout << "Failed to open " << vertex_file_path << std::endl; + return 0; + } + + GLint Result = GL_FALSE; + int InfoLogLength; + + // Compile Vertex Shader + std::cout << "Compiling vertex shader : " << name << std::endl; + char const * VertexSourcePointer = VertexShaderCode.c_str(); + glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); + glCompileShader(VertexShaderID); + + // Check Vertex Shader + glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if (InfoLogLength > 0) { + vector VertexShaderErrorMessage(InfoLogLength + 1); + glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, + &VertexShaderErrorMessage[0]); + printf("%s\n", &VertexShaderErrorMessage[0]); + } + + // Compile Fragment Shader + std::cout << "Compiling fragment shader : " << name << std::endl; + + char const * FragmentSourcePointer = FragmentShaderCode.c_str(); + glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); + glCompileShader(FragmentShaderID); + + // Check Fragment Shader + glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if (InfoLogLength > 0) { + vector FragmentShaderErrorMessage(InfoLogLength + 1); + glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, + &FragmentShaderErrorMessage[0]); + printf("%s\n", &FragmentShaderErrorMessage[0]); + } + + // Link the program + std::cout << "Linking program : " << name << std::endl; + + GLuint ProgramID = glCreateProgram(); + glAttachShader(ProgramID, VertexShaderID); + glAttachShader(ProgramID, FragmentShaderID); + glLinkProgram(ProgramID); + + // Check the program + glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); + glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if (InfoLogLength > 0) { + vector ProgramErrorMessage(InfoLogLength + 1); + glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, + &ProgramErrorMessage[0]); + printf("%s\n", &ProgramErrorMessage[0]); + } + + glDetachShader(ProgramID, VertexShaderID); + glDetachShader(ProgramID, FragmentShaderID); + + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + + return ProgramID; +} + +void Application::loadShader() { + if (programId >= 0) + GLCK(glDeleteProgram(programId)) + programId = loadProgram("standard"); + + GLCK(MVPloc = glGetUniformLocation(programId, "MVP")) + GLCK(Mloc = glGetUniformLocation(programId, "M")) + GLCK(Vloc = glGetUniformLocation(programId, "V")) + GLCK( + LightPosition_worldspaceloc = glGetUniformLocation(programId, "LightPosition_worldspace")) + + GLCK(vPositionLoc = glGetAttribLocation(programId, "vPosition")) + GLCK(vTexCoordLoc = glGetAttribLocation(programId, "vTexCoord")) + GLCK(vNormalLoc = glGetAttribLocation(programId, "vNormal")) + + GLCK(tAlbedoLoc = glGetAttribLocation(programId, "tAlbedo")) + GLCK(tNormalLoc = glGetAttribLocation(programId, "tNormal")) + GLCK(tRoughnessLoc = glGetAttribLocation(programId, "tRoughness")) + GLCK(tMetalicLoc = glGetAttribLocation(programId, "tMetalic")) +} + +void Application::uploadMesh() { + GLCK(glBindVertexArray(vertexArrayId)) + + GLCK(glBindBuffer(GL_ARRAY_BUFFER, vPositionId)) + GLCK( + glBufferData(GL_ARRAY_BUFFER, texturemapper.vertices.size() * sizeof(vec3), texturemapper.vertices.data(), GL_STATIC_DRAW)) + + GLCK(glBindBuffer(GL_ARRAY_BUFFER, vTexCoordId)) + GLCK( + glBufferData(GL_ARRAY_BUFFER, texturemapper.texcoords.size() * sizeof(glm::vec2), texturemapper.texcoords.data(), GL_STATIC_DRAW)) + + GLCK(glBindBuffer(GL_ARRAY_BUFFER, vNormalId)) + GLCK( + glBufferData(GL_ARRAY_BUFFER, texturemapper.normals.size() * sizeof(vec3), texturemapper.normals.data(), GL_STATIC_DRAW)) + + GLCK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId)) + GLCK( + glBufferData(GL_ELEMENT_ARRAY_BUFFER, texturemapper.indices.size() * sizeof(uvec3), texturemapper.indices.data(), GL_STATIC_DRAW)) + + GLCK(glBindVertexArray(0)) + + glBindTexture(GL_TEXTURE_2D, tAlbedoId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturemapper.getTextureSize(), + texturemapper.getTextureSize(), 0, GL_BGR, GL_UNSIGNED_BYTE, + texturemapper.albedo.data()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} + +void Application::renderMesh() { + GLCK(glBindVertexArray(vertexArrayId)) + GLCK( + glDrawElements(GL_TRIANGLES, texturemapper.indices.size() * 3, GL_UNSIGNED_INT, (void* ) 0)) + GLCK(glBindVertexArray(0)) + +} + +void Application::prepareShader() { + glm::mat4 model(1.0f); + glm::mat4 view; + + if (fpsMode) { + glm::vec4 movement(0.0); + if (fpsMode) { + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + movement += glm::vec4(0.0, 0.0, 0.1, 0.0); + } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + movement -= glm::vec4(0.0, 0.0, 0.1, 0.0); + } + } + glm::vec3 absolute = glm::transpose(fpsTrafo) * movement; + fpsTrafo = glm::translate(fpsTrafo, absolute); + view = fpsTrafo; + } else { + model = glm::rotate(model, (float) glfwGetTime(), vec3(0.f, 1.f, 0.f)); + + view = glm::lookAt(vec3(0, 0, viewDistance), // Camera is at (4,3,3), in World Space + vec3(0, 0, 0), // and looks at the origin + vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down) + ); + } + glm::mat4 perspective = glm::perspective(glm::radians(45.0f), + (float) width / (float) height, 0.1f, 100.0f); + glm::mat4 mvp = perspective * view * model; + + GLCK(glUseProgram(programId)) + if (MVPloc >= 0) { + GLCK(glUniformMatrix4fv(MVPloc, 1, GL_FALSE, glm::value_ptr(mvp))) + } + if (Mloc >= 0) { + GLCK(glUniformMatrix4fv(Mloc, 1, GL_FALSE, glm::value_ptr(model))) + } + if (Vloc >= 0) { + GLCK(glUniformMatrix4fv(Vloc, 1, GL_FALSE, glm::value_ptr(view))) + } + if (LightPosition_worldspaceloc >= 0) { + vec3 LightPosition_worldspace(10.0f, 10.0f, 10.0f); + GLCK( + glUniform3fv(LightPosition_worldspaceloc, 1, glm::value_ptr(LightPosition_worldspace))) + } + + int idx = 0; + if (tAlbedoLoc >= 0) { + glUniform1i(tAlbedoLoc, idx); + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, tAlbedoId); + idx++; + } + if (tNormalLoc >= 0) { + glUniform1i(tNormalLoc, idx); + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, tNormalId); + idx++; + } + if (tRoughnessLoc >= 0) { + glUniform1i(tRoughnessLoc, idx); + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, tRoughnessId); + idx++; + } + if (tMetalicLoc >= 0) { + glUniform1i(tMetalicLoc, idx); + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, tMetalicId); + idx++; + } +} + +void Application::gui() { + ImGui::Begin("Mesh Generation"); + ImGui::Text("Vertices: %lu, Triangles: %lu", polygonizer.vertices.size(), + polygonizer.indices.size()); + //ImGui::InputFloat("Resolution", &resolution); + ImGui::SliderFloat("Resolution", &resolution, 0.1, 0.001, "%.3f", 0.1); + if (ImGui::SliderFloat("Frequency", &densityFrequency, 1, 10, "%.0f", 1)) + density.setFrequency(densityFrequency); + if (ImGui::SliderFloat("Octave", &densityOctave, 1, 10, "%.0f", 1)) + density.setOctave(densityOctave); + + // if (ImGui::InputFloat("Frequency", &densityFrequency)) +// if (ImGui::InputFloat("Octave", &densityOctave)) +// density.setOctave(densityOctave); + + static const char *textureSizesStrings[] = { "512", "1024", "2048", "4096" }; + static const int textureSizes[] = { 512, 1024, 2048, 4096 }; + static int currentTextureSize = 0; + if (ImGui::Combo("Texture Size", ¤tTextureSize, textureSizesStrings, + 4, -1)) { + texturemapper.setTextureSize(textureSizes[currentTextureSize]); + } + + if (ImGui::Button("Generate")) { + generateAsteroid(); + uploadMesh(); + } + ImGui::End(); + + ImGui::Begin("Rendering"); + if (ImGui::Button("Reload Shader")) { + loadShader(); + updateVertexArrayObject(); + } + if (ImGui::Button("Wireframe")) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + if (ImGui::Button("Fill")) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", + 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::End(); + + ImGui::Begin("Textures"); + ImGui::Image((ImTextureID) (intptr_t) tAlbedoId, + ImVec2(ImGui::GetWindowContentRegionMax().x, + ImGui::GetWindowContentRegionMax().x)); + ImGui::End(); +} + +void Application::run() { + + while (!glfwWindowShouldClose(window)) { + glfwPollEvents(); + glfwGetFramebufferSize(window, &width, &height); + ImGui_ImplGlfwGL3_NewFrame(); + + gui(); + + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); + + prepareShader(); + renderMesh(); + + ImGui::Render(); + glfwSwapBuffers(window); + + } +} diff --git a/src/Application.h b/src/Application.h new file mode 100644 index 0000000..69b6289 --- /dev/null +++ b/src/Application.h @@ -0,0 +1,89 @@ +#pragma once + +#include "Density.h" +#include "Polygoniser.h" +#include "TextureMapper.h" + +#include +#include + +#include + + +struct GLFWwindow; + +class Application { + GLFWwindow* window; + int width, height; + + Density density; + float densityIsolevel; + Polygonizer polygonizer; + float textureSize; + TextureMapper texturemapper; + + unsigned int vertexArrayId, vPositionId, vTexCoordId, vNormalId, + indexBufferId, programId, tAlbedoId, tNormalId, tRoughnessId, + tMetalicId; + + int MVPloc, Vloc, Mloc, MVloc, LightPosition_worldspaceloc; + int vPositionLoc, vTexCoordLoc, vNormalLoc, tAlbedoLoc, tNormalLoc, + tRoughnessLoc, tMetalicLoc; + + std::vector vertices; + std::vector normals; + std::vector texcoords; + std::vector indices; + + size_t meteoridCount; + float meteroidMinRadius; + float meteroidMaxRadius; + int meteroidSizeExponent; + float densityFrequency, densityOctave; + glm::vec3 densityScale; + float resolution; + + float viewDistance; + + glm::mat4 fpsTrafo; + bool fpsMode; + + void toogleFpsMode(); +public: + Application(); + + ~Application(); + + static Application &instance(); + + void init(); + + void shutdown(); + + void KeyCallback(GLFWwindow* window, int key, int scancode, int action, + int mods); + void MouseButtonCallback(GLFWwindow* window, int button, int action, + int mods); + void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); + void CharCallback(GLFWwindow* window, unsigned int c); + + void generateAsteroid(); + + bool bindVertexAttrib(unsigned int id, int loc, unsigned int size); + + void updateVertexArrayObject(); + + unsigned int loadProgram(const std::string &name); + + void loadShader(); + + void uploadMesh(); + + void renderMesh(); + + void prepareShader(); + + void gui(); + + void run(); +}; diff --git a/src/Density.h b/src/Density.h index 89d95af..950befa 100644 --- a/src/Density.h +++ b/src/Density.h @@ -27,40 +27,57 @@ class Density { glm::vec3 scale; float scaleFactor; float frequency, octave; - + size_t version; public: Density() : - scale(1), scaleFactor(4), frequency(2), octave(2) { + scale(1.0f), scaleFactor(4), frequency(2), octave(2), version(0) { } + const std::vector &getImpacts() { + return impacts; + } + + size_t getVersion() { + return version; + } + void addImpact(Impact &impact) { size_t idx = impacts.size(); impacts.push_back(impact); glm::vec3 l = impact.pos - glm::vec3(impact.r); glm::vec3 u = impact.pos + glm::vec3(impact.r); impactTree.Insert(&l.x, &u.x, idx); + version++; } void setSeed(uint32_t seed) { noise.reseed(seed); + impacts.clear(); } void setScale(const glm::vec3 &scale) { this->scale = scale; scaleFactor = 4.f / std::min(scale.x, std::min(scale.y, scale.z)); + impacts.clear(); + version++; + } void setFrequency(float f) { frequency = f; + impacts.clear(); + version++; } void setOctave(float o) { octave = o; + impacts.clear(); + version++; } - float operator()(const glm::vec3 &p) const { - if (impacts.size()) { + float operator()(const glm::vec3 &p, bool includeImpacts = true) const { + if (includeImpacts & impacts.size()) { bool insideImpact = false; impactTree.Search(&p.x, &p.x, [&](int idx) -> bool { if (impacts[idx].contains(p)) { @@ -82,7 +99,7 @@ public: } bool intersectIsolevel(const glm::vec3 &start, const glm::vec3 &end, - glm::vec3 &pos, float isolevel, float resolution) { + glm::vec3 &pos, float isolevel, float resolution) const { glm::vec3 step = glm::normalize(end - start) * glm::vec3(resolution); size_t nSteps = ceil(glm::length(end - start) / resolution); pos = start; diff --git a/src/Polygoniser.cpp b/src/Polygoniser.cpp new file mode 100644 index 0000000..dfe016d --- /dev/null +++ b/src/Polygoniser.cpp @@ -0,0 +1,199 @@ +#include "Polygoniser.h" + +#include +#include + +#include + +#include + +static const int isocells = 32; + +Polygonizer::Polygonizer(Density &density, float isolevel) : + density(density), isolevel(isolevel) { + updateIsocell(); +} + +void Polygonizer::setIsoLevel(float isolevel) { + bool needIsocellUpdate = false; + if (this->isolevel != isolevel) { + this->isolevel = isolevel; + needIsocellUpdate = true; + } + needIsocellUpdate |= (isocellVersion != density.getVersion()); + if (needIsocellUpdate) + updateIsocell(); +} + +void Polygonizer::updateIsocell() { + isocell.clear(); + isocell.reserve(isocells * isocells * isocells); + + float step = 1. / isocells; + for (size_t ix = 0; ix < isocells; ix++) { + float xmin = ix * step; + float xmax = xmin + step; + for (size_t iy = 0; iy < isocells; iy++) { + float ymin = iy * step; + float ymax = ymin + step; + + float xyz = density(vec3(xmin, ymin, 0)); + float Xyz = density(vec3(xmax, ymin, 0)); + float xYz = density(vec3(xmin, ymax, 0)); + float XYz = density(vec3(xmax, ymax, 0)); + bool zAllUnder = (xyz < isolevel) && (Xyz < isolevel) + && (xYz < isolevel) && (XYz < isolevel); + bool zAllOver = (xyz > isolevel) && (Xyz > isolevel) + && (xYz > isolevel) && (XYz > isolevel); + + for (size_t iz = 0; iz < isocells; iz++) { + float zmin = iz * step; + float zmax = zmin + step; + + float xyZ = density(vec3(xmin, ymin, zmax)); + float XyZ = density(vec3(xmax, ymin, zmax)); + float xYZ = density(vec3(xmin, ymax, zmax)); + float XYZ = density(vec3(xmax, ymax, zmax)); + bool ZAllUnder = (xyZ < isolevel) && (XyZ < isolevel) + && (xYZ < isolevel) && (XYZ < isolevel); + bool ZAllOver = (xyZ > isolevel) && (XyZ > isolevel) + && (xYZ > isolevel) && (XYZ > isolevel); + + isocell[ix * isocells * isocells + iy * isocells + iz] = + (zAllUnder && ZAllUnder) || (zAllOver && ZAllOver); + + xyz = xyZ; + Xyz = XyZ; + xYz = xYZ; + XYz = XYZ; + zAllUnder = ZAllUnder; + zAllOver = ZAllOver; + } + } + } + isocellVersion = density.getVersion(); +} + +void Polygonizer::polygonize(const glm::vec3 lower, const glm::vec3 upper, + float resolution) { + + size_t nSteps = 1.f / resolution - 1; + size_t nT = 0; + for (size_t ix = 0; ix < nSteps; ix++) { + double x = (double(ix) + 0.5) * resolution; + for (size_t iy = 0; iy < nSteps; iy++) { + double y = (double(iy) + 0.5) * resolution; + for (size_t iz = 0; iz < nSteps; iz++) { + double z = (double(iz) + 0.5) * resolution; + + GRIDCELL gridCell; + gridCell.p[0] = vec3(x, y, z); + gridCell.p[1] = vec3(x + resolution, y, z); + gridCell.p[2] = vec3(x + resolution, y + resolution, z); + gridCell.p[3] = vec3(x, y + resolution, z); + gridCell.p[4] = vec3(x, y, z + resolution); + gridCell.p[5] = vec3(x + resolution, y, z + resolution); + gridCell.p[6] = vec3(x + resolution, y + resolution, + z + resolution); + gridCell.p[7] = vec3(x, y + resolution, z + resolution); + + for (size_t iCell = 0; iCell < 8; iCell++) { + gridCell.val[iCell] = density(gridCell.p[iCell]); + } + + TRIANGLE tris[6]; + int nTris = Polygonise(gridCell, isolevel, tris); + nT += nTris; + for (int iTri = 0; iTri < nTris; iTri++) { + vec3 *ps = tris[iTri].p; + + // skip degenerate vertices + if (all(epsilonEqual(ps[0], ps[1], 1e-8f)) + || all(epsilonEqual(ps[0], ps[2], 1e-8f)) + || all(epsilonEqual(ps[2], ps[1], 1e-8f))) + continue; + + glm::uvec3 idc; + for (size_t k = 0; k < 3; k++) { + glm::vec3 &p = tris[iTri].p[k]; + std::map::iterator vit = + vertexLookup.find(p); + if (vit != vertexLookup.end()) { + idc[k] = vit->second; + } else { + idc[k] = vertices.size(); + vertices.push_back(p); + vertexLookup[p] = idc[k]; + } + } + indices.push_back(idc); + } + } + } + } +} + +void Polygonizer::polygonize(float resolution) { + vertexLookup.clear(); + vertices.clear(); + indices.clear(); + +// coarse scan + float coarseResolution = resolution * 10; + + size_t nSteps = 1.f / resolution - 1; + size_t nT = 0; + for (size_t ix = 0; ix < nSteps; ix++) { + double x = (double(ix) + 0.5) * resolution; + for (size_t iy = 0; iy < nSteps; iy++) { + double y = (double(iy) + 0.5) * resolution; + for (size_t iz = 0; iz < nSteps; iz++) { + double z = (double(iz) + 0.5) * resolution; + + GRIDCELL gridCell; + gridCell.p[0] = vec3(x, y, z); + gridCell.p[1] = vec3(x + resolution, y, z); + gridCell.p[2] = vec3(x + resolution, y + resolution, z); + gridCell.p[3] = vec3(x, y + resolution, z); + gridCell.p[4] = vec3(x, y, z + resolution); + gridCell.p[5] = vec3(x + resolution, y, z + resolution); + gridCell.p[6] = vec3(x + resolution, y + resolution, + z + resolution); + gridCell.p[7] = vec3(x, y + resolution, z + resolution); + + for (size_t iCell = 0; iCell < 8; iCell++) { + gridCell.val[iCell] = density(gridCell.p[iCell]); + } + + TRIANGLE tris[6]; + int nTris = Polygonise(gridCell, isolevel, tris); + nT += nTris; + for (int iTri = 0; iTri < nTris; iTri++) { + vec3 *ps = tris[iTri].p; + + // skip degenerate vertices + if (all(epsilonEqual(ps[0], ps[1], 1e-8f)) + || all(epsilonEqual(ps[0], ps[2], 1e-8f)) + || all(epsilonEqual(ps[2], ps[1], 1e-8f))) + continue; + + glm::uvec3 idc; + for (size_t k = 0; k < 3; k++) { + glm::vec3 &p = tris[iTri].p[k]; + std::map::iterator vit = + vertexLookup.find(p); + if (vit != vertexLookup.end()) { + idc[k] = vit->second; + } else { + idc[k] = vertices.size(); + vertices.push_back(p); + vertexLookup[p] = idc[k]; + } + } + indices.push_back(idc); + } + } + } + } + +} diff --git a/src/Polygoniser.h b/src/Polygoniser.h index f9f551e..40789be 100644 --- a/src/Polygoniser.h +++ b/src/Polygoniser.h @@ -1,14 +1,9 @@ #pragma once -#include #include #include #include -#include - -#include -#include #include "Density.h" @@ -39,79 +34,22 @@ struct CompareVec3 { }; class Polygonizer { + Density &density; + float isolevel; public: std::vector vertices; - std::vector triangles; + std::vector indices; + std::map vertexLookup; - Density &density; + std::vector isocell; + size_t isocellVersion; - Polygonizer(Density &density) : - density(density) { + Polygonizer(Density &density, float isolevel); + void setIsoLevel(float isolevel); - } - - void polygonize(float isolevel, float resolution) { - vertices.clear(); - triangles.clear(); - - std::map vertexLookup; - - size_t nSteps = 1.f / resolution - 1; - size_t nT = 0; - for (size_t ix = 0; ix < nSteps; ix++) { - double x = (double(ix) + 0.5) * resolution; - for (size_t iy = 0; iy < nSteps; iy++) { - double y = (double(iy) + 0.5) * resolution; - for (size_t iz = 0; iz < nSteps; iz++) { - double z = (double(iz) + 0.5) * resolution; - - GRIDCELL gridCell; - gridCell.p[0] = vec3(x, y, z); - gridCell.p[1] = vec3(x + resolution, y, z); - gridCell.p[2] = vec3(x + resolution, y + resolution, z); - gridCell.p[3] = vec3(x, y + resolution, z); - gridCell.p[4] = vec3(x, y, z + resolution); - gridCell.p[5] = vec3(x + resolution, y, z + resolution); - gridCell.p[6] = vec3(x + resolution, y + resolution, - z + resolution); - gridCell.p[7] = vec3(x, y + resolution, z + resolution); - - for (size_t iCell = 0; iCell < 8; iCell++) { - gridCell.val[iCell] = density(gridCell.p[iCell]); - } - - TRIANGLE tris[6]; - int nTris = Polygonise(gridCell, isolevel, tris); - nT += nTris; - for (int iTri = 0; iTri < nTris; iTri++) { - vec3 *ps = tris[iTri].p; - - // skip degenerate vertices - if (all(epsilonEqual(ps[0], ps[1], 1e-8f)) - || all(epsilonEqual(ps[0], ps[2], 1e-8f)) - || all(epsilonEqual(ps[2], ps[1], 1e-8f))) - continue; - - glm::uvec3 idc; - for (size_t k = 0; k < 3; k++) { - glm::vec3 &p = tris[iTri].p[k]; - std::map::iterator vit = - vertexLookup.find(p); - if (vit != vertexLookup.end()) { - idc[k] = vit->second; - } else { - idc[k] = vertices.size(); - vertices.push_back(p); - vertexLookup[p] = idc[k]; - } - } - triangles.push_back(idc); - } - } - } - } - - - } + void updateIsocell(); + void polygonize(float resolution); + void polygonize(const glm::vec3 lower, const glm::vec3 upper, + float isolevel); }; diff --git a/src/TextureMapper.cpp b/src/TextureMapper.cpp new file mode 100644 index 0000000..a2e80a3 --- /dev/null +++ b/src/TextureMapper.cpp @@ -0,0 +1,205 @@ +#include "TextureMapper.h" + +#include + +#include "stb_image_write.h" + +#include + +TextureMapper::TextureMapper(Density &density, size_t textureSize) : + density(density), textureSize(textureSize), albedo( + textureSize * textureSize), normal(textureSize * textureSize), roughness( + textureSize * textureSize), darkestColor(0.3, 0.25, 0.2), brightestColor( + 0.9, 0.85, 0.8) { + +} +void TextureMapper::setTextureSize(size_t size) { + textureSize = size; + albedo.resize(textureSize * textureSize); + normal.resize(textureSize * textureSize); + roughness.resize(textureSize * textureSize); +} + +size_t TextureMapper::getTextureSize() { + return textureSize; +} + +void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals, + const uvec3v_t &inIndices) { + float texf = 1. / textureSize; + + vertices.clear(); + vertices.reserve(inIndices.size() * 3); + normals.clear(); + normals.reserve(inIndices.size() * 3); + texcoords.clear(); + texcoords.reserve(inIndices.size() * 3); + + int rects = ceil(sqrt(inIndices.size())), rx = 0, ry = 0; + float rectSize = floor(float(textureSize) / rects) / textureSize; + for (size_t i = 0; i != inIndices.size(); i++) { + glm::vec3 p[3], n[3]; + glm::uvec3 idx = inIndices[i]; + indices.push_back( + glm::uvec3(vertices.size(), vertices.size() + 1, + vertices.size() + 2)); + for (size_t j = 0; j < 3; j++) { + p[j] = inVertices[idx[j]]; + vertices.push_back(p[j]); + n[j] = inNormals[idx[j]]; + normals.push_back(n[j]); + } + + glm::vec3 ex = glm::normalize(p[1] - p[0]); + glm::vec3 ey = glm::normalize(glm::cross(ex, p[2] - p[0])); + glm::vec3 ez = glm::normalize(glm::cross(ex, ey)); + glm::mat3 base = glm::mat3(ex, ey, ez); + glm::vec3 t[3] = { p[0] * base, p[1] * base, p[2] * base }; + glm::vec3 lower = min(min(t[0], t[1]), t[2]); + glm::vec3 upper = max(max(t[0], t[1]), t[2]); + t[0] -= lower; + t[1] -= lower; + t[2] -= lower; + glm::vec3 extent = upper - lower; + float s = std::max(std::max(extent.x, extent.y), extent.z); + t[0] *= 0.8 * rectSize / s; + t[1] *= 0.8 * rectSize / s; + t[2] *= 0.8 * rectSize / s; + glm::vec3 off(rx * rectSize, 0, ry * rectSize); + t[0] += off; + t[1] += off; + t[2] += off; + texcoords.push_back(glm::vec2(t[0].x, t[0].z)); + texcoords.push_back(glm::vec2(t[1].x, t[1].z)); + texcoords.push_back(glm::vec2(t[2].x, t[2].z)); + + //if (rx == 0 && ry == 0) { + t[0].y = 0; + t[1].y = 0; + t[2].y = 0; +// cout << "ftex " << texf << endl; +// cout << "t[0] " << t[0].x << " " << t[0].z << endl; +// cout << "t[1] " << t[1].x << " " << t[1].z << endl; +// cout << "t[2] " << t[2].x << " " << t[2].z << endl; +// cout << "t[0]p " << t[0].x * ntex << " " << (1 - t[0].z) * ntex << endl; +// cout << "t[1]p " << t[1].x * ntex << " " << (1 - t[1].z) * ntex << endl; +// cout << "t[2]p " << t[2].x * ntex << " " << (1 - t[2].z) * ntex << endl; + // fill texture + // fill whole rect for now + int rpix = floor(rectSize * textureSize); + + glm::vec3 eb = t[1] - t[0]; + float leb = glm::length(eb); + glm::vec3 ec = t[2] - t[0]; + float lec = glm::length(ec); +// mat2 textureBase = mat2(vec2(eb.x, eb.z), vec2(ec.x, ec.z)); +// mat2 itextureBase = inverse(textureBase); + glm::mat3 textureBase = glm::mat3(eb, glm::cross(eb, ec), ec); + glm::mat3 itextureBase = glm::inverse(textureBase); + +// eb = normalize(eb); +// ec = normalize(ec); + + glm::vec3 db = p[1] - p[0]; + glm::vec3 dc = p[2] - p[0]; + + glm::vec3 mb = glm::normalize(p[1] - p[0]); + glm::vec3 mc = glm::normalize(p[2] - p[0]); +// mat2 faceBase = mat2(vec2(mb.x, mb.z), vec2(mc.x, mc.z)); +// mat2 ifaceBase = inverse(faceBase); + + glm::mat3 faceBase = glm::mat3(db, glm::cross(db, dc), dc); + glm::mat3 ifaceBase = glm::inverse(faceBase); + + glm::vec3 tmin = max( + floor( + min(min(t[0], t[1]), t[2]) + * glm::vec3((float) textureSize)) + - glm::vec3(1.0f), glm::vec3(0.1)); + glm::vec3 tmax = min( + ceil( + max(max(t[0], t[1]), t[2]) + * glm::vec3((float) textureSize)) + + glm::vec3(1.0f), glm::vec3(textureSize-1)); + + // TODO: borders! + for (int ix = tmin.x; ix < tmax.x; ix++) { + for (int iy = (textureSize - tmax.z); iy < (textureSize - tmin.z); + iy++) { + + // https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle#2049593 + +// for (int iy = tmin.z; iy < tmax.z; iy++) { + +// cout << "pix " << ix << " " << iy << endl; +// cout << "uv " << float(ix) * texf << " " << 1.f - float(iy) * texf << endl; + + // pixel to uv space + glm::vec3 res = glm::vec3(float(ix) * texf, 0.f, + 1.f - float(iy) * texf) - t[0]; + // cout << "r = " << r.x << " " << r.y << endl; + glm::vec3 local = faceBase * itextureBase * res; + + // cout << "res = " << res.x << " " << res.y << endl; +// vec2 res = ifaceBase * textureBase * r * faceBase; + // +// cout << "pix " << ix << " " << res.x << " " << res.y << " " << res.z << endl; +// float fb = dot(r, eb) / leb; +// float fc = dot(r, ec) / lec; + glm::vec3 sp = p[0] + local; //res.x * mb + res.y * mc; + float v = (float) density(sp, false); +// + //v = pow(v, 3); + // default color +// float r = 0.8 + v * 0.2, g = 0.75 + 0.2 * v, b = 0.7 +// + 0.2 * v; + + glm::vec3 rgb = glm::vec3(255) + * glm::mix(darkestColor, brightestColor, v); + albedo[ix + (textureSize - iy) * textureSize][0] = rgb.x; + albedo[ix + (textureSize - iy) * textureSize][1] = rgb.y; + albedo[ix + (textureSize - iy) * textureSize][2] = rgb.z; + +// diff[ix + iy * ntex] = v * 255; +// diff[ix + iy * ntex][0] = (32 * rx) % 255; +// diff[ix + iy * ntex][1] = (32 * ry) % 255; +// diff[ix + iy * ntex][2] = 0; //(0.5 + sp.z) * 255; + +// float rd = 1.f; //0.7 + 0.3 * length(r) * rects; +// albedo[ix + iy * textureSize][0] = rd * (0.5 + sp.x) * 255; +// albedo[ix + iy * textureSize][1] = rd * (0.5 + sp.y) * 255; +// albedo[ix + iy * textureSize][2] = rd * (0.5 + sp.z) * 255; + +// albedo[ix + iy * textureSize][0] = length(res) * rects * 255; +// albedo[ix + iy * textureSize][1] = length(res) * rects * 255; +// albedo[ix + iy * textureSize][2] = length(res) * rects * 255; + +// diff[ix + iy * ntex][0] = r.x * rects * 200; +// diff[ix + iy * ntex][1] = -r.z * rects * 200; +// diff[ix + iy * ntex][2] = 0; + +// diff[ix + iy * ntex][0] = 128 + (res.x - 0.5) * 200; +// diff[ix + iy * ntex][1] = 128 + (res.y - 0.5) * 200; +// diff[ix + iy * ntex][2] = 0; //res.z * 255; + + } + //} + } + rx++; + if (rx >= rects) { + rx = 0; + ry++; + } + + } +// +// for (int ix = 0; ix < ntex; ix++) { +// for (int iy = 0; iy < ntex; iy++) { +// +// float v = (float) noise.octaveNoise0_1(ix * texf * frequency, +// iy * texf * frequency, 0.5 * frequency, 4); +// diff[ix + (ntex - iy) * ntex] = 5 + v * 250; +// } +// } + stbi_write_png("albedo.png", textureSize, textureSize, 3, albedo.data(), 0); +} diff --git a/src/TextureMapper.h b/src/TextureMapper.h index 36484e5..75bc0ba 100644 --- a/src/TextureMapper.h +++ b/src/TextureMapper.h @@ -1,201 +1,38 @@ -#ifndef SRC_TEXTUREMAPPER_H_ -#define SRC_TEXTUREMAPPER_H_ +#pragma once + +#include "Density.h" #include #include class TextureMapper { -public: - typedef std::vector texture3_t; - typedef std::vector texture1_t; - texture3_t diffuse; - texture3_t normal; - texture1_t roughness; size_t textureSize; - TextureMapper(size_t textureSize) : - textureSize(textureSize), diffuse(textureSize * textureSize), normal( - textureSize * textureSize), roughness( - textureSize * textureSize) { +public: + typedef std::vector< glm::tvec3 > texture3_t; + typedef std::vector texture1_t; + typedef std::vector vec3v_t; + typedef std::vector vec2v_t; + typedef std::vector uvec3v_t; - } + Density &density; - void map() { - cout << "Stage4: UV map" << endl; - TriMesh mappedMesh; - float texf = 1. / texture_size; + texture3_t albedo; + texture3_t normal; + texture1_t roughness; + texture1_t metalness; - mesh.request_vertex_normals(); - mesh.request_face_normals(); - mesh.update_face_normals(); - mesh.update_vertex_normals(); - int rects = ceil(sqrt(mesh.n_faces())), rx = 0, ry = 0; - float rectSize = floor(float(texture_size) / rects) / texture_size; - size_t nfaces = mesh.n_faces(), iface = 0; - for (auto i = mesh.faces_begin(); i != mesh.faces_end(); i++) { - if (show_progress) - (cout << "\r " << int(100. * float(iface++) / nfaces) << "%").flush(); + vec3v_t vertices; + vec3v_t normals; + vec2v_t texcoords; + uvec3v_t indices; - vec3 p[3], n[3]; - int k = 0; - TriMesh::VertexHandle h[3]; - for (auto j = mesh.fv_begin(*i); j != mesh.fv_end(*i); j++) { - if (!j->is_valid()) - cout << "invalid vertex" << endl; - TriMesh::Point pt = mesh.point(*j); - p[k] = vec3(pt[0], pt[1], pt[2]); - TriMesh::Normal nm = mesh.calc_vertex_normal(*j); - n[k] = vec3(nm[0], nm[1], nm[2]); - h[k] = mappedMesh.add_vertex(pt); - mappedMesh.set_normal(h[k], nm); - k++; - if (k > 3) - cout << "not a triangle!" << endl; - } - mappedMesh.add_face(h, 3); + glm::vec3 darkestColor, brightestColor; - vec3 ex = normalize(p[1] - p[0]); - vec3 ey = normalize(cross(ex, p[2] - p[0])); - vec3 ez = normalize(cross(ex, ey)); - mat3 base = mat3(ex, ey, ez); - vec3 t[3] = { p[0] * base, p[1] * base, p[2] * base }; - vec3 lower = min(min(t[0], t[1]), t[2]); - vec3 upper = max(max(t[0], t[1]), t[2]); - t[0] -= lower; - t[1] -= lower; - t[2] -= lower; - vec3 extent = upper - lower; - float s = std::max(std::max(extent.x, extent.y), extent.z); - t[0] *= 0.8 * rectSize / s; - t[1] *= 0.8 * rectSize / s; - t[2] *= 0.8 * rectSize / s; - vec3 off(rx * rectSize, 0, ry * rectSize); - t[0] += off; - t[1] += off; - t[2] += off; - mappedMesh.set_texcoord2D(h[0], - TriMesh::TexCoord2D(t[0].x, t[0].z)); - mappedMesh.set_texcoord2D(h[1], - TriMesh::TexCoord2D(t[1].x, t[1].z)); - mappedMesh.set_texcoord2D(h[2], - TriMesh::TexCoord2D(t[2].x, t[2].z)); + TextureMapper(Density &density, size_t textureSize); - //if (rx == 0 && ry == 0) { - t[0].y = 0; - t[1].y = 0; - t[2].y = 0; -// cout << "ftex " << texf << endl; -// cout << "t[0] " << t[0].x << " " << t[0].z << endl; -// cout << "t[1] " << t[1].x << " " << t[1].z << endl; -// cout << "t[2] " << t[2].x << " " << t[2].z << endl; -// cout << "t[0]p " << t[0].x * ntex << " " << (1 - t[0].z) * ntex << endl; -// cout << "t[1]p " << t[1].x * ntex << " " << (1 - t[1].z) * ntex << endl; -// cout << "t[2]p " << t[2].x * ntex << " " << (1 - t[2].z) * ntex << endl; - // fill texture - // fill whole rect for now - int rpix = floor(rectSize * texture_size); - - vec3 eb = t[1] - t[0]; - float leb = length(eb); - vec3 ec = t[2] - t[0]; - float lec = length(ec); -// mat2 textureBase = mat2(vec2(eb.x, eb.z), vec2(ec.x, ec.z)); -// mat2 itextureBase = inverse(textureBase); - mat3 textureBase = mat3(eb, cross(eb, ec), ec); - mat3 itextureBase = inverse(textureBase); - -// eb = normalize(eb); -// ec = normalize(ec); - - vec3 db = p[1] - p[0]; - vec3 dc = p[2] - p[0]; - - vec3 mb = normalize(p[1] - p[0]); - vec3 mc = normalize(p[2] - p[0]); -// mat2 faceBase = mat2(vec2(mb.x, mb.z), vec2(mc.x, mc.z)); -// mat2 ifaceBase = inverse(faceBase); - - mat3 faceBase = mat3(db, cross(db, dc), dc); - mat3 ifaceBase = inverse(faceBase); - - // mat2 trafo = ifaceBase * textureBase * faceBase; - - for (int ix = rx * rpix; ix < (rx + 1) * rpix; ix++) { - for (int iy = (texture_size - (ry + 1) * rpix); - iy < (texture_size - ry * rpix); iy++) { - -// cout << "pix " << ix << " " << iy << endl; -// cout << "uv " << float(ix) * texf << " " << 1.f - float(iy) * texf << endl; - - // pixel to uv space - vec3 res = vec3(float(ix) * texf, 0.f, - 1.f - float(iy) * texf) - t[0]; - // cout << "r = " << r.x << " " << r.y << endl; - res = faceBase * itextureBase * res; - - // cout << "res = " << res.x << " " << res.y << endl; -// vec2 res = ifaceBase * textureBase * r * faceBase; - // -// cout << "pix " << ix << " " << res.x << " " << res.y << " " << res.z << endl; -// float fb = dot(r, eb) / leb; -// float fc = dot(r, ec) / lec; - vec3 sp = p[0] + res; //res.x * mb + res.y * mc; - float v = (float) noise.octaveNoise0_1(sp.x * frequency * 4, - sp.y * frequency * 4, sp.z * frequency * 4, 8); -// - v = pow(v, 3); - // default color - float r = 0.12 + v * 0.72, g = 0.1 + 0.7 * v, b = 0.1 - + 0.7 * v; - - diff[ix + iy * texture_size][0] = r * 255; - diff[ix + iy * texture_size][1] = g * 255; - diff[ix + iy * texture_size][2] = b * 255; - -// diff[ix + iy * ntex] = v * 255; -// diff[ix + iy * ntex][0] = (32 * rx) % 255; -// diff[ix + iy * ntex][1] = (32 * ry) % 255; -// diff[ix + iy * ntex][2] = 0; //(0.5 + sp.z) * 255; - -// float rd = 1.f; //0.7 + 0.3 * length(r) * rects; -// diff[ix + iy * ntex][0] = rd * (0.5 + sp.x) * 255; -// diff[ix + iy * ntex][1] = rd * (0.5 + sp.y) * 255; -// diff[ix + iy * ntex][2] = rd * (0.5 + sp.z) * 255; - -// diff[ix + iy * ntex][0] = length(r) * rects * 255; -// diff[ix + iy * ntex][1] = length(r) * rects * 255; -// diff[ix + iy * ntex][2] = length(r) * rects * 255; - -// diff[ix + iy * ntex][0] = r.x * rects * 200; -// diff[ix + iy * ntex][1] = -r.z * rects * 200; -// diff[ix + iy * ntex][2] = 0; - -// diff[ix + iy * ntex][0] = 128 + (res.x - 0.5) * 200; -// diff[ix + iy * ntex][1] = 128 + (res.y - 0.5) * 200; -// diff[ix + iy * ntex][2] = 0; //res.z * 255; - - } - //} - } - rx++; - if (rx >= rects) { - rx = 0; - ry++; - } - - } -// -// for (int ix = 0; ix < ntex; ix++) { -// for (int iy = 0; iy < ntex; iy++) { -// -// float v = (float) noise.octaveNoise0_1(ix * texf * frequency, -// iy * texf * frequency, 0.5 * frequency, 4); -// diff[ix + (ntex - iy) * ntex] = 5 + v * 250; -// } -// } - stbi_write_bmp("diffuse.bmp", texture_size, texture_size, 3, - diff.data()); - } + void setTextureSize(size_t size); + size_t getTextureSize(); + void map(const vec3v_t &inVertices, const vec3v_t &inNormals, + const uvec3v_t &inIndices); }; - -#endif /* SRC_TEXTUREMAPPER_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 114346f..aed13b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,385 +1,7 @@ -#include "Density.h" -#include "Polygoniser.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -static bool glck(const char* call) { - int err = glGetError(); - if (err == 0) { - return true; - } else { - switch (err) { - case GL_INVALID_VALUE: - printf("GL_INVALID_VALUE: %s\n", call); - break; - case GL_INVALID_ENUM: - printf("GL_INVALID_ENUM: %s\n", call); - break; - case GL_INVALID_OPERATION: - printf("GL_INVALID_OPERATION: %s\n", call); - break; - default: - printf("UNKNOWN Error: %s\n", call); - } - return false; - } -} - -#define GLCK(a) {a; assert(glck(#a));} - -// ! https://learnopengl.com/#!PBR/Lighting - -static const char* vertex_shader_text = "#version 130\n" - "uniform mat4 MVP;\n" - "in vec3 vPos;\n" - "in vec3 vNorm;\n" - "out vec3 normal;\n" - "void main()\n" - "{\n" - " gl_Position = MVP * vec4(vPos, 1.0);\n" - " normal = normalize(vNorm);\n" - "}\n"; - -static const char* fragment_shader_text = "#version 130\n" - "in vec3 normal;\n" - "out vec4 color;\n" - "void main()\n" - "{\n" - " color = normal.y * vec4(1.0, 0.95, 0.9, 1.0);\n" - "}\n"; -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) { - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GLFW_TRUE); -} - -void checkShader(GLuint vertexShader, const std::string &name) { - GLint status; - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); - - if (status == GL_FALSE) { - - std::cout << "Shader '" << name << "' compiled with an error(s):" - << std::endl; - char buffer[512]; - int l; - glGetShaderInfoLog(vertexShader, 512, &l, buffer); - buffer[l] = 0; - std::cout << buffer << std::endl; - } -} - -void checkProgam(GLuint vertexShader, const std::string &name) { - GLint status; - glGetProgramiv(vertexShader, GL_LINK_STATUS, &status); - - if (status == GL_FALSE) { - - std::cout << "Program '" << name << "' failed with an error(s):" - << std::endl; - char buffer[512]; - int l; - glGetProgramInfoLog(vertexShader, 512, &l, buffer); - buffer[l] = 0; - std::cout << buffer << std::endl; - } -} - -void calculateNormals(const std::vector &vtx, - std::vector &tri, std::vector &normals) { - normals.clear(); - normals.resize(vtx.size(), glm::vec3(0)); - for (size_t i = 0; i < tri.size(); i++) { - int a = tri[i].x, b = tri[i].y, c = tri[i].z; - glm::vec3 faceNormal = normalize( - glm::cross(vtx[b] - vtx[a], vtx[c] - vtx[a])); - normals[a] += faceNormal; - normals[b] += faceNormal; - normals[c] += faceNormal; - } - for (size_t i = 0; i < normals.size(); i++) - normals[i] = glm::normalize(normals[i]); - -} - -void moveToMean(std::vector &vtx) { - glm::vec3 mean(0); - for (size_t i = 0; i < vtx.size(); i++) { - mean += vtx[i]; - } - mean *= glm::vec3(1.f / vtx.size()); - for (size_t i = 0; i < vtx.size(); i++) { - vtx[i] -= mean; - } -} - -void smooth(std::vector &vtx, const std::vector &tri) { - std::vector cogs(vtx.size(), glm::vec3(0.f)); - std::vector valence(vtx.size(), 0); - - for (size_t iTri = 0; iTri < tri.size(); iTri++) { - const glm::uvec3 &idx = tri[iTri]; - for (size_t iE = 0; iE < 3; iE++) { - valence[idx[iE]] += 2; - cogs[idx[iE]] += vtx[idx[(iE + 1) % 3]]; - cogs[idx[iE]] += vtx[idx[(iE + 2) % 3]]; - } - } - /* - for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) { - cog[0] = cog[1] = cog[2] = valence = 0.0; - - for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) { - cog += mesh.point(*vv_it); - ++valence; - } - cogs.push_back(cog / valence); - } - for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); v_it != v_end; - ++v_it, ++cog_it) - if (!mesh.is_boundary(*v_it)) - mesh.set_point(*v_it, *cog_it); - - */ - for (size_t i = 0; i < vtx.size(); i++) { -// vtx[i] = vtx[i] * glm::vec3(0.8) -// + cogs[i] * glm::vec3(0.2f / valence[i]); - vtx[i] = cogs[i] * glm::vec3(1.f / valence[i]); - } -} - -void saveAttrib(std::ostream &out, const char *prefix, - std::vector &elements) { - for (size_t i = 0; i < elements.size(); i++) { - out << prefix << elements[i].x << " " << elements[i].y << " " << elements[i].z - << "\n"; - } -} - -void saveAttrib(std::ostream &out, const char *prefix, - std::vector &elements) { - for (size_t i = 0; i < elements.size(); i++) { - out << prefix << elements[i].x << " " << elements[i].y << "\n"; - } -} - -void saveFaces(std::ostream &out, const std::vector &tris, size_t attribs) { - for (size_t i = 0; i < tris.size(); i++) { - out << "f"; - - for (size_t j = 0; j < 3; j++) { - int v = tris[i][j] + 1; - out << " " << v; - if (attribs > 1) - out << "/" << v; - if (attribs > 2) - out << "/" << v; - out << " "; - } - - out << "\n"; - } -} - -void calculateEdges(const std::vector &vtx, - std::vector &tri, std::vector &edges) { - edges.clear(); -} +#include "Application.h" int main(void) { - std::srand(123); + Application::instance().run(); - Density density; - density.addRandomImpacts(1000, 0.2, 0.01, 0.005, 0.2, 4096); - //density.saveCrossSection("density.png", 512); - - Polygonizer polygonizer(density); - polygonizer.polygonize(0.2, 1. / 20.); - - moveToMean(polygonizer.vertices); - { - std::ofstream out("stage1.obj"); - saveAttrib(out, "v ", polygonizer.vertices); - saveFaces(out, polygonizer.triangles, 1); - } - smooth(polygonizer.vertices, polygonizer.triangles); - { - std::ofstream out("stage2.obj"); - saveAttrib(out, "v ", polygonizer.vertices); - saveFaces(out, polygonizer.triangles, 1); - } - std::vector normals; - calculateNormals(polygonizer.vertices, polygonizer.triangles, normals); - { - std::ofstream out("stage3.obj"); - saveAttrib(out, "v ", polygonizer.vertices); - saveAttrib(out, "vn ", normals); - saveFaces(out, polygonizer.triangles, 2); - } - - std::vector edges; - std::cout << "Vertices: " << polygonizer.vertices.size() << std::endl; - std::cout << "Triangles: " << polygonizer.triangles.size() << std::endl; - - GLFWwindow* window; - GLuint vertex_array, vertex_buffer, index_buffer, normal_buffer, - vertex_shader, fragment_shader, program; - GLint mvp_location, vpos_location, vnorm_location; - - glfwSetErrorCallback(error_callback); - - if (!glfwInit()) - exit(EXIT_FAILURE); - -// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - - window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL); - if (!window) { - glfwTerminate(); - exit(EXIT_FAILURE); - } - - glfwSetKeyCallback(window, key_callback); - - glfwMakeContextCurrent(window); - gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); - glfwSwapInterval(1); - - std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; - std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) - << std::endl; - std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl; - std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl; - - // NOTE: OpenGL error checks have been omitted for brevity - -// glGenBuffers(1, &vertex_buffer); -// glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); -// glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - GLCK(glGenVertexArrays(1, &vertex_array)) - GLCK(glBindVertexArray(vertex_array)) - - GLCK(glGenBuffers(1, &vertex_buffer)) - GLCK(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)) - GLCK( - glBufferData(GL_ARRAY_BUFFER, polygonizer.vertices.size() * sizeof(glm::vec3), polygonizer.vertices.data(), GL_STATIC_DRAW)) - - GLCK(glGenBuffers(1, &index_buffer)) - GLCK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer)) - GLCK( - glBufferData(GL_ELEMENT_ARRAY_BUFFER, polygonizer.triangles.size() * sizeof(glm::uvec3), polygonizer.triangles.data(), GL_STATIC_DRAW)) - - GLCK(glGenBuffers(1, &normal_buffer)) - GLCK(glBindBuffer(GL_ARRAY_BUFFER, normal_buffer)) - GLCK( - glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW)) - - GLCK(vertex_shader = glCreateShader(GL_VERTEX_SHADER)) - GLCK(glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL)) - GLCK(glCompileShader(vertex_shader)) - checkShader(vertex_shader, "vertex"); - - GLCK(fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)) - GLCK(glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL)) - GLCK(glCompileShader(fragment_shader)) - checkShader(fragment_shader, "fragment"); - - GLCK(program = glCreateProgram()) - GLCK(glAttachShader(program, vertex_shader)) - GLCK(glAttachShader(program, fragment_shader)) - GLCK(glLinkProgram(program)) - checkProgam(program, "program"); - - GLCK(mvp_location = glGetUniformLocation(program, "MVP")) - std::cout << mvp_location << std::endl; - - GLCK(vpos_location = glGetAttribLocation(program, "vPos")) - std::cout << vpos_location << std::endl; - - GLCK(vnorm_location = glGetAttribLocation(program, "vNorm")) - std::cout << vnorm_location << std::endl; - - GLCK(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)) - glEnableVertexAttribArray(vpos_location); - GLCK( - glVertexAttribPointer(vpos_location, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0)) - - if (vnorm_location >= 0) { - GLCK(glBindBuffer(GL_ARRAY_BUFFER, normal_buffer)) - GLCK(glEnableVertexAttribArray(vnorm_location)) - GLCK( - glVertexAttribPointer(vnorm_location, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0)) - } - - ImGui_ImplGlfwGL3_Init(window, true); - - while (!glfwWindowShouldClose(window)) { - glfwPollEvents(); - ImGui_ImplGlfwGL3_NewFrame(); - { - static float f = 0.0f; - static float resolution = 0.1f; - ImGui::Text("Hello, world!"); - if (ImGui::Button("Wireframe")) - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); - if (ImGui::Button("Fill")) - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); - ImGui::InputFloat("Resolution", &resolution); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, - ImGui::GetIO().Framerate); - } - int width, height; - glm::mat4 m(1.0f), p, mvp(2); - - glfwGetFramebufferSize(window, &width, &height); - float ratio = width / (float) height; - - glViewport(0, 0, width, height); - glClear(GL_COLOR_BUFFER_BIT); - - m = glm::rotate(m, (float) glfwGetTime(), glm::vec3(0.f, 0.f, 1.f)); - //m = glm::translate(m, glm::vec3(-1.f)); - //glm::translate(mvp, glm::vec3((float) glfwGetTime())); - p = glm::ortho(-1.f, 1.f, -1.f, 1.f); - mvp = p * m; - - GLCK(glUseProgram(program)) - GLCK( - glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) &mvp)) - - // Draw the triangles ! - GLCK(glBindVertexArray(vertex_array)) - glDrawElements( GL_TRIANGLES, polygonizer.triangles.size() * 3, - GL_UNSIGNED_INT, (void*) 0); - //GLCK(glDrawArrays( GL_TRIANGLES, 0, polygonizer.triangles.size() * 3)) - ImGui::Render(); - glfwSwapBuffers(window); - - } - - glfwDestroyWindow(window); - - ImGui_ImplGlfwGL3_Shutdown(); - - glfwTerminate(); }