Exemple #1
0
void Octree::constructOctree(int depth)
{
	//1. bounding box generation
	Vec3f leftDown(MAX, MAX, MAX);
	Vec3f rightUp(MIN, MIN, MIN);
	Vec3f mid;

	for(int i=0;i<NbNode;i++)
	{
		for(int j=0;j<3;j++)
		{
			if(leftDown[j]>(*Node)[i][j])
				leftDown[j]=(*Node)[i][j];
			if(rightUp[j]<(*Node)[i][j])
				rightUp[j]=(*Node)[i][j];
		}
	}
	mid=(rightUp+leftDown)/2.0;

	//2. Root node
	Root=new OctreeNode;
	Root->setBoundingBox(leftDown, rightUp);
	Root->Depth=0;

	//3. Descendant
	OctreeNode** descendant=new OctreeNode*[8];
	for(int i=0;i<8;i++)
	{
		descendant[i]=new OctreeNode;
		descendant[i]->Depth=Root->Depth+1;
		Root->Descendant[i]=descendant[i];
	}

	//4. Descendant generation
	std::vector<int> nodeIdx[8];
	for(int i=0;i<NbNode;i++)
	{
		if((*Node)[i][0]>mid[0])
		{
			if((*Node)[i][1]>mid[1])
			{
				if((*Node)[i][2]>mid[2])
				{
					//RightTopFront
					nodeIdx[0].push_back(i);
				}
				else
				{
					//RightTopBehind
					nodeIdx[1].push_back(i);
				}
			}
			else
			{
				if((*Node)[i][2]>mid[2])
				{
					//RightBottomFront
					nodeIdx[2].push_back(i);
				}
				else
				{
					//RightBottomBehind
					nodeIdx[3].push_back(i);
				}
			}
		}
		else
		{
			if((*Node)[i][1]>mid[1])
			{
				if((*Node)[i][2]>mid[2])
				{
					//LeftTopFront
					nodeIdx[4].push_back(i);
				}
				else
				{
					//LeftTopBehind
					nodeIdx[5].push_back(i);
				}
			}
			else
			{
				if((*Node)[i][2]>mid[2])
				{
					//LeftBottomFront
					nodeIdx[6].push_back(i);
				}
				else
				{
					//LeftBottomBehind
					nodeIdx[7].push_back(i);
				}
			}
		}
	}

	//RightTopFront
	Vec3f p1=mid;
	Vec3f p2=rightUp;
	genOctree(descendant[0], p1, p2, nodeIdx[0], depth);  

	//RightTopBehind
	p1=Vec3f(mid[0], mid[1], leftDown[2]);
	p2=Vec3f(rightUp[0], rightUp[1], mid[2]);
	genOctree(descendant[1], p1, p2, nodeIdx[1], depth);  

	//RightBottomFront
	p1=Vec3f(mid[0], leftDown[1], mid[2]);
	p2=Vec3f(rightUp[0], mid[1], rightUp[2]) ;
	genOctree(descendant[2], p1, p2, nodeIdx[2], depth);

	//RightBottomBehind
	p1=Vec3f(mid[0],leftDown[1],leftDown[2]);
	p2=Vec3f(rightUp[0], mid[1], mid[2]);
	genOctree(descendant[3], p1, p2, nodeIdx[3], depth);

	//LeftTopFront
	p1=Vec3d(leftDown[0], mid[1], mid[2]);
	p2=Vec3d(mid[0], rightUp[1], rightUp[2]);
	genOctree(descendant[4], p1, p2, nodeIdx[4], depth);

	//LeftTopBehind
	p1=Vec3f(leftDown[0], mid[1], leftDown[2]);
	p2=Vec3f(mid[0], rightUp[1], mid[2]);
	genOctree(descendant[5], p1, p2, nodeIdx[5], depth);

	//LeftBottomFront
	p1=Vec3f(leftDown[0], leftDown[1], mid[2]);
	p2=Vec3f(mid[0], mid[1], rightUp[2]);
	genOctree(descendant[6], p1, p2, nodeIdx[6], depth);

	//LeftBottomBehind
	p1=leftDown;
	p2=(leftDown+rightUp)/2.0;
	genOctree(descendant[7], p1, p2, nodeIdx[7], depth);

	delete [] descendant;
}
	void VolumeRender::generate()
	{
		double start_time, end_time, dt;

		start_time = glfwGetTime();

		// Load tree
		int32_t tree_size = 0;
		tree_data = 0;
		
		// Load from file
		if (_scene == 0)
		{
			tree_size = rendering::read_full_file_binary(_treeFilename, &tree_data);

			if (tree_size == 0)
			{
				fprintf(stderr, "Invalid tree file: %s\n", _treeFilename);
				exit(1);
			}
		}
		else
		{
			char filename_buffer[1024];
			sprintf(filename_buffer, "scene%d.tree.%d", _scene, _depth);

			FILE* file = fopen(filename_buffer, "rb");

			if (file != nullptr)
			{
				// Load tree
				printf("Loading file %s\n", filename_buffer);
				fclose(file);

				tree_size = rendering::read_full_file_binary(filename_buffer, &tree_data);

				if (tree_size == 0)
				{
					fprintf(stderr, "Invalid tree file: %s\n", filename_buffer);
					exit(1);
				}
			}
			else
			{
				// Generate
				printf("Generating scene for the first time, please wait..\n");

				// Generate from sphere
				if (_scene == 1)
				{
					tree_size =
						rendering::genOctreeSphere((int32_t**)&tree_data, _depth,
						glm::vec3(0.5f, 0.5f, 0.5f), 0.4f);
				}

				// Generate from miku mesh
				if (_scene == 2)
				{
					if (_mesh.load("miku.md2"))
					{
						// Rotate mesh to right rotation (md2s are messed up like that..)
						glm::mat4 rotation = glm::rotate(180.0f, glm::vec3(0, 0, 1.0f));
						rotation = glm::rotate(rotation, 90.0f, glm::vec3(0, 1.0f, 0));
						_mesh.transform(rotation);

						tree_size = genOctreeMesh((int32_t**)&tree_data, _depth, &_mesh);
					}
				}

				// r = 1.5 sphere with embedded r = 1 sphere
				if (_scene == 3)
				{
					if (_mesh.load("miku.md2"))
					{
						// Rotate mesh to right rotation (md2s are messed up like that..)
						glm::mat4 rotation = glm::rotate(180.0f, glm::vec3(0, 0, 1.0f));
						rotation = glm::rotate(rotation, 90.0f, glm::vec3(0, 1.0f, 0));
						_mesh.transform(rotation);
			
						// Get min, max and func for octree generation
						glm::vec3 overall_min = *_mesh.getMin();
						glm::vec3 overall_max = *_mesh.getMax();
						overall_max += (overall_max - overall_min);

						// Make cube around bounds
						glm::vec3 extents = (overall_max - overall_min) * 0.5f;
						glm::vec3 centre = overall_min + extents;

						float greatest_extent = std::max(std::max(extents.x, extents.y), extents.z);
			
						extents.x = greatest_extent;
						extents.y = greatest_extent;
						extents.z = greatest_extent;
			
						overall_min = centre - extents;
						overall_max = centre + extents;

						// Sphere position
						glm::vec3 sphere_pos = centre;
						sphere_pos.x += extents.x * 0.5f;
						float sphere_radius = 10.0f;

						// Test function
						auto test_func = [&] (glm::vec3 min, glm::vec3 max, raw_attachment_uncompressed& shading_attributes)
						{
							glm::vec3 half_size = 0.5f * (max - min);
							glm::vec3 centre = min + half_size;
							float half_size_one_axis = half_size.x;

							//bool sphere_intersect = cubeSphereSurfaceIntersection(centre, half_size_one_axis, sphere_pos, sphere_radius);
							bool sphere_intersect = boxSphereIntersection(min, max, sphere_pos, sphere_radius);

							if (sphere_intersect)
							{
								// This is not normalised to save generation time
								// it is normalised later in the GPU anyway after being unpacked
								shading_attributes.normal = sphere_pos - centre;
								shading_attributes.colour = glm::vec4(1.0f, 1.0f, 1.0f, 0.5f);
								shading_attributes.reflectivity = 1.0f;

								shading_attributes.refractive_index = 1.5f;

								float distFromCentre = glm::length(shading_attributes.normal);

								if (distFromCentre < 0.5f * sphere_radius)
									shading_attributes.refractive_index = 1.0f;

								return true;
							}
							else
							{
								bool mesh_intersect = meshAABBIntersect(&_mesh, min, max, shading_attributes);

								if (mesh_intersect)
								{
									shading_attributes.colour.a = 1.0f;
									shading_attributes.reflectivity = 0.0f;
									return true;
								}
							}

							return false;
						};

						point_test_func func(test_func);

						// Generate octree
						tree_size = genOctree((int32_t**)&tree_data, _depth, func, overall_min, overall_max);
					}
				}

				// r = 1.5 sphere with hollow sphere (should be the same as above)
				if (_scene == 4)
				{
					if (_mesh.load("miku.md2"))
					{
						// Rotate mesh to right rotation (md2s are messed up like that..)
						glm::mat4 rotation = glm::rotate(180.0f, glm::vec3(0, 0, 1.0f));
						rotation = glm::rotate(rotation, 90.0f, glm::vec3(0, 1.0f, 0));
						_mesh.transform(rotation);
			
						// Get min, max and func for octree generation
						glm::vec3 overall_min = *_mesh.getMin();
						glm::vec3 overall_max = *_mesh.getMax();
						overall_max += (overall_max - overall_min);

						// Make cube around bounds
						glm::vec3 extents = (overall_max - overall_min) * 0.5f;
						glm::vec3 centre = overall_min + extents;

						float greatest_extent = std::max(std::max(extents.x, extents.y), extents.z);
			
						extents.x = greatest_extent;
						extents.y = greatest_extent;
						extents.z = greatest_extent;
			
						overall_min = centre - extents;
						overall_max = centre + extents;

						// Sphere position
						glm::vec3 sphere_pos = centre;
						sphere_pos.x += extents.x * 0.5f;
						float sphere_radius = 10.0f;

						// Test function
						auto test_func = [&] (glm::vec3 min, glm::vec3 max, raw_attachment_uncompressed& shading_attributes)
						{
							glm::vec3 half_size = 0.5f * (max - min);
							glm::vec3 centre = min + half_size;
							float half_size_one_axis = half_size.x;

							//bool sphere_intersect = cubeSphereSurfaceIntersection(centre, half_size_one_axis, sphere_pos, sphere_radius);
							bool sphere_intersect = boxSphereIntersection(min, max, sphere_pos, sphere_radius);

							if (sphere_intersect)
							{
								// This is not normalised to save generation time
								// it is normalised later in the GPU anyway after being unpacked
								shading_attributes.normal = sphere_pos - centre;
								shading_attributes.colour = glm::vec4(1.0f, 1.0f, 1.0f, 0.5f);
								shading_attributes.reflectivity = 1.0f;

								shading_attributes.refractive_index = 1.5f;

								float distFromCentre = glm::length(shading_attributes.normal);

								if (distFromCentre < 0.5f * sphere_radius)
									return false;


								return true;
							}
							else
							{
								bool mesh_intersect = meshAABBIntersect(&_mesh, min, max, shading_attributes);

								if (mesh_intersect)
								{
									shading_attributes.colour.a = 1.0f;
									shading_attributes.reflectivity = 0.0f;
									return true;
								}
							}

							return false;
						};

						point_test_func func(test_func);

						// Generate octree
						tree_size = genOctree((int32_t**)&tree_data, _depth, func, overall_min, overall_max);
					}
				}

				// Generate from mesh
				if (_scene == 5)
				{
					Mesh teapot("teapot.obj", true);
					Mesh checkerboard("checkerboard.obj", true);
					
					// Lift teapot off checkerboard a bit so they don't intersect
					glm::mat4 translation = glm::translate(glm::vec3(0.0f, 0.1f, 0.0f));
					glm::mat4 rotation = glm::rotate(180.0f, glm::vec3(0, 0, 1.0f));
					checkerboard.transform(translation * rotation);

					teapot.transform(rotation);
			
					// Get min, max and func for octree generation
					glm::vec3 overall_min = *teapot.getMin();
					glm::vec3 overall_max = *teapot.getMax();
					overall_max += (overall_max - overall_min);

					// Make cube around bounds
					glm::vec3 extents = (overall_max - overall_min) * 0.5f;
					glm::vec3 centre = overall_min + extents;

					float greatest_extent = std::max(std::max(extents.x, extents.y), extents.z);
			
					extents.x = greatest_extent;
					extents.y = greatest_extent;
					extents.z = greatest_extent;
			
					overall_min = centre - extents;
					overall_max = centre + extents;

					// Test function
					auto test_func = [&] (glm::vec3 min, glm::vec3 max, raw_attachment_uncompressed& shading_attributes)
					{
						if (meshAABBIntersect(&checkerboard, min, max, shading_attributes))
						{
							shading_attributes.colour.a = 1.0f;
							shading_attributes.reflectivity = 0.0f;

							return true;
						}

						if (meshAABBIntersect(&teapot, min, max, shading_attributes))
						{
							shading_attributes.colour.a = 0.3f;
							shading_attributes.reflectivity = 0.5f;

							return true;
						}

						return false;
					};

					point_test_func func(test_func);

					// Generate octree
					tree_size = genOctree((int32_t**)&tree_data, _depth, func, overall_min, overall_max);
				}

				// transparent and reflective boxes on checkerboard
				if (_scene == 6)
				{
					Mesh checkerboard("checkerboard.obj", true);

					// The cube should have flat normals instead of smooth
					Mesh box1("cube.obj", true, aiProcess_GenNormals);
					Mesh box2("cube.obj", true, aiProcess_GenNormals);

					// Rotate checkerboard
					glm::mat4 rotation = glm::rotate(180.0f, glm::vec3(0, 0, 1.0f));
					checkerboard.transform(rotation);

					// Scale and position box
					glm::mat4 translation = glm::translate(glm::vec3(0, 1.0f, 0));
					glm::mat4 scale = glm::scale(glm::vec3(0.25f));
					glm::mat4 box_transform = scale * translation;
					box1.transform(scale);
					box2.transform(scale);
			
					// Get min, max and func for octree generation
					glm::vec3 overall_min = *checkerboard.getMin();
					glm::vec3 overall_max = *checkerboard.getMax();
					overall_max += (overall_max - overall_min);

					// Make cube around bounds
					glm::vec3 extents = (overall_max - overall_min) * 0.5f;
					glm::vec3 centre = overall_min + extents;

					float greatest_extent = std::max(std::max(extents.x, extents.y), extents.z);
			
					extents.x = greatest_extent;
					extents.y = greatest_extent;
					extents.z = greatest_extent;
			
					overall_min = centre - extents;
					overall_max = centre + extents;

					// Test function
					auto test_func = [&] (glm::vec3 min, glm::vec3 max, raw_attachment_uncompressed& shading_attributes)
					{
						if (meshAABBIntersect(&checkerboard, min, max, shading_attributes))
						{
							shading_attributes.colour.a = 1.0f;
							shading_attributes.reflectivity = 0.0f;

							return true;
						}

						if (meshAABBIntersect(&box1, min, max, shading_attributes))
						{
							shading_attributes.colour.a = 1.0f;
							shading_attributes.reflectivity = 1.0f;

							return true;
						}

						return false;
					};

					point_test_func func(test_func);

					// Generate octree
					tree_size = genOctree((int32_t**)&tree_data, _depth, func, overall_min, overall_max);
				}

				// Reflective inverted box with teapot inside
				if (_scene == 7)
				{
					// The cube should have flat normals instead of smooth
					Mesh teapot("teapot.obj", true);
					Mesh box1("inverted_cube.obj", true, aiProcess_GenNormals);

					teapot.transform(glm::scale(glm::vec3(0.2f)) * glm::rotate(180.0f, glm::vec3(0.0f, 0.0f, 1.0f)));
			
					// Get min, max and func for octree generation
					glm::vec3 overall_min = *box1.getMin();
					glm::vec3 overall_max = *box1.getMax();
					overall_max += (overall_max - overall_min);

					// Make cube around bounds
					glm::vec3 extents = (overall_max - overall_min) * 0.5f;
					glm::vec3 centre = overall_min + extents;

					float greatest_extent = std::max(std::max(extents.x, extents.y), extents.z);
			
					extents.x = greatest_extent;
					extents.y = greatest_extent;
					extents.z = greatest_extent;
			
					overall_min = centre - extents;
					overall_max = centre + extents;

					// Test function
					auto test_func = [&] (glm::vec3 min, glm::vec3 max, raw_attachment_uncompressed& shading_attributes)
					{
						glm::vec3 aabb_extents = (max - min) * 0.5f;
						glm::vec3 aabb_centre = aabb_centre + min;

						if (meshAABBIntersect(&box1, min, max, shading_attributes))
						{
							shading_attributes.colour.a = 1.0f;
							shading_attributes.reflectivity = 1.0f;

							return true;
						}

						if (meshAABBIntersect(&teapot, min, max, shading_attributes))
						{
							shading_attributes.colour = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
							shading_attributes.reflectivity = 0.0f;

							return true;
						}

						return false;
					};

					point_test_func func(test_func);

					// Generate octree
					tree_size = genOctree((int32_t**)&tree_data, _depth, func, overall_min, overall_max);
				}

				// Write custom generation to file
				if (_saveTrees)
				{
					printf("Writing %s...\n", filename_buffer);

					file = fopen(filename_buffer, "wb");

					if (file == nullptr)
					{
						fprintf(stderr, "Failed to open file for writing: %s\n", filename_buffer);
					}
					else
					{
						fwrite(tree_data, tree_size, sizeof(char), file);
						fclose(file);
					}
				}
			}
		}
		
		// Calculate time to load/generate
		end_time = glfwGetTime();
		dt = end_time - start_time;

		printf("Time to load/generate tree: %f\n", dt);
		printf("%.2fMB\n", tree_size / (1024.0f * 1024.0f));

		// Reset timer
		start_time = glfwGetTime();

		// Upload sphere to GPU
		gpuErrchk(cudaMalloc((void**)&_gpuTree, tree_size));
		gpuErrchk(cudaMemcpy(_gpuTree, tree_data, tree_size, cudaMemcpyHostToDevice));

		// Calculate time to upload
		end_time = glfwGetTime();
		dt = end_time - start_time;

		printf("Time to upload tree: %f\n", dt);
		printf("%.2fMB\n", tree_size / (1024.0f * 1024.0f));

		// Free CPU memory
		//free(tree_data);
	}
