Skip to content
Snippets Groups Projects
scene.cpp 13.6 KiB
Newer Older
Noé's avatar
Noé committed
#include "scene.hpp"

#include "tree.hpp"
#include "interpolation.hpp"
#include "ball.hpp"
#include "bird.hpp"
Marie AUDOUARD's avatar
Marie AUDOUARD committed
#include "bat.hpp"
Noé's avatar
Noé committed
#include "terrain.hpp"

using namespace cgp;
int num_trees = 200;
int num_grass = 200;
Noé's avatar
Noé committed
std::vector<vec3> tree_position;
std::vector<vec3> grass_position;
float terrain_length = 250;
Noé's avatar
Noé committed

void scene_structure::initialize()
{
	
	camera_control.initialize(inputs, window); // Give access to the inputs and window global state to the camera controler

	//for orbit camera
	//camera_control.set_rotation_axis_z(); 
	//camera_control.look_at({ 20.0f,15.0f,15.0f }, {0,0,0});
	
	//for first person camera
	camera_control.camera_model.position_camera = { 0,0,evaluate_terrain_height(0,0,terrain_length)+10};
	camera_control.camera_model.set_rotation_axis({ 0,0,1 });
	//custum function we added to ..first_person_euler
Noé's avatar
Noé committed
	global_frame.initialize_data_on_gpu(mesh_primitive_frame());

	//skybox_debug.png for debugging
	image_structure image_skybox_template = image_load_file("assets/skybox2.jpg");
	std::vector<image_structure> image_grid = image_split_grid(image_skybox_template, 4, 3);

	skybox.initialize_data_on_gpu();
	//x neg, x pos, y neg, y pos, z neg, z pos
	skybox.texture.initialize_cubemap_on_gpu(image_grid[7].rotate_90_degrees_counterclockwise(), image_grid[1].rotate_90_degrees_clockwise(), image_grid[4].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise(), image_grid[10], image_grid[3], image_grid[5].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise());


	int N_terrain_samples = 500;
Noé's avatar
Noé committed
	mesh const terrain_mesh = create_terrain_mesh(N_terrain_samples, terrain_length);
	terrain.initialize_data_on_gpu(terrain_mesh);
Marie AUDOUARD's avatar
Marie AUDOUARD committed
	// terrain.material.color = { 0.6f,0.85f,0.5f }; terrain de couleur de base verte
	terrain.material.color = { 1,1,1 };
Noé's avatar
Noé committed
	terrain.material.phong.specular = 0.0f; // non-specular terrain material

Noé's avatar
Noé committed
	terrain.shader.load(project::path + "shaders/mesh_multi_texture/mesh_multi_texture.vert.glsl", project::path + "shaders/mesh_multi_texture/mesh_multi_texture.frag.glsl");
	terrain.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/texture_grass.jpg",
		GL_REPEAT,
		GL_MIRRORED_REPEAT);
Marie AUDOUARD's avatar
Marie AUDOUARD committed
	terrain.supplementary_texture["image_texture_2"].load_and_initialize_texture_2d_on_gpu(project::path + "assets/snow.jpg",
Noé's avatar
Noé committed
		GL_REPEAT,
		GL_MIRRORED_REPEAT);

Noé's avatar
Noé committed
	int r = 1;
	int h = 5;
	mesh cyl_mesh = create_cylinder_mesh(r, h);
	cyl.initialize_data_on_gpu(cyl_mesh);
	cyl.material.color = { 0.58f,0.294f,0.0f };
	cyl.material.phong.specular = 0.0f;

	r = 3;
	h = 2;
	int z = 3;
	mesh cone_mesh = create_cone_mesh(r, h, z);
	cone.initialize_data_on_gpu(cone_mesh);
	cone.material.color = { 0.0f,0.8f,0.0f };
	cone.material.phong.specular = 0.0f;

	mesh tree_mesh = create_tree();
	tree.initialize_data_on_gpu(tree_mesh);

	float x = 1.0;
	float y = 2.0;
Noé's avatar
Noé committed
	tree.model.translation = { x, y, evaluate_terrain_height(x,y, terrain_length) };
