-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathassignment2.js
218 lines (186 loc) · 10.9 KB
/
assignment2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import {tiny, defs} from './examples/common.js';
// Pull these names into this module's scope for convenience:
const { vec3, vec4, color, Mat4, Shape, Material, Shader, Texture, Component } = tiny;
// TODO: you should implement the required classes here or in another file.
import {Articulated_Human} from "./human.js";
import { Curve_Shape, Spline } from './ucla.js';
// var memoryManager = new EmscriptenMemoryManager();
export
const Assignment2_base = defs.Assignment2_base =
class Assignment2_base extends Component
{
// **My_Demo_Base** is a Scene that can be added to any display canvas.
// This particular scene is broken up into two pieces for easier understanding.
// The piece here is the base class, which sets up the machinery to draw a simple
// scene demonstrating a few concepts. A subclass of it, Assignment2,
// exposes only the display() method, which actually places and draws the shapes,
// isolating that code so it can be experimented with on its own.
init()
{
console.log("init")
// constructor(): Scenes begin by populating initial values like the Shapes and Materials they'll need.
this.hover = this.swarm = false;
// At the beginning of our program, load one of each of these shape
// definitions onto the GPU. NOTE: Only do this ONCE per shape it
// would be redundant to tell it again. You should just re-use the
// one called "box" more than once in display() to draw multiple cubes.
// Don't define more than one blueprint for the same thing here.
this.shapes = { 'box' : new defs.Cube(),
'ball' : new defs.Subdivision_Sphere( 4 ),
'axis' : new defs.Axis_Arrows() };
// *** Materials: *** A "material" used on individual shapes specifies all fields
// that a Shader queries to light/color it properly. Here we use a Phong shader.
// We can now tweak the scalar coefficients from the Phong lighting formulas.
// Expected values can be found listed in Phong_Shader::update_GPU().
const basic = new defs.Basic_Shader();
const phong = new defs.Phong_Shader();
const tex_phong = new defs.Textured_Phong();
this.materials = {};
this.materials.plastic = { shader: phong, ambient: .5, diffusivity: .5, specularity: .5, color: color( .9,.5,.9,1 ) }
this.materials.metal = { shader: phong, ambient: .2, diffusivity: 1, specularity: 1, color: color( .9,.5,.9,1 ) }
this.materials.rgb = { shader: tex_phong, ambient: .5, texture: new Texture( "assets/rgb.jpg" ) }
this.ball_location = vec3(2, 6, 3);
this.ball_radius = 0.25;
// TODO: you should create a Spline class instance
this.spline = new Spline();
this.spline.add_point(3, 6, -0.8, 10, 10, 0);
this.spline.add_point(4.2, 7, -0.8, 12, 0, 0);
this.spline.add_point(5.0, 6, -0.8, 0, -12, 0);
this.spline.add_point(4.2, 5, -0.8, -12, 0, 0);
this.spline.add_point(3, 6, -0.8, -10, 10, 0);
this.spline.add_point(1.8, 7, -0.8, -12, 0, 0);
this.spline.add_point(1.0, 6, -0.8, 0, -12, 0);
this.spline.add_point(1.8, 5, -0.8, 12, 0, 0);
this.spline.add_point(3, 6, -0.8, 0, 0, 0);
this.spline.add_curves();
this.jobs = this.spline.get_jobs();
this.idx = 0;
this.human = new Articulated_Human();
}
render_animation( caller )
{ // display(): Called once per frame of animation. We'll isolate out
// the code that actually draws things into Assignment2, a
// subclass of this Scene. Here, the base class's display only does
// some initial setup.
// Setup -- This part sets up the scene's overall camera matrix, projection matrix, and lights:
if( !caller.controls )
{ this.animated_children.push( caller.controls = new defs.Movement_Controls( { uniforms: this.uniforms } ) );
caller.controls.add_mouse_controls( caller.canvas );
// Define the global camera and projection matrices, which are stored in shared_uniforms. The camera
// matrix follows the usual format for transforms, but with opposite values (cameras exist as
// inverted matrices). The projection matrix follows an unusual format and determines how depth is
// treated when projecting 3D points onto a plane. The Mat4 functions perspective() or
// orthographic() automatically generate valid matrices for one. The input arguments of
// perspective() are field of view, aspect ratio, and distances to the near plane and far plane.
// !!! Camera changed here
// TODO: you can change the camera as needed.
Shader.assign_camera( Mat4.look_at (vec3 (5, 8, 15), vec3 (0, 5, 0), vec3 (0, 1, 0)), this.uniforms );
}
this.uniforms.projection_transform = Mat4.perspective( Math.PI/4, caller.width/caller.height, 1, 100 );
// *** Lights: *** Values of vector or point lights. They'll be consulted by
// the shader when coloring shapes. See Light's class definition for inputs.
const t = this.t = this.uniforms.animation_time/1000;
// const light_position = Mat4.rotation( angle, 1,0,0 ).times( vec4( 0,-1,1,0 ) ); !!!
// !!! Light changed here
const light_position = vec4(20, 20, 20, 1.0);
this.uniforms.lights = [ defs.Phong_Shader.light_source( light_position, color( 1,1,1,1 ), 1000000 ) ];
// draw axis arrows.
this.shapes.axis.draw(caller, this.uniforms, Mat4.identity(), this.materials.rgb);
}
}
export class Assignment2 extends Assignment2_base
{
// **Assignment2** is a Scene object that can be added to any display canvas.
// This particular scene is broken up into two pieces for easier understanding.
// See the other piece, My_Demo_Base, if you need to see the setup code.
// The piece here exposes only the display() method, which actually places and draws
// the shapes. We isolate that code so it can be experimented with on its own.
// This gives you a very small code sandbox for editing a simple scene, and for
// experimenting with matrix transformations.
render_animation( caller )
{ // display(): Called once per frame of animation. For each shape that you want to
// appear onscreen, place a .draw() call for it inside. Each time, pass in a
// different matrix value to control where the shape appears.
// Variables that are in scope for you to use:
// this.shapes.box: A vertex array object defining a 2x2x2 cube.
// this.shapes.ball: A vertex array object defining a 2x2x2 spherical surface.
// this.materials.metal: Selects a shader and draws with a shiny surface.
// this.materials.plastic: Selects a shader and draws a more matte surface.
// this.lights: A pre-made collection of Light objects.
// this.hover: A boolean variable that changes when the user presses a button.
// shared_uniforms: Information the shader needs for drawing. Pass to draw().
// caller: Wraps the WebGL rendering context shown onscreen. Pass to draw().
// Call the setup code that we left inside the base class:
super.render_animation( caller );
/**********************************
Start coding down here!!!!
**********************************/
// From here on down it's just some example shapes drawn for you -- freely
// replace them with your own! Notice the usage of the Mat4 functions
// translation(), scale(), and rotation() to generate matrices, and the
// function times(), which generates products of matrices.
const blue = color( 0,0,1,1 ), yellow = color( 1,0.7,0,1 ),
wall_color = color( 0.7, 1.0, 0.8, 1 ),
blackboard_color = color( 0.2, 0.2, 0.2, 1 );
const t = this.t = this.uniforms.animation_time/1000;
// !!! Draw ground
let floor_transform = Mat4.translation(0, 0, 0).times(Mat4.scale(10, 0.01, 10));
this.shapes.box.draw( caller, this.uniforms, floor_transform, { ...this.materials.plastic, color: yellow } );
// TODO: you should draw scene here.
// TODO: you can change the wall and board as needed.
let wall_transform = Mat4.translation(0, 5, -1.2).times(Mat4.scale(6, 5, 0.1));
this.shapes.box.draw( caller, this.uniforms, wall_transform, { ...this.materials.plastic, color: wall_color } );
let board_transform = Mat4.translation(3, 6, -1).times(Mat4.scale(2.5, 2.5, 0.1));
this.shapes.box.draw( caller, this.uniforms, board_transform, { ...this.materials.plastic, color: blackboard_color } );
let ball_transform = Mat4.translation(this.ball_location[0], this.ball_location[1], this.ball_location[2])
.times(Mat4.scale(this.ball_radius, this.ball_radius, this.ball_radius));
this.shapes.ball.draw( caller, this.uniforms, ball_transform, { ...this.materials.metal, color: blue } );
// Draw spline here
for(let curve of this.spline.curves) {
curve.draw(caller, this.uniforms);
}
let dt = 1.0 / 30.0;
let t_sim = t;
let t_next = t_sim + dt;
for(; t_sim<=t_next; t_sim += this.d_t) {
let target = this.jobs[this.idx % this.jobs.length];
let err = target.minus(this.human.get_end_effector_position());
let dis = err.norm();
if(dis < 0.05) this.idx++;
else {
// IK of arm
// console.log("CURRENT EF POSITION: ", this.human.end_effector.global_position)
console.log("ERROR: ", dis)
let dx = err.times(0.1);
let jacobian = this.human.calculate_Jacobian();
// console.log("Jacobian: ", jacobian)
let delta_theta = this.human.calculate_delta_theta(jacobian, dx).flat();
// console.log("Delta Theta: ", delta_theta)
this.human.update_delta_theta(delta_theta) // Update this.theta
this.human.apply_theta(); // Update human articulation matrices
this.human.get_end_effector_position();
}
}
// draw human
this.human.draw(caller, this.uniforms, this.materials.plastic);
}
render_controls()
{
// render_controls(): Sets up a panel of interactive HTML elements, including
// buttons with key bindings for affecting this scene, and live info readouts.
this.control_panel.innerHTML += "Assignment 2: IK Engine";
this.new_line();
// TODO: You can add your button events for debugging. (optional)
this.key_triggered_button( "Debug", [ "Shift", "D" ], this.debug );
this.key_triggered_button( "Debug 2", [ "Shift", "E" ], this.debug2 );
this.new_line();
}
debug() {
this.human.debug();
console.log("Current end effector at ", this.human.get_end_effector_position());
}
debug2() {
this.human.debug(null, 2);
console.log("Current end effector at ", this.human.get_end_effector_position());
}
}