Exemple #3
0
int Octree::genOctree(OctreeNode* root, Vec3f& leftDown, Vec3f& rightUp, std::vector<int>& nodeIdx, int maxDepth)
{
	//1. Set bounding box
	root->setBoundingBox(leftDown, rightUp);

	//2. Stop if there is only one node in the box
	if(Mode==OCTREE_NORMAL)
	{
		if(nodeIdx.size()==0)
		{
			root->End=true;
			return 0;
		}
		if(root->Depth==maxDepth)
		{
			root->End=true;
			return 0;
		}
	}
	if(Mode==OCTREE_UNIFORM)
	{
		if(root->Depth==maxDepth)
		{
			root->End=true;
			return 0;
		}
	}
	if(Mode==OCTREE_MULTILEVEL)
	{
		if(root->Depth==maxDepth)
		{
			if(nodeIdx.size()==0)
			{
				root->End=true;
				return 0;
			}
		}
		if(root->Depth==(maxDepth+1))
		{
			root->End=true;
			return 0;
		}
	}

	//3. Descendant
	OctreeNode** descendant=new OctreeNode*[8];
	for(int i=0;i<8;i++)
	{
		descendant[i]=new OctreeNode;
		descendant[i]->Depth=root->Depth+1;
		root->Descendant[i]=descendant[i];
		if(nodeIdx.size()>0)
			descendant[i]->NodeIdx=1;
	}

	//4. Descendant generation
	Vec3f mid=(leftDown+rightUp)/2.0;
	std::vector<int> _nodeIdx[8];
	for(int i=0;i<nodeIdx.size();i++)
	{
		if((*Node)[nodeIdx[i]][0]>mid[0])
		{
			if((*Node)[nodeIdx[i]][1]>mid[1])
			{
				if((*Node)[nodeIdx[i]][2]>mid[2])
				{
					//RightTopFront
					_nodeIdx[0].push_back(nodeIdx[i]);
				}
				else
				{
					//RightTopBehind
					_nodeIdx[1].push_back(nodeIdx[i]);
				}
			}
			else
			{
				if((*Node)[nodeIdx[i]][2]>mid[2])
				{
					//RightBottomFront
					_nodeIdx[2].push_back(nodeIdx[i]);
				}
				else
				{
					//RightBottomBehind
					_nodeIdx[3].push_back(nodeIdx[i]);
				}
			}
		}
		else
		{
			if((*Node)[nodeIdx[i]][1]>mid[1])
			{
				if((*Node)[nodeIdx[i]][2]>mid[2])
				{
					//LeftTopFront
					_nodeIdx[4].push_back(nodeIdx[i]);
				}
				else
				{
					//LeftTopBehind
					_nodeIdx[5].push_back(nodeIdx[i]);
				}
			}
			else
			{
				if((*Node)[nodeIdx[i]][2]>mid[2])
				{
					//LeftBottomFront
					_nodeIdx[6].push_back(nodeIdx[i]);
				}
				else
				{
					//LeftBottomBehind
					_nodeIdx[7].push_back(nodeIdx[i]);
				}
			}
		}
	}

	Vec3f p1;
	Vec3f p2;

	//RightTopFront
	p1=mid;
	p2=rightUp;
	genOctree(descendant[0], p1, p2, _nodeIdx[0], maxDepth);  

	//RightTopBehind
	p1=Vec3f(mid[0], mid[1], leftDown[2]);
	p2=Vec3f(rightUp[0], rightUp[1], mid[2]);
	genOctree(descendant[1], p1, p2, _nodeIdx[1], maxDepth);  

	//RightBottomFront
	p1=Vec3f(mid[0], leftDown[1], mid[2]);
	p2=Vec3f(rightUp[0], mid[1], rightUp[2]) ;
	genOctree(descendant[2], p1, p2, _nodeIdx[2], maxDepth);

	//RightBottomBehind
	p1=Vec3f(mid[0],leftDown[1],leftDown[2]);
	p2=Vec3f(rightUp[0], mid[1], mid[2]);
	genOctree(descendant[3], p1, p2, _nodeIdx[3], maxDepth);

	//LeftTopFront
	p1=Vec3d(leftDown[0], mid[1], mid[2]);
	p2=Vec3d(mid[0], rightUp[1], rightUp[2]);
	genOctree(descendant[4], p1, p2, _nodeIdx[4], maxDepth);

	//LeftTopBehind
	p1=Vec3f(leftDown[0], mid[1], leftDown[2]);
	p2=Vec3f(mid[0], rightUp[1], mid[2]);
	genOctree(descendant[5], p1, p2, _nodeIdx[5], maxDepth);

	//LeftBottomFront
	p1=Vec3f(leftDown[0], leftDown[1], mid[2]);
	p2=Vec3f(mid[0], mid[1], rightUp[2]);
	genOctree(descendant[6], p1, p2, _nodeIdx[6], maxDepth);

	//LeftBottomBehind
	p1=leftDown;
	p2=mid;
	genOctree(descendant[7], p1, p2, _nodeIdx[7], maxDepth);

	delete [] descendant;
	return 0;
}