## 摄像机、投影、3D旋转、缩放

2011-09-23 08:18  【当耐特】  阅读(19593)  评论(64编辑  收藏

# 简述

3D效果分两种，一种是伪3D骨架，一种是3D实体.

#### 3D骨架：是通过大量的计算将3D世界中所有点投影到二维平面中。

3D实体:通过摄像机向投影面发射射线与世界中的物体交汇，把与物体交汇点的颜色渲染到投影面 （光线追踪的基础） 。

# 投影分析

#### h / Math.abs(vidiconZ - z1)

x = x1 * h / Math.abs(vidiconZ - z);

y=  y1 * h / Math.abs(vidiconZ - z);

 <canvas id="myCanvas" width="700" height="500" style="border: 1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
cxt.lineWidth = 3;
//正方体8个顶点
var Point1 = { x: 100, y: 100, z: 100 };
var Point2 = { x: 100, y: 100, z: -100 };
var Point3 = { x: -100, y: 100, z: -100 };
var Point4 = { x: -100, y: 100, z: 100 };
var Point_1 = { x: 100, y: -100, z: 100 };
var Point_2 = { x: 100, y: -100, z: -100 };
var Point_3 = { x: -100, y: -100, z: -100 };
var Point_4 = { x: -100, y: -100, z: 100 };
var startX = 250;
var startY = 250;
//摄像机到显示屏的距离
var distance = 500;
//摄像机位置
var eyePosition = { x: 0, y: 0, z: 700 };
function changeDistance() {
Point1.x = Point1.x * distance / Math.abs(eyePosition.z - Point1.z);
Point1.y = Point1.y * distance / Math.abs(eyePosition.z - Point1.z);
Point2.x = Point2.x * distance / Math.abs(eyePosition.z - Point2.z);
Point2.y = Point2.y * distance / Math.abs(eyePosition.z - Point2.z);
Point3.x = Point3.x * distance / Math.abs(eyePosition.z - Point3.z);
Point3.y = Point3.y * distance / Math.abs(eyePosition.z - Point3.z);
Point4.x = Point4.x * distance / Math.abs(eyePosition.z - Point4.z);
Point4.y = Point4.y * distance / Math.abs(eyePosition.z - Point4.z);
Point_1.x = Point_1.x * distance / Math.abs(eyePosition.z - Point_1.z);
Point_1.y = Point_1.y * distance / Math.abs(eyePosition.z - Point_1.z);
Point_2.x = Point_2.x * distance / Math.abs(eyePosition.z - Point_2.z);
Point_2.y = Point_2.y * distance / Math.abs(eyePosition.z - Point_2.z);
Point_3.x = Point_3.x * distance / Math.abs(eyePosition.z - Point_3.z);
Point_3.y = Point_3.y * distance / Math.abs(eyePosition.z - Point_3.z);
Point_4.x = Point_4.x * distance / Math.abs(eyePosition.z - Point_4.z);
Point_4.y = Point_4.y * distance / Math.abs(eyePosition.z - Point_4.z);
}
var drawCube = function () {
changeDistance();
cxt.beginPath();
cxt.moveTo(startX + Point1.x, startY - Point1.y);
cxt.lineTo(startX + Point2.x, startY - Point2.y);
cxt.lineTo(startX + Point3.x, startY - Point3.y);
cxt.lineTo(startX + Point4.x, startY - Point4.y);
cxt.lineTo(startX + Point1.x, startY - Point1.y);
cxt.moveTo(startX + Point_1.x, startY - Point_1.y);
cxt.lineTo(startX + Point_2.x, startY - Point_2.y);
cxt.lineTo(startX + Point_3.x, startY - Point_3.y);
cxt.lineTo(startX + Point_4.x, startY - Point_4.y);
cxt.lineTo(startX + Point_1.x, startY - Point_1.y);
cxt.moveTo(startX + Point2.x, startY - Point2.y);
cxt.lineTo(startX + Point_2.x, startY - Point_2.y);
cxt.moveTo(startX + Point1.x, startY - Point1.y);
cxt.lineTo(startX + Point_1.x, startY - Point_1.y);
cxt.moveTo(startX + Point3.x, startY - Point3.y);
cxt.lineTo(startX + Point_3.x, startY - Point_3.y);
cxt.moveTo(startX + Point4.x, startY - Point4.y);
cxt.lineTo(startX + Point_4.x, startY - Point_4.y);
cxt.stroke();
}
</script>
<div id="show">
</div>
<input type="button" onclick="drawCube();" value="开始画立方体"
style="width: 135px" />

# 演示

Your browser does not support the canvas element.

 <script type="text/javascript">
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
cxt.lineWidth = 3;
//正方体8个顶点
var Point = new Array();
Point[0] = { x: 100, y: 100, z: 100 };
Point[1] = { x: 100, y: 100, z: -100 };
Point[2] = { x: -100, y: 100, z: -100 };
Point[3] = { x: -100, y: 100, z: 100 };
Point[4] = { x: 100, y: -100, z: 100 };
Point[5] = { x: 100, y: -100, z: -100 };
Point[6] = { x: -100, y: -100, z: -100 };
Point[7] = { x: -100, y: -100, z: 100 };
var startX = 250;
var startY = 250;
//摄像机到显示屏的距离
var distance = 500;
//摄像机位置
var eyePosition = { x: 0, y: 0, z: 700 };
function changeDistance() {
for (var i = 0; i < Point.length; i++) {
Point[i].x = Point[i].x * distance / Math.abs(eyePosition.z - Point[i].z);
Point[i].y = Point[i].y * distance / Math.abs(eyePosition.z - Point[i].z);
}
}
var drawCube = function () {
changeDistance();
cxt.beginPath();
cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
cxt.lineTo(startX + Point[1].x, startY - Point[1].y);
cxt.lineTo(startX + Point[2].x, startY - Point[2].y);
cxt.lineTo(startX + Point[3].x, startY - Point[3].y);
cxt.lineTo(startX + Point[0].x, startY - Point[0].y);
cxt.moveTo(startX + Point[4].x, startY - Point[4].y);
cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
cxt.moveTo(startX + Point[1].x, startY - Point[1].y);
cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
cxt.moveTo(startX + Point[2].x, startY - Point[2].y);
cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
cxt.moveTo(startX + Point[3].x, startY - Point[3].y);
cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
cxt.stroke();
}
</script>

<script language="javascript" type="text/javascript" src="lib/uglifyjs-parser.js"></script>
<script language="javascript" type="text/javascript" src="src/jscex.js"></script>
<script language="javascript" type="text/javascript" src="src/jscex.builderBase.js"></script>
<script language="javascript" type="text/javascript" src="src/jscex.async.js"></script>
<!--[if IE]>
<script language="javascript" type="text/javascript" src="lib/json2.js"></script>
<script language="javascript">
Jscex.config.codeGenerator = function (code) { return "false || " + code; }
</script>
<![endif]-->
<canvas id="myCanvas" width="700" height="500" style="border: 1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
cxt.lineWidth = 3;
var Point = new Array();
var startX = 250;
var startY = 250;
var distance = 500;
var eyePosition = { x: 0, y: 0, z: 700 };
function init() {
Point[0] = { x: 100, y: 100, z: 100 };
Point[1] = { x: 100, y: 100, z: -100 };
Point[2] = { x: -100, y: 100, z: -100 };
Point[3] = { x: -100, y: 100, z: 100 };
Point[4] = { x: 100, y: -100, z: 100 };
Point[5] = { x: 100, y: -100, z: -100 };
Point[6] = { x: -100, y: -100, z: -100 };
Point[7] = { x: -100, y: -100, z: 100 };
}
function changeDistance() {
for (var i = 0; i < Point.length; i++) {
Point[i].x = Point[i].x * distance / Math.abs(eyePosition.z - Point[i].z);
Point[i].y = Point[i].y * distance / Math.abs(eyePosition.z - Point[i].z);
}
}
var drawCube = function (increment) {
cxt.clearRect(0, 0, 1200, 1200);
init();
distance += increment;
changeDistance();
cxt.beginPath();
cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
cxt.lineTo(startX + Point[1].x, startY - Point[1].y);
cxt.lineTo(startX + Point[2].x, startY - Point[2].y);
cxt.lineTo(startX + Point[3].x, startY - Point[3].y);
cxt.lineTo(startX + Point[0].x, startY - Point[0].y);
cxt.moveTo(startX + Point[4].x, startY - Point[4].y);
cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
cxt.moveTo(startX + Point[1].x, startY - Point[1].y);
cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
cxt.moveTo(startX + Point[2].x, startY - Point[2].y);
cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
cxt.moveTo(startX + Point[3].x, startY - Point[3].y);
cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
cxt.stroke();
}
var reduceDrawCubeAsync = eval(Jscex.compile("async", function () {
//当摄像机到显示屏的距离大于750，退出循环·
while (distance < 750) {
drawCube(10);
$await(Jscex.Async.sleep(100)); } })); var magnifyDrawCubeAsync = eval(Jscex.compile("async", function () { //当摄像机到显示屏的距离小于150，退出循环· while (distance > 150) { drawCube(-10);$await(Jscex.Async.sleep(100));
}
}));
var executeAsync = eval(Jscex.compile("async", function () {
$await(reduceDrawCubeAsync());$await(magnifyDrawCubeAsync());
}));
</script>
<div id="show">
</div>
<input type="button" onclick="executeAsync().start();" value="开始移动显示屏" style="width: 135px" />