Noé's avatar
Noé committed

	tree_position = generate_positions_on_terrain(num_trees, terrain_length-1);

	grass_position = generate_positions_on_terrain(num_grass, terrain_length-1);
	mesh quadrangle_mesh;
	quadrangle_mesh.position = { {0,0,0},{1, 0, 0}, {1,0,1},  {0, 0,1} };
	quadrangle_mesh.uv = { {0,0},{1,0}, {1,1}, {0,1} };
	quadrangle_mesh.connectivity = { {0,1,2}, {0,2,3} };
	quadrangle_mesh.fill_empty_field(); // (fill with some default values the other buffers (colors, normals) that we didn't filled before)
	// Convert the mesh structure into a mesh_drawable structure
	grass.initialize_data_on_gpu(quadrangle_mesh);
	grass.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/grass.png",
		GL_CLAMP_TO_BORDER,
		GL_CLAMP_TO_BORDER);

	bird1.initialize_bird();
	initialize_mvt();
	chain1.initialize();
	bouncing.initialize(10); //10 balls
Marie AUDOUARD's avatar
Marie AUDOUARD committed
	bat1.initialize_bat();
	projectiles.initialize(0);
Noé's avatar
Noé committed
}

void scene_structure::initialize_mvt()
{
	// Definition of the initial data
	//--------------------------------------//

	// Key 3D positions
	numarray<vec3> key_positions =
	{ {-1,1,0}, {0,1,0}, {1,1,0}, {1,2,0}, {2,2,0}, {2,2,1}, {2,0,1.5}, {1.5,-1,1}, {1.5,-1,0}, {1,-1,0}, {0,-0.5,0}, {-1,1,0} };
	float h = 20+evaluate_terrain_height(0,0,terrain_length);
Noé's avatar
Noé committed
	for (int i = 0; i < key_positions.size(); i++) key_positions[i][2] += h;

	// Key times (time at which the position must pass in the corresponding position)
	numarray<float> key_times =
	{ 0.0f, 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 3.75f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f };
Noé's avatar
Noé committed

	// Initialize the helping structure to display/interact with these positions
	keyframe.initialize(key_positions, key_times);


	// Set timer bounds
	// The timer must span a time interval on which the interpolation can be conducted
	// By default, set the minimal time to be key_times[1], and the maximal time to be key_time[N-2] (enables cubic interpolation)
	int N = key_times.size();
	timer_mvt.t_min = key_times[0];
	timer_mvt.t_max = key_times[N - 1];
	timer_mvt.t = timer_mvt.t_min;

}

void scene_structure::display_frame()
{
	// Update the current time
	timer.update();

	//  Must be called before drawing the other shapes and without writing in the Depth Buffer
	glDepthMask(GL_FALSE); // disable depth-buffer writing
	draw(skybox, environment);
	glDepthMask(GL_TRUE);  // re-activate depth-buffer write

Noé's avatar
Noé committed
	//Walking on ground
	if (!gui.fly) {
		vec3 eye_level = camera_control.camera_model.position_camera;
		eye_level[2] = evaluate_terrain_height(eye_level[0], eye_level[1], terrain_length) + 0.75;
		camera_control.camera_model.position_camera = eye_level;
	}
Noé's avatar
Noé committed

Noé's avatar
Noé committed
	// Set the light to the current position of the camera
	environment.light = camera_control.camera_model.position();

	if (gui.display_frame)
		draw(global_frame, environment);

	draw(terrain, environment);
	if (gui.display_wireframe)
		draw_wireframe(terrain, environment);

	for (int i = 0; i < num_trees; i++) {
		tree.model.translation = tree_position[i];
		draw(tree, environment);
	}
	vec3 p = display_mvt();
Marie AUDOUARD's avatar
Marie AUDOUARD committed
	//display_bird(p);
Noé's avatar
Noé committed
	display_chain(p);
	display_ball();
Marie AUDOUARD's avatar
Marie AUDOUARD committed
	display_bat(p);
	display_projectiles();
Noé's avatar
Noé committed


	if (gui.display_wireframe)
		draw_wireframe(tree, environment);

	display_semiTransparent();

}


