Interactive 3D Graphics是Udacity上的一门图形学公开课(需要×××),最近在学习,在这里记录一下课程的学习进度和作业的答案。


多边形的三角形划分

由于在图形学中,面的表示通常是用三角形来表示,所以要显示多边形的时候,就要将其碎片化。

//////////////////////////////////////////////////////////////////////////////// // Polygon Creation Exercise // Your task is to complete the function PolygonGeometry(sides) // which takes 1 argument: //   sides - how many edges the polygon has. // Return the mesh that defines the minimum number of triangles necessary // to draw the polygon. // Radius of the polygon is 1. Center of the polygon is at 0, 0. //////////////////////////////////////////////////////////////////////////////// /*global, THREE, Coordinates, $, document, window*/  var camera, scene, renderer; var windowScale;  function PolygonGeometry(sides) { 	var geo = new THREE.Geometry(); 	 	// generate vertices 	for ( var pt = 0 ; pt < sides; pt++ ) 	{ 		// Add 90 degrees so we start at +Y axis, rotate counterclockwise around 		var angle = (Math.PI/2) + (pt / sides) * 2 * Math.PI;  		var x = Math.cos( angle ); 		var y = Math.sin( angle ); 		 		// YOUR CODE HERE         //Save the vertex location - fill in the code         geo.vertices.push(new THREE.Vector3(x,y,0)); 	}     // YOUR CODE HERE 	// Write the code to generate minimum number of faces for the polygon.     for ( var fc = 0 ; fc < sides-1; fc++ ) 	{     geo.faces.push( new THREE.Face3( 0, fc, fc+1) );     } 	// Return the geometry object 	return geo; }  function init() { 	//  Setting up some parameters 	var canvasWidth = 846; 	var canvasHeight = 494; 	var canvasRatio = canvasWidth / canvasHeight; 	// scene 	scene = new THREE.Scene();  	// Camera: Y up, X right, Z up 	windowScale = 4; 	var windowWidth = windowScale * canvasRatio; 	var windowHeight = windowScale;  	camera = new THREE.OrthographicCamera( windowWidth / - 2, windowWidth / 2, windowHeight / 2, windowHeight / - 2, 0, 40 ); 	 	var focus = new THREE.Vector3( 0,1,0 ); 	camera.position.x = focus.x; 	camera.position.y = focus.y; 	camera.position.z = 10; 	camera.lookAt(focus);  	renderer = new THREE.WebGLRenderer({ antialias: false, preserveDrawingBuffer: true}); 	renderer.gammaInput = true; 	renderer.gammaOutput = true; 	renderer.setSize( canvasWidth, canvasHeight ); 	renderer.setClearColorHex( 0xffffff, 1.0 );  } function showGrids() {   	// Background grid and axes. Grid step size is 1, axes cross at 0, 0 	Coordinates.drawGrid({size:100,scale:1,orientation:"z"}); 	Coordinates.drawAxes({axisLength:4,axisOrientation:"x",axisRadius:0.02}); 	Coordinates.drawAxes({axisLength:3,axisOrientation:"y",axisRadius:0.02}); } 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 render() { 	renderer.render( scene, camera ); }  // Main body of the script init(); showGrids(); addToDOM(); var geo = PolygonGeometry(5); var material = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.FrontSide } ); var mesh = new THREE.Mesh( geo, material ); scene.add( mesh ); render();

运行结果:




在制定位置绘制制定半径的多边形

原先的函数变成了PolygonGeometry(sides,radius, location),只要在生成vertex的时候对坐标进行相应的变换就可已了。

