big update
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										21
									
								
								ToDo.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								ToDo.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
							
								
								
									
										64
									
								
								shader/standard.fragment.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								shader/standard.fragment.glsl
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										44
									
								
								shader/standard.vertex.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								shader/standard.vertex.glsl
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										736
									
								
								src/Application.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										736
									
								
								src/Application.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,736 @@ | ||||
| #include "Application.h" | ||||
|  | ||||
| #include <glad/glad.h> | ||||
| #include <GLFW/glfw3.h> | ||||
|  | ||||
| #include <glm/mat4x4.hpp> | ||||
| #include <glm/mat3x3.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| #include <imgui.h> | ||||
| #include <imgui_impl_glfw_gl3.h> | ||||
|  | ||||
| #include <stb_image.h> | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <map> | ||||
| #include <vector> | ||||
|  | ||||
| using glm::vec3; | ||||
| using glm::uvec3; | ||||
| using std::map; | ||||
| using std::vector; | ||||
|  | ||||
| void calculateNormals(const vector<vec3> &vtx, vector<uvec3> &tri, | ||||
| 		vector<vec3> &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<vec3> &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<vec3> &vtx, const vector<uvec3> &tri) { | ||||
| 	vector<vec3> cogs(vtx.size(), vec3(0.f)); | ||||
| 	vector<int> 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<vec3> &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<glm::vec2> &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<uvec3> &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<vec3> &vtx, vector<uvec3> &tri, | ||||
| 		vector<glm::uvec4> &edges) { | ||||
| 	edges.clear(); | ||||
| 	map<std::pair<uint32_t, uint32_t>, 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<vec3> & vertices, vector<glm::vec2> & uvs, | ||||
| 		vector<vec3> & normals, vector<vec3> & tangents, | ||||
| 		vector<vec3> & 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<glm::uvec4> 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<char> 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<char> 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<char> 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); | ||||
|  | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										89
									
								
								src/Application.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/Application.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Density.h" | ||||
| #include "Polygoniser.h" | ||||
| #include "TextureMapper.h" | ||||
|  | ||||
| #include <glm/mat4x4.hpp> | ||||
| #include <glm/vec3.hpp> | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| 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<glm::vec3> vertices; | ||||
| 	std::vector<glm::vec3> normals; | ||||
| 	std::vector<glm::vec2> texcoords; | ||||
| 	std::vector<glm::uvec3> 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(); | ||||
| }; | ||||
| @@ -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<Impact> &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; | ||||
|   | ||||
							
								
								
									
										199
									
								
								src/Polygoniser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								src/Polygoniser.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| #include "Polygoniser.h" | ||||
|  | ||||
| #include <functional> | ||||
| #include <map> | ||||
|  | ||||
| #include <glm/gtc/epsilon.hpp> | ||||
|  | ||||
| #include <MarchingCube.h> | ||||
|  | ||||
| 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<glm::vec3, int>::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<glm::vec3, int>::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); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -1,14 +1,9 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <functional> | ||||
| #include <vector> | ||||
| #include <map> | ||||
|  | ||||
| #include <glm/vec3.hpp> | ||||
| #include <glm/gtc/epsilon.hpp> | ||||
|  | ||||
| #include <MarchingCube.h> | ||||
| #include <logger.h> | ||||
|  | ||||
| #include "Density.h" | ||||
|  | ||||
| @@ -39,79 +34,22 @@ struct CompareVec3 { | ||||
| }; | ||||
|  | ||||
| class Polygonizer { | ||||
| 	Density &density; | ||||
| 	float isolevel; | ||||
| public: | ||||
| 	std::vector<glm::vec3> vertices; | ||||
| 	std::vector<glm::uvec3> triangles; | ||||
| 	std::vector<glm::uvec3> indices; | ||||
| 	std::map<glm::vec3, int, CompareVec3> vertexLookup; | ||||
|  | ||||
| 	Density &density; | ||||
| 	std::vector<bool> 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<glm::vec3, int, CompareVec3> 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<glm::vec3, int>::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); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										205
									
								
								src/TextureMapper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								src/TextureMapper.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | ||||
| #include "TextureMapper.h" | ||||
|  | ||||
| #include <glm/mat3x3.hpp> | ||||
|  | ||||
| #include "stb_image_write.h" | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| 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); | ||||
| } | ||||
| @@ -1,201 +1,38 @@ | ||||
| #ifndef SRC_TEXTUREMAPPER_H_ | ||||
| #define SRC_TEXTUREMAPPER_H_ | ||||
| #pragma once | ||||
|  | ||||
| #include "Density.h" | ||||
|  | ||||
| #include <vector> | ||||
| #include <glm/vec3.hpp> | ||||
|  | ||||
| class TextureMapper { | ||||
| public: | ||||
| 	typedef std::vector<glm::uint8[3]> texture3_t; | ||||
| 	typedef std::vector<uint8_t> 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<uint8_t> > texture3_t; | ||||
| 	typedef std::vector<uint8_t> texture1_t; | ||||
| 	typedef std::vector<glm::vec3> vec3v_t; | ||||
| 	typedef std::vector<glm::vec2> vec2v_t; | ||||
| 	typedef std::vector<glm::uvec3> 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_ */ | ||||
|   | ||||
							
								
								
									
										382
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										382
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -1,385 +1,7 @@ | ||||
| #include "Density.h" | ||||
| #include "Polygoniser.h" | ||||
|  | ||||
| #include <glad/glad.h> | ||||
| #include <GLFW/glfw3.h> | ||||
| #include <glm/mat4x4.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <imgui.h> | ||||
| #include <imgui_impl_glfw_gl3.h> | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| 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<glm::vec3> &vtx, | ||||
| 		std::vector<glm::uvec3> &tri, std::vector<glm::vec3> &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<glm::vec3> &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<glm::vec3> &vtx, const std::vector<glm::uvec3> &tri) { | ||||
| 	std::vector<glm::vec3> cogs(vtx.size(), glm::vec3(0.f)); | ||||
| 	std::vector<int> 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<glm::vec3> &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<glm::vec2> &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<glm::uvec3> &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<glm::vec3> &vtx, | ||||
| 		std::vector<glm::uvec3> &tri, std::vector<glm::vec4> &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<glm::vec3> 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<glm::uvec4> 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(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user