创建一个HTML5的3D引擎

我们知道三维投影平面上的点映射到一个二维,三维点定义一个对象….不幸的是,计算三维可能会是相当复杂的代码。我们怎样才能简化它?



如果我们定义平面旋转角与theta 相关,三维投影计算忽然变得简单!

任何在三维平面点可以定义为具有以下两个方程描述沿着一个椭圆的边缘点:

x = A  * cos(theta)
y = B * sin(theta)
其中A是椭圆的宽/2,B是椭圆的高/2
 
下面是平面示意图:


这种特殊的三维形状是由三横截面– 上,中,底平面组成,这些是我们遐想的所有使用的点,也是我们需要渲染的3d对象。

下面是看下HTML5的3D引擎的代码:

<style>
body {
margin:0px;
padding:0px;
}
#myCanvas {
border:2px solid #D2D2D2;
}
</style>

<script>


var canvas=null;
var c=null;
var canvasWidth=576;
var canvasHeight=400;
var t=0;

var myShape = null;

function Shape(topPlane, centerPlane, bottomPlane) {
this.topPlane=topPlane;
this.centerPlane=centerPlane;
this.bottomPlane=bottomPlane;

this.rotate = function(newTheta) {
topPlane.rotate(newTheta);
centerPlane.rotate(newTheta);
bottomPlane.rotate(newTheta);
}

this.generatePlanes = function() {
topPlane.generate();
centerPlane.generate();
bottomPlane.generate();
}
}

// This simple 3-d engine was provided by www.crazyfrom.com for the purpose of creating 3-d HTML5 renderings.
// December 20, 2010
function Plane(centerX,centerY, planeLength, planeWidth, planeTilt, planeTheta) {
this.centerX = centerX;
this.centerY = centerY;
this.planeLength = planeLength;
this.planeTheta = planeTheta;

var lastPerspectiveX = null;
var lastPerspectiveX2 = null;
var planeNextCornerAngle = 2*Math.asin(planeWidth/planeLength);

this.rotate = function(newTheta) {
planeTheta = newTheta - planeNextCornerAngle/2;
}

this.translate = function(newCenterX, newCenterY) {
centerX = newCenterX;
centerY = newCenterY;
}

this.generate = function() {
var ovalLength = planeLength;
var ovalWidth = ovalLength * planeTilt;

var perspectiveX = (ovalLength / 2) * Math.cos(planeTheta);
var perspectiveY = (ovalWidth / 2) * Math.sin(planeTheta);
var perspectiveX2 = (ovalLength / 2) * Math.cos(planeTheta + planeNextCornerAngle);
var perspectiveY2 = (ovalWidth / 2) * Math.sin(planeTheta + planeNextCornerAngle);

this.topLeftX = (perspectiveX *1) + centerX;
this.topLeftY = (perspectiveY * -1) + centerY;
this.bottomRightX = (perspectiveX*-1) + centerX;
this.bottomRightY = (perspectiveY*1) + centerY
this.topRightX = (perspectiveX2 *1) + centerX;
this.topRightY = (perspectiveY2 *-1) + centerY;
this.bottomLeftX = (perspectiveX2 *-1) + centerX;
this.bottomLeftY = (perspectiveY2 *1) + centerY;
}
}

function clearCanvas() {
canvas.width = 1;
canvas.width = canvasWidth;
}

function init () {
canvas=document.getElementById("myCanvas");
c=canvas.getContext("2d");
canvas.width = canvasWidth;
canvas.height = canvasHeight;

var topPlane = new Plane(288,150, 100,70,0.5,theta);
var centerPlane = new Plane(288,200,600,70,0.5,theta);
var bottomPlane = new Plane(288,250, 100,70,0.5,theta);

myShape = new Shape(topPlane, centerPlane, bottomPlane);

//drawScreen();

updateScreen();
}

var theta = 0; // top left

function drawScreen() {

var lineWidth = 2;

myShape.rotate(theta);
//myPlane.translate(tankX, 100);
myShape.generatePlanes();

// draw front bottom of tank
c.beginPath();
c.moveTo(myShape.centerPlane.topLeftX, myShape.centerPlane.topLeftY); // top left
c.lineTo(myShape.centerPlane.topRightX, myShape.centerPlane.topRightY); // top right
c.lineTo(myShape.bottomPlane.topRightX, myShape.bottomPlane.topRightY); // bottom right
c.lineTo(myShape.bottomPlane.topLeftX, myShape.bottomPlane.topLeftY); // bottom left
c.closePath();

c.lineJoin="round";
c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();

// draw back bottom of tank
c.beginPath();
c.moveTo(myShape.centerPlane.bottomLeftX, myShape.centerPlane.bottomLeftY); // top left
c.lineTo(myShape.centerPlane.bottomRightX, myShape.centerPlane.bottomRightY); // top right
c.lineTo(myShape.bottomPlane.bottomRightX, myShape.bottomPlane.bottomRightY); // bottom right
c.lineTo(myShape.bottomPlane.bottomLeftX, myShape.bottomPlane.bottomLeftY); // bottom left
c.closePath();

c.lineJoin="round";
c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();

// draw front top of tank
c.beginPath();
c.moveTo(myShape.topPlane.topLeftX, myShape.topPlane.topLeftY); // top left
c.lineTo(myShape.topPlane.topRightX, myShape.topPlane.topRightY); // top right
c.lineTo(myShape.centerPlane.topRightX, myShape.centerPlane.topRightY); // bottom right
c.lineTo(myShape.centerPlane.topLeftX, myShape.centerPlane.topLeftY); // bottom left
c.closePath();

c.lineJoin="round";
c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();

// draw back top of tank
c.beginPath();
c.moveTo(myShape.topPlane.bottomLeftX, myShape.topPlane.bottomLeftY); // top left
c.lineTo(myShape.topPlane.bottomRightX, myShape.topPlane.bottomRightY); // top right
c.lineTo(myShape.centerPlane.bottomRightX, myShape.centerPlane.bottomRightY); // bottom right
c.lineTo(myShape.centerPlane.bottomLeftX, myShape.centerPlane.bottomLeftY); // bottom left
c.closePath();

c.lineJoin="round";
c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();

// draw top of tank
c.beginPath();
c.moveTo(myShape.topPlane.topLeftX, myShape.topPlane.topLeftY); // top left
c.lineTo(myShape.topPlane.topRightX, myShape.topPlane.topRightY); // top right
c.lineTo(myShape.topPlane.bottomRightX, myShape.topPlane.bottomRightY); // bottom right
c.lineTo(myShape.topPlane.bottomLeftX, myShape.topPlane.bottomLeftY); // bottom left
c.closePath();

c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();

if (isRightSideOfShapeInFront(myShape)) {
// draw right of tank
c.beginPath();
c.moveTo(myShape.topPlane.topRightX, myShape.topPlane.topRightY); // front
c.lineTo(myShape.centerPlane.topRightX, myShape.centerPlane.topRightY); // front
c.lineTo(myShape.bottomPlane.topRightX, myShape.bottomPlane.topRightY); // front
c.lineTo(myShape.bottomPlane.bottomRightX, myShape.bottomPlane.bottomRightY); // back
c.lineTo(myShape.centerPlane.bottomRightX, myShape.centerPlane.bottomRightY); // back
c.lineTo(myShape.topPlane.bottomRightX, myShape.topPlane.bottomRightY); // back
c.closePath();

c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();
}
else {
// draw left of tank
c.beginPath();
c.moveTo(myShape.topPlane.topLeftX, myShape.topPlane.topLeftY); // front
c.lineTo(myShape.centerPlane.topLeftX, myShape.centerPlane.topLeftY); // front
c.lineTo(myShape.bottomPlane.topLeftX, myShape.bottomPlane.topLeftY); // front
c.lineTo(myShape.bottomPlane.bottomLeftX, myShape.bottomPlane.bottomLeftY); // back
c.lineTo(myShape.centerPlane.bottomLeftX, myShape.centerPlane.bottomLeftY); // back
c.lineTo(myShape.topPlane.bottomLeftX, myShape.topPlane.bottomLeftY); // back
c.closePath();

c.strokeStyle="black";
c.lineWidth=lineWidth;
c.stroke();
c.fillStyle="blue";
c.fill();
}

}

function isRightSideOfShapeInFront(tankObj) {
if (tankObj.topPlane.topRightY > tankObj.topPlane.topLeftY) {
return true;
}
else {
return false;
}
}

function updateScreen() {
theta += .01 ; // radians
clearCanvas();
drawScreen();
setTimeout("updateScreen()", 10);
}

function handleMouseDown(e) {
var mouseX = e.clientX;
var mouseY = e.clientY;
}

function handleMouseMove(e) {
var mouseX = e.clientX;
var mouseY = e.clientY;
}

function handleMouseUp(e) {

}

</script>

<body οnlοad="init()">
<canvas id="myCanvas"></canvas>
</body>

可以点击下载demos

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值