第四课讲的是变换,还有坐标系之类的,不是很深。
第四课的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 );
}