第四课讲的是变换,还有坐标系之类的,不是很深。

第四课的Problem set记录。

1.机器人手臂

要求是添加机器人手臂的底座,只要理解好THREE.Object3D()就可以了。参考一下原有的代码就可以得到结果。

//////////////////////////////////////////////////////////////////////////////// /*global THREE, Coordinates, $, document, window, dat*/  var camera, scene, renderer; var cameraControls, effectController; var clock = new THREE.Clock(); var gridX = true; var gridY = false; var gridZ = false; var axes = true; var ground = true; var arm, forearm, body;  function fillScene() { 	scene = new THREE.Scene(); 	scene.fog = new THREE.Fog( 0x808080, 2000, 4000 );  	// LIGHTS 	var ambientLight = new THREE.AmbientLight( 0x222222 ); 	var light = new THREE.DirectionalLight( 0xffffff, 1.0 ); 	light.position.set( 200, 400, 500 ); 	var light2 = new THREE.DirectionalLight( 0xffffff, 1.0 ); 	light2.position.set( -500, 250, -200 ); 	scene.add(ambientLight); 	scene.add(light); 	scene.add(light2);      // Robot definitions 	var robotBaseMaterial = new THREE.MeshPhongMaterial( { color: 0x6E23BB, specular: 0x6E23BB, shininess: 20 } ); 	var robotForearmMaterial = new THREE.MeshPhongMaterial( { color: 0xF4C154, specular: 0xF4C154, shininess: 100 } ); 	var robotUpperArmMaterial = new THREE.MeshPhongMaterial( { color: 0x95E4FB, specular: 0x95E4FB, shininess: 100 } ); 	var robotBodyMaterial = new THREE.MeshPhongMaterial( { color: 0x279933, specular: 0x279933, shininess: 100 } );  	var torus = new THREE.Mesh(  		new THREE.TorusGeometry( 22, 15, 32, 32 ), robotBaseMaterial ); 	torus.rotation.x = 90 * Math.PI/180; 	scene.add( torus );  	forearm = new THREE.Object3D(); 	var faLength = 80;  	createRobotExtender( forearm, faLength, robotForearmMaterial );  	arm = new THREE.Object3D(); 	var uaLength = 120;	 	 	createRobotCrane( arm, uaLength, robotUpperArmMaterial ); 	 	// Move the forearm itself to the end of the upper arm. 	forearm.position.y = uaLength;	 	arm.add( forearm ); 	//scene.add( arm );      // YOUR CODE HERE   	body = new THREE.Object3D(); 	var bodyLength = 60;         arm.position.y = bodyLength;         body.add( arm );         createRobotBody( body, bodyLength, robotBodyMaterial );         scene.add( body ); }  function createRobotExtender( part, length, material ) { 	var cylinder = new THREE.Mesh(  		new THREE.CylinderGeometry( 22, 22, 6, 32 ), material ); 	part.add( cylinder );  	var i; 	for ( i = 0; i < 4; i++ ) 	{ 		var box = new THREE.Mesh(  			new THREE.CubeGeometry( 4, length, 4 ), material ); 		box.position.x = (i < 2) ? -8 : 8; 		box.position.y = length/2; 		box.position.z = (i%2) ? -8 : 8; 		part.add( box ); 	} 	 	cylinder = new THREE.Mesh(  		new THREE.CylinderGeometry( 15, 15, 40, 32 ), material ); 	cylinder.rotation.x = 90 * Math.PI/180; 	cylinder.position.y = length; 	part.add( cylinder ); }  function createRobotCrane( part, length, material ) { 	var box = new THREE.Mesh(  		new THREE.CubeGeometry( 18, length, 18 ), material ); 	box.position.y = length/2; 	part.add( box ); 	 	var sphere = new THREE.Mesh(  		new THREE.SphereGeometry( 20, 32, 16 ), material ); 	// place sphere at end of arm 	sphere.position.y = length; 	part.add( sphere ); }  function createRobotBody( part, length, material ) { 	var cylinder = new THREE.Mesh(  		new THREE.CylinderGeometry( 50, 12, length/2, 18 ), material ); 	cylinder.position.y = length/4; 	part.add( cylinder ); 	 	cylinder = new THREE.Mesh(  		new THREE.CylinderGeometry( 12, 50, length/2, 18 ), material ); 	cylinder.position.y = 3*length/4; 	part.add( cylinder ); 	 	var box = new THREE.Mesh(  		new THREE.CubeGeometry( 12, length/4, 110 ), material ); 	box.position.y = length/2; 	part.add( box );  	var sphere = new THREE.Mesh(  		new THREE.SphereGeometry( 20, 32, 16 ), material ); 	// place sphere at end of arm 	sphere.position.y = length; 	part.add( sphere ); }  function init() { 	var canvasWidth = 846; 	var canvasHeight = 494; 	var canvasRatio = canvasWidth / canvasHeight;  	// RENDERER 	renderer = new THREE.WebGLRenderer( { antialias: true } ); 	renderer.gammaInput = true; 	renderer.gammaOutput = true; 	renderer.setSize(canvasWidth, canvasHeight); 	renderer.setClearColorHex( 0xAAAAAA, 1.0 );  	// CAMERA 	camera = new THREE.PerspectiveCamera( 38, canvasRatio, 1, 10000 ); 	camera.position.set( -510, 240, 100 ); 	// CONTROLS 	cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement); 	cameraControls.target.set(0,120,0); 	camera.position.set(-102, 177, 20); 	cameraControls.target.set(-13, 60, 2); 	fillScene();  }  function addToDOM() {     var container = document.getElementById('container');     var canvas = container.getElementsByTagName('canvas');     if (canvas.length>0) {         container.removeChild(canvas[0]);     }     container.appendChild( renderer.domElement ); }  function drawHelpers() {     if (ground) { 		Coordinates.drawGround({size:10000});		 	} 	if (gridX) { 		Coordinates.drawGrid({size:10000,scale:0.01}); 	} 	if (gridY) { 		Coordinates.drawGrid({size:10000,scale:0.01, orientation:"y"}); 	} 	if (gridZ) { 		Coordinates.drawGrid({size:10000,scale:0.01, orientation:"z"});	 	} 	if (axes) { 		Coordinates.drawAllAxes({axisLength:200,axisRadius:1,axisTess:50}); 	} }  function animate() { 	window.requestAnimationFrame(animate); 	render(); }  function render() { 	var delta = clock.getDelta(); 	cameraControls.update(delta);  	if ( effectController.newGridX !== gridX || effectController.newGridY !== gridY || effectController.newGridZ !== gridZ || effectController.newGround !== ground || effectController.newAxes !== axes) 	{ 		gridX = effectController.newGridX; 		gridY = effectController.newGridY; 		gridZ = effectController.newGridZ; 		ground = effectController.newGround; 		axes = effectController.newAxes;  		fillScene(); 	}        // UNCOMMENT FOLLOWING LINES TO ENABLE CONTROLS FOR BODY:    	// body.rotation.y = effectController.by * Math.PI/180;	// yaw  	arm.rotation.y = effectController.uy * Math.PI/180;	// yaw 	arm.rotation.z = effectController.uz * Math.PI/180;	// roll 	 	forearm.rotation.y = effectController.fy * Math.PI/180;	// yaw 	forearm.rotation.z = effectController.fz * Math.PI/180;	// roll 	 	renderer.render(scene, camera); }  function setupGui() {  	effectController = {  		newGridX: gridX, 		newGridY: gridY, 		newGridZ: gridZ, 		newGround: ground, 		newAxes: axes, 		         // UNCOMMENT FOLLOWING LINE TO SET DEFAULT VALUE OF CONTROLS FOR BODY: 		// by: 0.0, 		 		uy: 70.0, 		uz: -15.0,  		fy: 10.0, 		fz: 60.0 	};  	var gui = new dat.GUI(); 	var h = gui.addFolder("Grid display"); 	h.add( effectController, "newGridX").name("Show XZ grid"); 	h.add( effectController, "newGridY" ).name("Show YZ grid"); 	h.add( effectController, "newGridZ" ).name("Show XY grid"); 	h.add( effectController, "newGround" ).name("Show ground"); 	h.add( effectController, "newAxes" ).name("Show axes"); 	h = gui.addFolder("Arm angles"); 	// student, uncomment: h.add(effectController, "by", -180.0, 180.0, 0.025).name("Body y"); 	h.add(effectController, "uy", -180.0, 180.0, 0.025).name("Upper arm y"); 	h.add(effectController, "uz", -45.0, 45.0, 0.025).name("Upper arm z"); 	h.add(effectController, "fy", -180.0, 180.0, 0.025).name("Forearm y"); 	h.add(effectController, "fz", -120.0, 120.0, 0.025).name("Forearm z"); }  init(); fillScene(); drawHelpers(); addToDOM(); setupGui(); animate();