void scene_structure::display_bird(vec3 p)
{
	// Apply transformation to some elements of the hierarchy
	bird1.bird["Bird head"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, 0.3 * cos(timer.t));
	bird1.bird["Bird wing left1"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, 0.5 * cos(5 * timer.t));
	bird1.bird["Bird wing left2"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, 0.7 * cos(5 * timer.t));
	bird1.bird["Bird wing right1"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, -0.5 * cos(5 * timer.t));
	bird1.bird["Bird wing right2"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, -0.7 * cos(5 * timer.t));


	// This function must be called before the drawing in order to propagate the deformations through the hierarchy
	bird1.bird.update_local_to_global_coordinates();
	
	//Orientation and position of the bird along the path
	float t = timer_mvt.t;
	vec3 p2;
	if(t+0.1f > timer_mvt.t_max) p2 = interpolation(0.01f, keyframe.key_positions, keyframe.key_times, gui.k);
	else p2 = interpolation((t + 0.1f), keyframe.key_positions, keyframe.key_times, gui.k);
	bird1.bird["Bird base"].transform_local.rotation = rotation_transform::from_vector_transform({1,0,0}, normalize(p2 - p));
	bird1.bird["Bird base"].transform_local.translation = p;

	/* Exemple TD5
	hierarchy["Cylinder1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,0,1 }, timer.t);
	hierarchy["Cube1"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, -3 * timer.t);
	hierarchy["Cyl2"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,0,1 }, 6 * timer.t);
	hierarchy["Cyl3"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,0,1 }, 6 * timer.t);
	hierarchy["Cube base"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, 0.8 * cos(3 * timer.t));

	hierarchy.update_local_to_global_coordinates();
	*/

	draw(bird1.bird, environment);
	if (gui.display_wireframe) {
		//draw_wireframe(hierarchy, environment);
		draw_wireframe(bird1.bird, environment);
	}


}

Marie AUDOUARD's avatar
Marie AUDOUARD committed
void scene_structure::display_bat(vec3 p)
{
	// Apply transformation to some elements of the hierarchy
	bat1.bat["Bat wing left1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, 0.5 * cos(5 * timer.t));
	bat1.bat["Bat wing right1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, -0.5 * cos(5 * timer.t));


	// This function must be called before the drawing in order to propagate the deformations through the hierarchy
	bat1.bat.update_local_to_global_coordinates();


	
	//Orientation and position of the bird along the path
	float t = timer_mvt.t;
	vec3 p2;
	if (t + 0.1f > timer_mvt.t_max) p2 = interpolation(0.01f, keyframe.key_positions, keyframe.key_times, gui.k);
	else p2 = interpolation((t + 0.1f), keyframe.key_positions, keyframe.key_times, gui.k);
	bat1.bat["Bat base"].transform_local.rotation = rotation_transform::from_vector_transform({ 0,-1,0 }, normalize(p2 - p));
Marie AUDOUARD's avatar
Marie AUDOUARD committed
	bat1.bat["Bat base"].transform_local.translation = p;


	draw(bat1.bat, environment);
	if (gui.display_wireframe) {
		draw_wireframe(bat1.bat, environment);
	}
}

Noé's avatar
Noé committed
void scene_structure::display_semiTransparent()
{
	// Enable use of alpha component as color blending for transparent elements
	//  alpha = current_color.alpha
	//  new color = previous_color * alpha + current_color * (1-alpha)
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// Disable depth buffer writing
	//  - Transparent elements cannot use depth buffer
	//  - They are supposed to be display from furest to nearest elements
	glDepthMask(false);

	auto const& camera = camera_control.camera_model;

	// Re-orient the grass shape to always face the camera direction
	vec3 const right = camera.right();
	// Rotation such that the grass follows the right-vector of the camera, while pointing toward the z-direction
	
	for (int i = 0; i < num_grass; i++) {
		grass.model.translation = grass_position[i];
		rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1 }, right, { 0,0,1 });
		grass.model.rotation = R;
		draw(grass, environment);
	}

	// Don't forget to re-activate the depth-buffer write
	glDepthMask(true);
	glDisable(GL_BLEND);
}





