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

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

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

本系列的所有演示都是3D骨架,非3D实体。本文将穿插图片、公式、代码、演示,让读者深刻理解3D的基本概念极其思想。

 

对象及概念介绍

对象一:摄像机。

大家都有一个基本常识,在不同的角度观看到的物体是不同的。摄像机对象有自己的空间的坐标(vidiconX,vidiconY,vidiconZ)。

对象二:显示屏

任何三维物体,都会以二维的形式投影在显示屏上,显示屏垂直于摄像机的观测方向,所以摄像机的空间坐标变化,会导致显示屏的坐标系的变换

对象三:被观察测物体

任何物体都是有无数个点构成,每个点有自己的空间坐标(x,y,z),显示屏介于摄像机和物体之间。

 

为了降低复杂度,本文将显示屏和被观测物体所处的坐标系公用一套(x,y),所有的旋转都是物体旋转,摄像机不动!

缩放原理:摄像机不动,被观察测物体不动,显示屏离摄像机越近,缩放比例越小,显示屏离摄像机越远,缩放比例越大。


投影分析

我们来看下面这张图:

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

 

因为,我们将显示屏和被观测物体共用一个坐标系,所以,我们可以计算出点(x1,y1,z1)投影到显示屏上的点的缩放比例为:

h / Math.abs(vidiconZ - z1)

所以投影后的坐标为:

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

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

 

有了以上这些知识,我们可以轻松的在Canvas里画一个正方体(再次强调,是根据计算的结果画,非人类经验)。

 <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" />

演示

相关文章: