码农干货系列【8】--世界上最简单的3D渲染(no webgl)

rd3DPlane

简介

进行上图所示的3D格子地板的渲染,需要进行Canvas的像素级别操作,从视点连接屏幕(屏幕就是canvas)中的所有像素点,形成大量的射线,倘若射线与地板相交,把交点以及交点的颜色反馈给屏幕(canvas)。如下图所示:

image

像素操作

在进行3D渲染之前,必须了解Canvas的像素操作相关概念。在给定了width和height的canvas上,在坐标(x ,y)上的像素的index构成如下。

var data=getImageData(0, 0, canvas.width, canvas.height);

红色index:((width * y) + x) * 4          像素值:data[((width * y) + x) * 4]

绿色index:((width * y) + x) * 4 + 1    像素值:data[((width * y) + x) * 4+1]

蓝色index:((width * y) + x) * 4 + 2    像素值:data[((width * y) + x) * 4+2]

透明度index:((width * y) + x) * 4 + 3 像素值:data[((width * y) + x) * 4+3]

修改了任何像素的红、绿、蓝和alpha值之后,可以通过第二个函数来更新canvas上的显示,那就是context.putImageData(imagedata, dx, dy)。

寻找交点

怎么找到射线与地板的交点?可以先列出已知的条件:

视点坐标A、屏幕上的点坐标B、交点P的Y坐标(y=0),向量AP,BP共线。

根据上面的条件,利用两两向量共线(Ax-Px/Bx-Px = Ay-Py/By-Py = Az-Pz/Bz-Pz) 可以推导出交点的坐标。

格子材质

找到交点后,还剩下的问题就是根据z的坐标渲染格子材质,如下面代码所示:

 (Math.ceil(cv.x / sideLength) + Math.ceil(cv.z / sideLength)) % 2 === 0 

上面的cv为交点坐标,sideLength为地板格子编程,根据上面的true和false返回相应的颜色值。

在线演示

修改代码里面的变量值点击run again试试!
var Vector3 = function (x, y, z) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; var Camera = function (x, y, z) { this.x = x || 0; this.y = y || 0; this.z = z || 0; } var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); var imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height); var pixels = imgdata.data, i = 0, cm = new Camera(0, 200, 200), sideLength = 100, planeLength = 4400; for (var y = 0; y < canvas.height; y++) { for (var x = 0; x < canvas.width; x++) { var v = new Vector3(-canvas.width / 2 + x, canvas.height - y, 0); var cv = new Vector3(cm.y * v.x / (cm.y - v.y), 0, cm.z * v.y / (v.y - cm.y)); (cv.z > -planeLength && cv.z < 0) && (pixels[i] = pixels[i + 1] = pixels[i + 2] = (Math.ceil(cv.x / sideLength) + Math.ceil(cv.z / sideLength)) % 2 === 0 ? 148 : 0, pixels[i + 3] = 255 * (planeLength - Math.abs(cv.z)) / planeLength); i += 4; } } ctx.putImageData(imgdata, 0, 0);

Have Fun!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值