//////////////////////////////////////////////////////////////////////////////// // Polygon Radius Exercise // Your task is to write a function that will take 3 arguments: //   sides - how many edges the polygon has. //   location - location of the center of the polygon as a THREE.Vector3. //   radius - radius of the polygon. // Return the mesh that defines the minimum number of triangles necessary // to draw the polygon. //////////////////////////////////////////////////////////////////////////////// /*global, THREE, Coordinates, $, document, window*/  var camera, scene, renderer; var windowScale;  function PolygonGeometry(sides, location, radius) { 	var geo = new THREE.Geometry(); 	 	// generate vertices 	for ( var pt = 0 ; pt < sides; pt++ ) 	{ 		// Add 90 degrees so we start at +Y axis, rotate counterclockwise around 		var angle = (Math.PI/2) + (pt / sides) * 2 * Math.PI;  		var x = radius*Math.cos(angle) + location.x; 		var y = radius*Math.sin(angle) + location.y; 		 		// Save the vertex location 		geo.vertices.push( new THREE.Vector3( x, y, 0.0 ) ); 	}  	// generate faces 	for ( var face = 0 ; face < sides-2; face++ ) 	{ 		// this makes a triangle fan, from the first +Y point around 		geo.faces.push( new THREE.Face3( 0, face+1, face+2 ) ); 	}	 	// done: return it. 	return geo; }  function init() { 	//  Setting up some parameters 	var canvasWidth = 846; 	var canvasHeight = 494; 	var canvasRatio = canvasWidth / canvasHeight; 	// scene 	scene = new THREE.Scene();  	// Camera: Y up, X right, Z up 	windowScale = 12; 	var windowWidth = windowScale * canvasRatio; 	var windowHeight = windowScale;  	camera = new THREE.OrthographicCamera( windowWidth / - 2, windowWidth / 2, windowHeight / 2, windowHeight / - 2, 0, 40 ); 	 	var focus = new THREE.Vector3( 5,5,0 ); 	camera.position.x = focus.x; 	camera.position.y = focus.y; 	camera.position.z = 10; 	camera.lookAt(focus);   	renderer = new THREE.WebGLRenderer({ antialias: false, preserveDrawingBuffer: true}); 	renderer.gammaInput = true; 	renderer.gammaOutput = true; 	renderer.setSize(canvasWidth, canvasHeight); 	renderer.setClearColorHex( 0xffffff, 1.0 ); 	 } function showGrids() {   	// Background grid and axes. Grid step size is 1, axes cross at 0, 0 	Coordinates.drawGrid({size:100,scale:1,orientation:"z"}); 	Coordinates.drawAxes({axisLength:4,axisOrientation:"x",axisRadius:0.02}); 	Coordinates.drawAxes({axisLength:3,axisOrientation:"y",axisRadius:0.02}); } 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 render() { 	renderer.render( scene, camera ); }  // Main body of the script init(); showGrids(); addToDOM(); var geo = PolygonGeometry(9, new THREE.Vector3( 5, 5, 0 ), 4); var material = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.FrontSide } ); var mesh = new THREE.Mesh( geo, material ); scene.add( mesh ); render(); 




建造楼梯

搭建一个楼梯,最终获得奖杯。