vec3 scene_structure::display_mvt()
{
	// Basic elements of the scene
	environment.light = camera_control.camera_model.position();
	if (gui.display_frame)
		draw(global_frame, environment);

	// Update the current time
	timer_mvt.update();
	float t = timer_mvt.t;

	// clear trajectory when the timer restart
	if (t < timer_mvt.t_min + 0.1f)
		keyframe.trajectory.clear();

	// Display the key positions and lines b/w positions
	keyframe.display_key_positions(environment);

	// Compute the interpolated position
	//  This is this function that you need to complete
	return interpolation(t, keyframe.key_positions, keyframe.key_times, gui.k);

	// Display the interpolated position (and its trajectory)
	//keyframe.display_current_position(p, environment);
}

void scene_structure::draw_segment(vec3 const& a, vec3 const& b)
{
	chain1.segment.vbo_position.update(numarray<vec3>{ a, b });
	draw(chain1.segment, environment);
}

void scene_structure::display_chain(vec3 bird_pos)
{
	
	// Update the current time
	timer_chain.update();


	chain1.simulation_step(timer_chain.scale * 0.01f, bird_pos);

	for (int i = 0; i < chain1.n; i++) {
		chain1.particle_sphere.model.translation = chain1.p[i];
		chain1.particle_sphere.material.color = { (float)i / chain1.n,(float)i / chain1.n,0 };
		draw(chain1.particle_sphere, environment);
	}

	for (int i = 0; i < chain1.n - 1; i++) {
		draw_segment(chain1.p[i], chain1.p[i + 1]);
	}
}


void scene_structure::display_gui()
{
	ImGui::Checkbox("Frame", &gui.display_frame);
	ImGui::Checkbox("Wireframe", &gui.display_wireframe);
Noé's avatar
Noé committed
	ImGui::Checkbox("Fly", &gui.fly);
Noé's avatar
Noé committed

	ImGui::SliderFloat("Time", &timer_mvt.t, timer_mvt.t_min, timer_mvt.t_max);
	ImGui::SliderFloat("Time scale", &timer_mvt.scale, 0.0f, 2.0f);
	ImGui::SliderFloat("K", &gui.k, 0.0f, 10.0f);
	ImGui::SliderFloat("Speed", &gui.speed, 0.0f, 10.0f);
Noé's avatar
Noé committed

	// Display the GUI associated to the key position
	keyframe.display_gui();
}

void scene_structure::display_ball() {

	bouncing.simulate(timer_chain.scale * 0.01f, terrain_length);
	for (int i = 0; i < bouncing.N; i++) {	
		bouncing.mesh.model.translation = bouncing.pos[i];
		bouncing.mesh.material.color = bouncing.color[i];
		draw(bouncing.mesh, environment);
	}
}

void scene_structure::display_projectiles() {

	projectiles.simulate(timer_chain.scale * 0.01f, terrain_length);
	for (int i = 0; i < projectiles.N; i++) {
		projectiles.mesh.model.translation = projectiles.pos[i];
		projectiles.mesh.material.color = projectiles.color[i];
		draw(projectiles.mesh, environment);
	}
}

Noé's avatar
Noé committed
void scene_structure::mouse_move_event()
{
	if (!inputs.keyboard.shift)
		camera_control.action_mouse_move(environment.camera_view);
}
void scene_structure::mouse_click_event()
{
	if (camera_control.inputs->mouse.click.left){
		//std::cout << "ball created";
		projectiles.add_ball(camera_control.camera_model.position_camera + 2*camera_control.camera_model.front(), 20*camera_control.camera_model.front());
	}
Noé's avatar
Noé committed
	camera_control.action_mouse_click(environment.camera_view);
}
void scene_structure::keyboard_event()
{
	camera_control.action_keyboard(environment.camera_view);
	if(camera_control.inputs->keyboard.shift) {
		projectiles.reset();
	}
Noé's avatar
Noé committed
}
void scene_structure::idle_frame()
{
	if (camera_control.inputs->keyboard.ctrl) {
		camera_control.idle_frame(environment.camera_view, 10);
	}
	else {
		camera_control.idle_frame(environment.camera_view, gui.speed);
	}