2.添加机器人手指

首先参照leftHand的创建方式创建rightHand,然后在render()方法中添加对手指的控制。

//////////////////////////////////////////////////////////////////////////////// /*global THREE, Coordinates, $, document, window, dat*/  var camera, scene, renderer; var cameraControls, effectController; var clock = new THREE.Clock(); var gridX = true; var gridY = false; var gridZ = false; var axes = true; var ground = true; var arm, forearm, body, handLeft, handRight;  function fillScene() { 	scene = new THREE.Scene(); 	scene.fog = new THREE.Fog( 0x808080, 2000, 4000 );  	// LIGHTS 	var ambientLight = new THREE.AmbientLight( 0x222222 ); 	var light = new THREE.DirectionalLight( 0xffffff, 1.0 ); 	light.position.set( 200, 400, 500 ); 	var light2 = new THREE.DirectionalLight( 0xffffff, 1.0 ); 	light2.position.set( -500, 250, -200 ); 	scene.add(ambientLight); 	scene.add(light); 	scene.add(light2);      // Robot definitions 	var robotHandLeftMaterial = new THREE.MeshPhongMaterial( { color: 0xCC3399, specular: 0xCC3399, shininess: 20 } ); 	var robotHandRightMaterial = new THREE.MeshPhongMaterial( { color: 0xDD3388, specular: 0xDD3388, shininess: 20 } ); 	var robotBaseMaterial = new THREE.MeshPhongMaterial( { color: 0x6E23BB, specular: 0x6E23BB, shininess: 20 } ); 	var robotForearmMaterial = new THREE.MeshPhongMaterial( { color: 0xF4C154, specular: 0xF4C154, shininess: 100 } ); 	var robotUpperArmMaterial = new THREE.MeshPhongMaterial( { color: 0x95E4FB, specular: 0x95E4FB, shininess: 100 } );  	var torus = new THREE.Mesh(  		new THREE.TorusGeometry( 22, 15, 32, 32 ), robotBaseMaterial ); 	torus.rotation.x = 90 * Math.PI/180; 	scene.add( torus ); 	 	forearm = new THREE.Object3D(); 	var faLength = 80;  	createRobotExtender( forearm, faLength, robotForearmMaterial );  	arm = new THREE.Object3D(); 	var uaLength = 120;	 	 	createRobotCrane( arm, uaLength, robotUpperArmMaterial ); 	 	// Move the forearm itself to the end of the upper arm. 	forearm.position.y = uaLength;	 	arm.add( forearm ); 	 	scene.add( arm );  	var handLength = 38;  	handLeft = new THREE.Object3D(); 	createRobotGrabber( handLeft, handLength, robotHandLeftMaterial ); 	// Move the hand part to the end of the forearm. 	handLeft.position.y = faLength;		 	forearm.add( handLeft );        // YOUR CODE HERE 	// Add the second grabber handRight. Note that it uses a different color, defined above      handRight= new THREE.Object3D(); 	createRobotGrabber( handRight, handLength, robotHandRightMaterial ); 	// Move the hand part to the end of the forearm. 	handRight.position.y = faLength;		 	forearm.add( handRight );     // ALSO EDIT render() TO ENABLE CONTROLS FOR GRABBER  }  function createRobotGrabber( part, length, material ) { 	var box = new THREE.Mesh(  		new THREE.CubeGeometry( 30, length, 4 ), material ); 	box.position.y = length/2; 	part.add( box ); }  function createRobotExtender( part, length, material ) { 	var cylinder = new THREE.Mesh(  		new THREE.CylinderGeometry( 22, 22, 6, 32 ), material ); 	part.add( cylinder );  	var i; 	for ( i = 0; i < 4; i++ ) 	{ 		var box = new THREE.Mesh(  			new THREE.CubeGeometry( 4, length, 4 ), material ); 		box.position.x = (i < 2) ? -8 : 8; 		box.position.y = length/2; 		box.position.z = (i%2) ? -8 : 8; 		part.add( box ); 	} 	 	cylinder = new THREE.Mesh(  		new THREE.CylinderGeometry( 15, 15, 40, 32 ), material ); 	cylinder.rotation.x = 90 * Math.PI/180; 	cylinder.position.y = length; 	part.add( cylinder ); }  function createRobotCrane( part, length, material ) { 	var box = new THREE.Mesh(  		new THREE.CubeGeometry( 18, length, 18 ), material ); 	box.position.y = length/2; 	part.add( box ); 	 	var sphere = new THREE.Mesh(  		new THREE.SphereGeometry( 20, 32, 16 ), material ); 	// place sphere at end of arm 	sphere.position.y = length; 	part.add( sphere ); }  function init() { 	var canvasWidth = 846; 	var canvasHeight = 494; 	var canvasRatio = canvasWidth / canvasHeight;  	// RENDERER 	renderer = new THREE.WebGLRenderer( { antialias: true } ); 	renderer.gammaInput = true; 	renderer.gammaOutput = true; 	renderer.setSize(canvasWidth, canvasHeight); 	renderer.setClearColorHex( 0xAAAAAA, 1.0 );  	// CAMERA 	camera = new THREE.PerspectiveCamera( 38, canvasRatio, 1, 10000 ); 	// CONTROLS 	cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement); 	camera.position.set(-49, 242,54); 	cameraControls.target.set(54, 106, 33); 	fillScene();  }  function addToDOM() {     var container = document.getElementById('container');     var canvas = container.getElementsByTagName('canvas');     if (canvas.length>0) {         container.removeChild(canvas[0]);     }     container.appendChild( renderer.domElement ); }  function drawHelpers() {     if (ground) { 		Coordinates.drawGround({size:10000});		 	} 	if (gridX) { 		Coordinates.drawGrid({size:10000,scale:0.01}); 	} 	if (gridY) { 		Coordinates.drawGrid({size:10000,scale:0.01, orientation:"y"}); 	} 	if (gridZ) { 		Coordinates.drawGrid({size:10000,scale:0.01, orientation:"z"});	 	} 	if (axes) { 		Coordinates.drawAllAxes({axisLength:200,axisRadius:1,axisTess:50}); 	} }  function animate() { 	window.requestAnimationFrame(animate); 	render(); }  function render() { 	var delta = clock.getDelta(); 	cameraControls.update(delta);  	if ( effectController.newGridX !== gridX || effectController.newGridY !== gridY || effectController.newGridZ !== gridZ || effectController.newGround !== ground || effectController.newAxes !== axes) 	{ 		gridX = effectController.newGridX; 		gridY = effectController.newGridY; 		gridZ = effectController.newGridZ; 		ground = effectController.newGround; 		axes = effectController.newAxes;  		fillScene(); 	}    	arm.rotation.y = effectController.uy * Math.PI/180;	// yaw 	arm.rotation.z = effectController.uz * Math.PI/180;	// roll 	 	forearm.rotation.y = effectController.fy * Math.PI/180;	// yaw 	forearm.rotation.z = effectController.fz * Math.PI/180;	// roll 	     // ADD handRight yaw AND translate HERE     handLeft.rotation.z = effectController.hz * Math.PI/180;	// yaw 	handLeft.position.z = effectController.htz;	// translate          handRight.rotation.z = effectController.hz * Math.PI/180;     handRight.position.z = -effectController.htz; 	renderer.render(scene, camera); }  function setupGui() {  	effectController = {  		newGridX: gridX, 		newGridY: gridY, 		newGridZ: gridZ, 		newGround: ground, 		newAxes: axes, 		 		uy: 70.0, 		uz: -15.0,  		fy: 10.0, 		fz: 60.0,                  hz: 30.0, 		htz: 12.0 	};  	var gui = new dat.GUI(); 	var h = gui.addFolder("Grid display"); 	h.add( effectController, "newGridX").name("Show XZ grid"); 	h.add( effectController, "newGridY" ).name("Show YZ grid"); 	h.add( effectController, "newGridZ" ).name("Show XY grid"); 	h.add( effectController, "newGround" ).name("Show ground"); 	h.add( effectController, "newAxes" ).name("Show axes"); 	h = gui.addFolder("Arm angles"); 	h.add(effectController, "uy", -180.0, 180.0, 0.025).name("Upper arm y"); 	h.add(effectController, "uz", -45.0, 45.0, 0.025).name("Upper arm z"); 	h.add(effectController, "fy", -180.0, 180.0, 0.025).name("Forearm y"); 	h.add(effectController, "fz", -120.0, 120.0, 0.025).name("Forearm z");     h.add(effectController, "hz", -45.0, 45.0, 0.025).name("Hand z"); 	h.add(effectController, "htz", 2.0, 17.0, 0.025).name("Hand spread"); }  init(); fillScene(); drawHelpers(); addToDOM(); setupGui(); animate();