//////////////////////////////////////////////////////////////////////////////// // Staircase exercise                                                         // // Your task is to complete the model for simple stairs                       // // Using the provided sizes and colors, complete the staircase                // // and reach the Gold Cup!                                                    // //////////////////////////////////////////////////////////////////////////////// /*global, THREE, Coordinates, $, document, window, dat*/  var camera, scene, renderer; var cameraControls, effectController; var clock = new THREE.Clock(); var gridX = false; var gridY = false; var gridZ = false; var axes = false; var ground = true;  function createStairs() {  	// MATERIALS 	var stepMaterialVertical = new THREE.MeshLambertMaterial( {  		color: 0xA85F35  	} ); 	var stepMaterialHorizontal = new THREE.MeshLambertMaterial( {  		color: 0xBC7349  	} );  	var stepWidth = 500; 	var stepSize = 200; 	var stepThickness = 50; 	// height from top of one step to bottom of next step up 	var verticalStepHeight = stepSize; 	var horizontalStepDepth = stepSize*2;  	var stepHalfThickness = stepThickness/2; 	 	// +Y direction is up 	// Define the two pieces of the step, vertical and horizontal 	// THREE.CubeGeometry takes (width, height, depth) 	var stepVertical = new THREE.CubeGeometry(stepWidth, verticalStepHeight, stepThickness); 	var stepHorizontal = new THREE.CubeGeometry(stepWidth, stepThickness, horizontalStepDepth); 	var stepMesh;       for( var i=0;i<6;i++ )     {         stepMesh = new THREE.Mesh( stepVertical, stepMaterialVertical ); 	// The position is where the center of the block will be put. 	// You can define position as THREE.Vector3(x, y, z) or in the following way:         stepMesh.position.x = 0;			// centered at origin         stepMesh.position.y = i*verticalStepHeight+verticalStepHeight/2+i*stepThickness;	// half of height: put it above ground plane         stepMesh.position.z = i*horizontalStepDepth-i*stepThickness;			// centered at origin         scene.add( stepMesh );     } 	  	// Make and position the horizontal part      for( var i=0;i<6;i++ )     {         stepMesh = new THREE.Mesh( stepHorizontal, stepMaterialHorizontal );         stepMesh.position.x = 0;         // Push up by half of horizontal step's height, plus vertical step's height         stepMesh.position.y = i*stepThickness + (i+1)*verticalStepHeight+stepHalfThickness;         // Push step forward by half the depth, minus half the vertical step's thickness         stepMesh.position.z = i*horizontalStepDepth+horizontalStepDepth/2 -  i*stepThickness-stepHalfThickness;         scene.add( stepMesh );     } }  function createCup() { 	var cupMaterial = new THREE.MeshLambertMaterial( { color: 0xFDD017}); 	// THREE.CylinderGeometry takes (radiusTop, radiusBottom, height, segmentsRadius) 	var cupGeo = new THREE.CylinderGeometry( 200, 50, 400, 32 ); 	var cup = new THREE.Mesh( cupGeo, cupMaterial ); 	cup.position.x = 0; 	cup.position.y = 1725; 	cup.position.z = 1925; 	scene.add( cup ); 	cupGeo = new THREE.CylinderGeometry( 100, 100, 50, 32 ); 	cup = new THREE.Mesh( cupGeo, cupMaterial ); 	cup.position.x = 0; 	cup.position.y = 1525; 	cup.position.z = 1925; 	scene.add( cup ); }  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( 45, canvasRatio, 1, 40000 ); 	camera.position.set( -700, 500, -1600 ); 	// CONTROLS 	cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement); 	cameraControls.target.set(0,600,0);  	// Camera(2) for testing has following values: 	// camera.position.set( 1225, 2113, 1814 ); 	// cameraControls.target.set(-1800,180,630);    	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 fillScene() { 	// SCENE 	scene = new THREE.Scene(); 	scene.fog = new THREE.Fog( 0x808080, 3000, 6000 ); 	// 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( -400, 200, -300 );  	scene.add(ambientLight); 	scene.add(light); 	scene.add(light2);  	scene.add(camera);  	if (ground) { 		Coordinates.drawGround({size:1000});		 	} 	if (gridX) { 		Coordinates.drawGrid({size:1000,scale:0.01}); 	} 	if (gridY) { 		Coordinates.drawGrid({size:1000,scale:0.01, orientation:"y"}); 	} 	if (gridZ) { 		Coordinates.drawGrid({size:1000,scale:0.01, orientation:"z"});	 	} 	if (axes) { 		Coordinates.drawAllAxes({axisLength:300,axisRadius:2,axisTess:50}); 	} 	createCup(); 	var stairs = createStairs(); 	scene.add(stairs); } //  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,  		dummy: function() { 		} 	};  	var gui = new dat.GUI(); 	gui.add(effectController, "newGridX").name("Show XZ grid"); 	gui.add( effectController, "newGridY" ).name("Show YZ grid"); 	gui.add( effectController, "newGridZ" ).name("Show XY grid"); 	gui.add( effectController, "newGround" ).name("Show ground"); 	gui.add( effectController, "newAxes" ).name("Show axes"); }  init(); addToDOM(); setupGui(); animate(); 