# 演示

Your browser does not support the canvas element.

# 3D旋转

#### a.绕Z轴方向的旋转，此时，x和y发生变化，x不变。

    //旋转
function rotate(angle) {
for (var i = 0; i < Points.length; i++) {
var tempX = Points[i].x;
Points[i].x = Points[i].x * Math.cos(angle) - Points[i].z * Math.sin(angle);
Points[i].z = Points[i].z * Math.cos(angle) + tempX * Math.sin(angle);
}
}

    function degToRad(a) {
return (a / (360 / (2 * Math.PI)));
}

    function randomColor() {
var arrHex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]; var strHex = "#";
var index;
for (var i = 0; i < 6; i++) {
index = Math.round(Math.random() * 15);
strHex += arrHex[index];
}
return strHex;
}

   var currentAngle = 0;
var drawCube2 = function () {
cxt2.clearRect(0, 0, 1200, 1200);
init();
changedistance2();
cxt2.strokeStyle = randomColor();
cxt2.beginPath();
cxt2.moveTo(startX + Points[0].x, startY - Points[0].y);
cxt2.lineTo(startX + Points[1].x, startY - Points[1].y);
cxt2.lineTo(startX + Points[2].x, startY - Points[2].y);
cxt2.lineTo(startX + Points[3].x, startY - Points[3].y);
cxt2.lineTo(startX + Points[0].x, startY - Points[0].y);
cxt2.moveTo(startX + Points[4].x, startY - Points[4].y);
cxt2.lineTo(startX + Points[5].x, startY - Points[5].y);
cxt2.lineTo(startX + Points[6].x, startY - Points[6].y);
cxt2.lineTo(startX + Points[7].x, startY - Points[7].y);
cxt2.lineTo(startX + Points[4].x, startY - Points[4].y);
cxt2.moveTo(startX + Points[1].x, startY - Points[1].y);
cxt2.lineTo(startX + Points[5].x, startY - Points[5].y);
cxt2.moveTo(startX + Points[0].x, startY - Points[0].y);
cxt2.lineTo(startX + Points[4].x, startY - Points[4].y);
cxt2.moveTo(startX + Points[2].x, startY - Points[2].y);
cxt2.lineTo(startX + Points[6].x, startY - Points[6].y);
cxt2.moveTo(startX + Points[3].x, startY - Points[3].y);
cxt2.lineTo(startX + Points[7].x, startY - Points[7].y);
cxt2.stroke();
}
drawCube2()
var rotateAsync = eval(Jscex.compile("async", function () {
while (true) {
currentAngle += 5;
drawCube2();
\$await(Jscex.Async.sleep(100));
}
}));

# 演示

Your browser does not support the canvas element.

    for (var i = 0; i < Points4.length; i++) {
var tempY = Points4[i].y;
Points4[i].y = Points4[i].z * Math.sin(angle) - Points4[i].y * Math.cos(angle);
Points4[i].z = tempY * Math.sin(angle) + Points4[i].z * Math.cos(angle);
}

# 演示

Your browser does not support the canvas element.

    function rotate(angle) {
for (var i = 0; i < Points2.length; i++) {
var tempX = Points2[i].x;
var tempZ = Points2[i].z;
Points2[i].x = Points2[i].x * Math.cos(angle) - Points2[i].z * Math.sin(angle);
Points2[i].z = Points2[i].z * Math.cos(angle) + tempX * Math.sin(angle);
}
for (var i = 0; i < Points2.length; i++) {
var tempY = Points2[i].y;
Points2[i].y = Points2[i].y * Math.cos(angle) - Points2[i].z * Math.sin(angle);
Points2[i].z = tempY * Math.sin(angle) + Points2[i].z * Math.cos(angle);
}
}

# 演示

Your browser does not support the canvas element.