3.画一朵花

这里给出了花的柄,要求画出24朵花瓣。

花瓣的绘制方法已经给出,通过循环变换就可以绘制出来,注意变换的顺序。

//////////////////////////////////////////////////////////////////////////////// // Make a Flower //////////////////////////////////////////////////////////////////////////////// /*global THREE, Coordinates, document, window, dat*/  var camera, scene, renderer; var cameraControls, effectController; var clock = new THREE.Clock(); var gridX = true; var gridY = false; var gridZ = false; var axes = true; var ground = true;   function fillScene() { 	scene = new THREE.Scene(); 	scene.fog = new THREE.Fog( 0x808080, 2000, 4000 );  	// LIGHTS 	var ambientLight = new THREE.AmbientLight( 0x222222 ); 	var light = new THREE.DirectionalLight( 0xffffff, 1.0 ); 	light.position.set( 200, 400, 500 ); 	var light2 = new THREE.DirectionalLight( 0xffffff, 1.0 ); 	light2.position.set( -500, 250, -200 ); 	scene.add(ambientLight); 	scene.add(light); 	scene.add(light2);      // FLOWER     var petalMaterial = new THREE.MeshLambertMaterial( { color: 0xCC5920 } ); 	var flowerHeight = 200; 	var petalLength = 120; 	var cylGeom = new THREE.CylinderGeometry( 15, 0, petalLength, 32 ); 	var flower = new THREE.Object3D();          /////////     // YOUR CODE HERE 	// add code here to make 24 petals, radiating around the sphere     for (var i=0;i<24;i++)     {     	var cylinder = new THREE.Mesh( cylGeom, petalMaterial );                  cylinder.rotation.x = 90*Math.PI/180;         cylinder.position.z = petalLength/2;         var petal = new THREE.Object3D();         petal.position.y = flowerHeight;          petal.rotation.y = i*15*Math.PI/180;         petal.add( cylinder );         flower.add( petal );     }       	var stamenMaterial = new THREE.MeshLambertMaterial( { color: 0x333310 } ); 	var stamen = new THREE.Mesh(  		new THREE.SphereGeometry( 20, 32, 16 ), stamenMaterial ); 	stamen.position.y = flowerHeight;	// move to flower center 	flower.add( stamen );  	var stemMaterial = new THREE.MeshLambertMaterial( { color: 0x339424 } ); 	var stem = new THREE.Mesh(  		new THREE.CylinderGeometry( 10, 10, flowerHeight, 32 ), stemMaterial ); 	stem.position.y = flowerHeight/2;	// move from ground to stamen 	flower.add( stem );  	scene.add( flower );  }   function init() { 	var canvasWidth = 846;  	var canvasHeight = 494; 	var canvasRatio = canvasWidth / canvasHeight;  	// RENDERER 	renderer = new THREE.WebGLRenderer( { antialias: false } ); 	renderer.gammaInput = true; 	renderer.gammaOutput = true; 	renderer.setSize(canvasWidth, canvasHeight); 	renderer.setClearColorHex( 0xAAAAAA, 1.0 );  	// CAMERA 	camera = new THREE.PerspectiveCamera( 38, canvasRatio, 1, 10000 ); 	// CONTROLS 	cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement); 	camera.position.set(-200, 400, 20); 	cameraControls.target.set(0,150,0); 	fillScene();  }  function addToDOM() {     var container = document.getElementById('container');     var canvas = container.getElementsByTagName('canvas');     if (canvas.length>0) {         container.removeChild(canvas[0]);     }     container.appendChild( renderer.domElement ); }  function drawHelpers() {   if (ground) { 		Coordinates.drawGround({size:10000});		 	} 	if (gridX) { 		Coordinates.drawGrid({size:10000,scale:0.01}); 	} 	if (gridY) { 		Coordinates.drawGrid({size:10000,scale:0.01, orientation:"y"}); 	} 	if (gridZ) { 		Coordinates.drawGrid({size:10000,scale:0.01, orientation:"z"});	 	} 	if (axes) { 		Coordinates.drawAllAxes({axisLength:200,axisRadius:1,axisTess:50}); 	} }  function animate() { 	window.requestAnimationFrame(animate); 	render(); }  function render() { 	var delta = clock.getDelta(); 	cameraControls.update(delta);  	if ( effectController.newGridX !== gridX || effectController.newGridY !== gridY || effectController.newGridZ !== gridZ || effectController.newGround !== ground || effectController.newAxes !== axes) 	{ 		gridX = effectController.newGridX; 		gridY = effectController.newGridY; 		gridZ = effectController.newGridZ; 		ground = effectController.newGround; 		axes = effectController.newAxes;  		fillScene(); 	}  	renderer.render(scene, camera); }    function setupGui() {  	effectController = {  		newGridX: gridX, 		newGridY: gridY, 		newGridZ: gridZ, 		newGround: ground, 		newAxes: axes  	};  	var gui = new dat.GUI(); 	var h = gui.addFolder("Grid display"); 	h.add( effectController, "newGridX").name("Show XZ grid"); 	h.add( effectController, "newGridY" ).name("Show YZ grid"); 	h.add( effectController, "newGridZ" ).name("Show XY grid"); 	h.add( effectController, "newGround" ).name("Show ground"); 	h.add( effectController, "newAxes" ).name("Show axes");  }   // this is the main action sequence init(); fillScene(); drawHelpers(); addToDOM(); setupGui(); animate();



4.压扁的花

在上一个程序上的改进,然它看起来更棒一些。
对花瓣继续进行处理,压扁,并且产生一些倾角。最终效果如下:


关键代码

    

 for (var i=0;i<24;i++)     {     	var cylinder = new THREE.Mesh( cylGeom, petalMaterial );        // cylinder.position.y = petalHeight;         cylinder.scale.z = 0.25;         cylinder.rotation.x = 90*Math.PI/180;         //cylinder.rotation.x = -20*Math.PI/180;         cylinder.position.z = petalLength/2;         var petal = new THREE.Object3D();                  petal.add( cylinder );         petal.rotation.x = -20*Math.PI/180;         var tmpObject = new THREE.Object3D();         tmpObject.add( petal);         tmpObject.rotation.y = i*15*Math.PI/180;         tmpObject.position.y = flowerHeight;                            flower.add( tmpObject );     }