From 3e757dbc71682972899a48651710c5d8280c3cee Mon Sep 17 00:00:00 2001 From: Kiet Tran Date: Mon, 29 Nov 2021 13:36:54 -0600 Subject: Publish A6 --- dev/a6-harold/ground.cc | 283 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 dev/a6-harold/ground.cc (limited to 'dev/a6-harold/ground.cc') diff --git a/dev/a6-harold/ground.cc b/dev/a6-harold/ground.cc new file mode 100644 index 0000000..51d4d92 --- /dev/null +++ b/dev/a6-harold/ground.cc @@ -0,0 +1,283 @@ +/** CSci-4611 Assignment 6: Harold + */ + +#include "ground.h" + + +Ground::Ground() : diffuse_ramp_(GL_CLAMP_TO_EDGE), + specular_ramp_(GL_CLAMP_TO_EDGE), light_pos_(30,30,30) +{ + +} + +Ground::~Ground() { + +} + +Mesh* Ground::mesh_ptr() { return &ground_mesh_; } + + +void Ground::Init(const std::vector &search_path) { + // init ground geometry, a simple grid is used. if it is running too slow, + // you can turn down the resolution by decreasing nx and ny, but this will + // make the hills look more jaggy. + const int nx = 150; + const int ny = 150; + const float size = 100.0; + std::vector verts; + std::vector norms; + for (int j = 0; j <= ny; j++) { + for (int i = 0; i <= nx; i++) { + float x = size*(float)j/nx - size/2.0f; + float y = size*(float)i/ny - size/2.0f; + verts.push_back(Point3(x, 0, y)); + norms.push_back(Vector3(0,1,0)); + } + } + std::vector indices; + for (int j = 0; j < ny; j++) { + for (int i = 0; i < nx; i++) { + // L\ triangle + indices.push_back((i+0)+(j+0)*(nx+1)); + indices.push_back((i+1)+(j+0)*(nx+1)); + indices.push_back((i+0)+(j+1)*(nx+1)); + // \7 triangle + indices.push_back((i+1)+(j+0)*(nx+1)); + indices.push_back((i+1)+(j+1)*(nx+1)); + indices.push_back((i+0)+(j+1)*(nx+1)); + } + } + ground_mesh_.SetIndices(indices); + ground_mesh_.SetVertices(verts); + ground_mesh_.SetNormals(norms); + ground_mesh_.UpdateGPUMemory(); + ground_edge_mesh_.CreateFromMesh(ground_mesh_); + + + // load textures and shaders + diffuse_ramp_.InitFromFile(Platform::FindFile("toonDiffuse.png", search_path)); + specular_ramp_.InitFromFile(Platform::FindFile("toonSpecular.png", search_path)); + + artsy_shaderprog_.AddVertexShaderFromFile(Platform::FindFile("artsy.vert", search_path)); + artsy_shaderprog_.AddFragmentShaderFromFile(Platform::FindFile("artsy.frag", search_path)); + artsy_shaderprog_.LinkProgram(); + + outline_shaderprog_.AddVertexShaderFromFile(Platform::FindFile("outline.vert", search_path)); + outline_shaderprog_.AddFragmentShaderFromFile(Platform::FindFile("outline.frag", search_path)); + outline_shaderprog_.LinkProgram(); +} + + + + +// Projects a 2D normalized screen point (e.g., the mouse position in normalized +// device coordinates) to a 3D point on the ground. Returns true and sets ground_point +// to be equal to the result if the conversion is successful. Returns false if +// the screen point does not project onto the ground. +bool Ground::ScreenPtHitsGround(const Matrix4 &view_matrix, const Matrix4 &proj_matrix, + const Point2 &normalized_screen_pt, Point3 *ground_point) +{ + Matrix4 camera_matrix = view_matrix.Inverse(); + Point3 eye = camera_matrix.ColumnToPoint3(3); + + Point3 pt3d = GfxMath::ScreenToNearPlane(view_matrix, proj_matrix, normalized_screen_pt); + Ray ray(eye, (pt3d - eye).ToUnit()); + float i_time; + int i_tri; + return ray.FastIntersectMesh(&ground_mesh_, &i_time, ground_point, &i_tri); +} + + + + +/** This implements the "h" term used in the equations described in section 4.5 of the + paper. Three arguments are needed: + 1. projection_plane_normal: We need to know where the projection plane is in 3-space + Since a plane can be defined by a point within the plane and a normal, we use + this normal together with the 3rd argument to the function to define the projection + plane described in the paper. + 2. silhouette_curve: As described in the paper, the silhouette curve is a 3D version + of the curve the user draws with the mouse. It is formed by projecting the + original 2D screen-space curve onto the 3D projection plane. + 3. closest_pt_in_plane: As described in the paper, this is the closest point within + the projection plane to the vertex of the mesh that we want to modify. In other + words, it is the perpendicular projection of the vertex we want to modify onto + the projection plane. + */ +float hfunc(const Vector3 projection_plane_normal, const std::vector &silhouette_curve, const Point3 &closest_pt_in_plane) { + // define the y axis for a "plane space" coordinate system as a world space vector + Vector3 plane_y = Vector3(0,1,0); + // define the x axis for a "plane space" coordinate system as a world space vector + Vector3 plane_x = plane_y.Cross(projection_plane_normal).ToUnit(); + // define the origin for a "plane space" coordinate system as the first point in the curve + Point3 origin = silhouette_curve[0]; + + // loop over line segments in the curve, find the one that lies over the point by + // comparing the "plane space" x value for the start and end of the line segment + // to the "plane space" x value for the closest point to the vertex that lies + // in the projection plane. + float x_target = (closest_pt_in_plane - origin).Dot(plane_x); + for (int i=1; i &stroke2d) +{ + // TODO: Deform the 3D ground mesh according to the algorithm described in the + // Cohen et al. Harold paper. + + // You might need the eye point and the look vector, these can be determined + // from the view matrix as follows: + Matrix4 camera_matrix = view_matrix.Inverse(); + Point3 eye = camera_matrix.ColumnToPoint3(3); + Vector3 look = -camera_matrix.ColumnToVector3(2); + + + + // There are 3 major steps to the algorithm, outlined here: + + // 1. Define a plane to project the stroke onto. The first and last points + // of the stroke are guaranteed to project onto the ground plane. The plane + // should pass through these two points on the ground. The plane should also + // have a normal vector that points toward the camera and is parallel to the + // ground plane. + + + + + + // 2. Project the 2D stroke into 3D so that it lies on the "projection plane" + // defined in step 1. + + + + + + // 3. Loop through all of the vertices of the ground mesh, and adjust the + // height of each based on the equations in section 4.5 of the paper, also + // repeated in the assignment handout. The equations rely upon a function + // h(), and we have implemented that for you as hfunc() defined above in + // this file. The basic structure of the loop you will need is here: + std::vector new_verts; + for (int i=0; i indices = ground_mesh_.triangle_vertices(t); + std::vector loop; + loop.push_back(ground_mesh_.vertex(indices[0])); + loop.push_back(ground_mesh_.vertex(indices[1])); + loop.push_back(ground_mesh_.vertex(indices[2])); + qs_.DrawLines(model_matrix, view_matrix, proj_matrix, Color(0.7,0.7,0.7), loop, QuickShapes::LinesType::LINE_LOOP, 0.01); + } + + // draw normals + for (int i=0; i