空间建模

第三题十一个三维建模的题目,需要一些空间想象。

和3dmax的建模类似,在max中建模是交互的,但这里是需要代码来实现。

主要用到了三个函数来创建空间物体:

//Create box boxGeometry = New THREE.CubeGeometry(float width,float,height,float depth); //Create sphere sphereGeometry = New THREE.SphereGeometry(float radius,int segsWidth,int segsHeight); // Create cylinder cylinderGeometry = New THREE.CylinderGeometry(float radius1,float radius1,int height,int segs);

平面图如下:




代码如下

//////////////////////////////////////////////////////////////////////////////// // Drinking Bird Model exercise                                               // // Your task is to complete the model for the drinking bird                   // // The following forms and sizes should be used:                              // // Hat: cylinder. color blue (cylinderMaterial)                               // //      Diameter top 80, bottom, full height 80, edge 10                      // // Head: sphere, red (sphereMaterial), diameter 104                           // // Middle of base: cube, color orange (cubeMaterial), width 77, length 194     // // Feet: cube, color orange, width 6, length 194, height 52                    // // Legs: cube, color orange, width 6, length 64, height 386                    // // Body: sphere, red, diameter 116                                            // // Spine: cylinder, blue, diameter 24, length 390                             // //////////////////////////////////////////////////////////////////////////////// /*global, THREE, Coordinates, $, document, window, dat*/  var camera, scene, renderer; var cameraControls, effectController; var clock = new THREE.Clock(); var gridX = false; var gridY = false; var gridZ = false; var axes = false; var ground = true;  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( 45, canvasRatio, 1, 40000 ); 	// CONTROLS 	cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);  	camera.position.set( -480, 659, -619 ); 	cameraControls.target.set(4,301,92);  	fillScene(); }  // Supporting frame for the bird - base + legs + feet function createSupport() {     var cubeMaterial = new THREE.MeshLambertMaterial( { color: 0xF07020 } ); 	// base 	var cube; 	cube = new THREE.Mesh(  		new THREE.CubeGeometry( 20+64+110, 4, 2*77 ), cubeMaterial ); 	cube.position.x = -45;	// (20+32) - half of width (20+64+110)/2 	cube.position.y = 4/2;	// half of height 	cube.position.z = 0;	// centered at origin 	scene.add( cube ); 	 	// left foot 	cube = new THREE.Mesh(  		new THREE.CubeGeometry( 20+64+110, 52, 6 ), cubeMaterial ); 	cube.position.x = -45;	// (20+32) - half of width (20+64+110)/2 	cube.position.y = 52/2;	// half of height 	cube.position.z = 77 + 6/2;	// offset 77 + half of depth 6/2 	scene.add( cube ); 	 	// left leg 	cube = new THREE.Mesh(  		new THREE.CubeGeometry( 64, 334+52, 6 ), cubeMaterial ); 	cube.position.x = 0;	// centered on origin along X 	cube.position.y = (334+52)/2; 	cube.position.z = 77 + 6/2;	// offset 77 + half of depth 6/2 	scene.add( cube ); 	 	// right foot 	cube = new THREE.Mesh(  		new THREE.CubeGeometry( 20+64+110, 52, 6 ), cubeMaterial ); 	cube.position.x = -45;	// (20+32) - half of width (20+64+110)/2 	cube.position.y = 52/2;	// half of height 	cube.position.z = -77 + -6/2;	// offset 77 + half of depth 6/2 	scene.add( cube ); 	// right leg     cube = new THREE.Mesh(  		new THREE.CubeGeometry( 64, 334+52, 6 ), cubeMaterial ); 	cube.position.x = 0;	// centered on origin along X 	cube.position.y = (334+52)/2; 	cube.position.z = -77 + -6/2;	// offset 77 + half of depth 6/2 	scene.add( cube ); }  // Body of the bird - body and the connector of body and head function createBody() {    var sphereMaterial = new THREE.MeshLambertMaterial( { color: 0xA00000 } );    var cylinderMaterial = new THREE.MeshLambertMaterial( { color: 0x0000D0 } );          //Create two balls     var sphere;    sphere = new THREE.Mesh( new THREE.SphereGeometry( 116/2, 32, 16 ), sphereMaterial ); 	sphere.position.x = 0;	 	sphere.position.y = 160;	 	sphere.position.z = 0;	 	scene.add( sphere );          sphere = new THREE.Mesh( new THREE.SphereGeometry( 104/2, 32, 16 ), sphereMaterial ); 	sphere.position.x = 0;	 	sphere.position.y = 390+160;	 	sphere.position.z = 0;	 	scene.add( sphere );          //Create a stick     var cylinder;     cylinder=new THREE.Mesh(new THREE.CylinderGeometry( 12, 12, 390, 32 ), cylinderMaterial);     cylinder.position.x = 0;	 	cylinder.position.y = 160+390/2;	 	cylinder.position.z = 0;	 	scene.add( cylinder ); }  // Head of the bird - head + hat function createHead() {    var sphereMaterial = new THREE.MeshLambertMaterial( { color: 0xA00000 } );    var cylinderMaterial = new THREE.MeshLambertMaterial( { color: 0x0000D0 } );     //Create cap    var cylinder;     cylinder=new THREE.Mesh(new THREE.CylinderGeometry( 142/2, 142/2, 10, 32 ), cylinderMaterial);     cylinder.position.x = 0;	 	cylinder.position.y = 160+390+40+5;	 	cylinder.position.z = 0;	 	scene.add( cylinder );          cylinder=new THREE.Mesh(new THREE.CylinderGeometry( 80/2, 80/2, 70, 32 ), cylinderMaterial);     cylinder.position.x = 0;	 	cylinder.position.y = 160+390+40+10+70/2;	 	cylinder.position.z = 0;	 	scene.add( cylinder ); }  function createDrinkingBird() {  	// MODELS 	// base + legs + feet 	createSupport(); 	 	// body + body/head connector 	createBody();  	// head + hat 	createHead(); }  function fillScene() { 	// SCENE 	scene = new THREE.Scene(); 	scene.fog = new THREE.Fog( 0x808080, 3000, 6000 ); 	// 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( -400, 200, -300 );  	scene.add(ambientLight); 	scene.add(light); 	scene.add(light2);  	scene.add(camera);  	if (ground) { 		Coordinates.drawGround({size:1000});		 	} 	if (gridX) { 		Coordinates.drawGrid({size:1000,scale:0.01}); 	} 	if (gridY) { 		Coordinates.drawGrid({size:1000,scale:0.01, orientation:"y"}); 	} 	if (gridZ) { 		Coordinates.drawGrid({size:1000,scale:0.01, orientation:"z"});	 	} 	if (axes) { 		Coordinates.drawAllAxes({axisLength:300,axisRadius:2,axisTess:50}); 	} 	createDrinkingBird(); } // 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 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,  		dummy: function() { 		} 	};  	var gui = new dat.GUI(); 	gui.add(effectController, "newGridX").name("Show XZ grid"); 	gui.add( effectController, "newGridY" ).name("Show YZ grid"); 	gui.add( effectController, "newGridZ" ).name("Show XY grid"); 	gui.add( effectController, "newGround" ).name("Show ground"); 	gui.add( effectController, "newAxes" ).name("Show axes"); }  init(); addToDOM(); setupGui(); animate(); 

运行效果: