boombeach beach 里面的建筑物看起来是2d而场景是3d的这是怎样实现的呢?

【WebGL教程】Lesson6,了解OpenGL坐标系,实现并封装部分矩阵运算,通过矩阵运算实现一个2D线条模拟的3D场景
原创,转载请注明出处。系列教程: webgl-lesson.wysaid.org
时隔数月,终于把该了解的了解了很多。于是厚颜继续更新。废话不多说,由于本教程将不引入任何第三方库,所有demo的代码均使用WebGL&Javascript代码完整提供,而WebGL 并不提供矩阵相关的运算。 一旦涉及到3D,必然要先讲讲矩阵部分了。
首先是OpenGL的坐标系,我们须明确,OpenGL使用右手笛卡尔坐标系,从左到右x递增,从下到上y递增,从远到近z递增而通常我们的屏幕原点是在左上角,就xOy平面来说,y方向是反的。初始化状态下,当前viewport指定的窗口(画布)范围恰好为-1到1。也就是前面几章所有demo用到的范围(前面几章仅仅进行了平面处理,每次都重绘整张画布)
由于本教程仅针对WebGL,所以仅粗略的介绍相关运算的知识。看完依旧不清楚的请自行查阅相关资料。须知:本章知识并不需要完全掌握,只要会使用就行。本章会封装出一个webgl_matrix.js完成所有的矩阵运算,请不要完全跳过本章内容。
OpenGL 坐标系&坐标变换等的一些概念
世界坐标系
世界坐标系是在OpenGL中描述场景的坐标系。比如我们的三维世界中有一条线段AB,顶点A坐标为(Xa, Ya, Za), 顶点B坐标为(Xb, Yb, Zb),这里的A和B就属于世界坐标系
模型坐标系 &模型变换
模型坐标系是描述一个模型的坐标系。就比如上面提到的线段AB所构成的线段模型,如果它的长度为1, 那么A可以为(1, 0, 0), B为(0, 0, 0)。当然,我们可以有无数种A和B的组合让这条线段长度为1。 而把这里的A和B进行移位、旋转和缩放之后放到世界坐标系里面的过程叫做模型变换。较典型的OpenGL函数有glRotate, glTransform, glScale等
法向量变换
法向量用来计算光照,光照方向和法向量的夹角影响光的强度, 法向量也决定了物体是面向光还是背光。相关资料参考:()
视点坐标系 &视点变换
在OpenGL中没有单独的view matrix。而 GL_MODELVIEW 矩阵则是 Model Matrix(模型矩阵) 与 View Matrix (视觉矩阵) 的组合 (ViewMatrix * ModelMatrix )。较典型的视点变换函数为gluLookAt。 而由于 ViewMatrix为 左乘数, 所以我们一般对GL_MODELVIEW 进行 loadIdentity之后先进行gluLookAt。当然这些东西WebGL都是没有的,稍后我们将自己计算出相关矩阵。
裁剪坐标系 &投影变换
视点坐标系与投影矩阵相乘得到裁剪坐标系。投影矩阵定义了一个平截头体,将平截头体以内的场景作为绘制对象,超出部分裁剪掉。投影变换分为透视投影(perspective)和平行投影(ortho)。
规格化设备坐标系
将裁剪坐标系除以w所得(透视除法)。这一步在透视投影过程中称为透视除法(Perspective Division),这是透视投影变换的第2步,经过这一步,就丢弃了原始的z值(得到了规则观察体中对应的z值,篇幅所限,请自行查阅资料),顶点才算完成了投影。此步过后,x, y, z三个方向的坐标将被标准化(取值范围为[-1, 1]。
屏幕坐标系
将规格化设备坐标系通过viewport变换就可以得到屏幕坐标系。屏幕坐标系当然是仅包含x和y的,z值将作为深度信息确定一些遮挡问题(如果启用GL_DEPTH_TEST的话)。简单概括来就是,假如viewport为 x0, y0, w, h, 那么我们只需要下面的操作:
x = x0 + (x + 1) * w / 2;
y = y0 + (y + 1) * h / 2;
z = (z + 1) / 2;
讲得有点多,如果还是不大明白的话,不妨再看看这个: 。 这里将一些必要的算式以图片形式给了处理,非常便于理解。看不明白也没关系,继续往下看,知道怎么用的就好
好的,相关资料就介绍这么多,下面开始动手吧!
凡事讲究循序渐进,为了让本章内容更加深刻,本章demo将不使用WebGL,而使用HTML5方式,以普通2D线条模拟出3D模型的效果。(当然了, 须得简单结合上面的矩阵变换的知识,实现的效果也较为简单)
首先当然需要先创建一个图形界面了(个人喜好),样式如下:
那么这个demo需要些什么矩阵功能呢?
本demo将包含一个随机生成的较复杂的较大的模型和一个较简单的小立方体。由于教程窗口大小有限,大的模型不需要随便动,但是可以使用鼠标旋转。较小的立方体则不停地游荡和旋转。
所以我们需要的至少包含平行&透视投影矩阵算法,模型旋转矩阵算法。(其中模型移动的算法可有可无,因为我们使用HTML5方式模拟,可以把线条画到指定的坐标上。
最后我们还需要一个映射算法,将最终结果映射到屏幕上
其中矩阵算法部分较为复杂,并且不是必须掌握,所以不详细讲述。有兴趣的读者可以参阅,本章我编写了一个js文件,
这里简单讲述一下我编写的webgl_matrix.js里面的一些转换方法
在webgl_matrix.js里面包含三个我们需要用到的类,分别是三维向量WYVec3,四维向量WYVec4以及4×4矩阵WYMat4。
使用时可以直接new 一个这类对象出来使用。提供了本次demo需要用到(以及部分现在用不到,以后可能会用到)的方法。
当然,还有很多静态方法
比如 WYMat4.makeLookAt ,顾名思义,参数跟gluLookAt是一样的,生成一个该状态下的4×4矩阵。
WYMat4.makeOrtho, 参数跟glOrtho一样,生成一个该状态下的平行投影矩阵。
WYMat4.makePerspective, 参数跟gluPerspective一样,生成一个该状态下的透视投影矩阵。
还有一些比如旋转,平移之类的,就不多赘述了。
下面来详细讲一下怎么做吧。
首先当然是生成简单模型了。本次demo的模型超级简单,就是30~50个3维的点,然后我们把它们两两使用直线相连,就可以得到一个看起来还算比较立体的效果(30*29 = 870)。于是乎,我们的代码可能就是下面这样的:(部分代码,不完整。完整代码请参见末尾demo给出)
//生成大模型:
var bigModel =
function genBigModel(width, height, depth)
bigModel = new Array(30);
for(var i = 0; i != 30; ++i)
bigModel = new WYVec4(Math.random() * width * 2 - width,
Math.random() * height * 2 - height,
Math.random() * depth * 2 - depth,
//生成小模型:
var smallModel =
function genSmallModel(size)
smallModel = new Array(
new WYVec4(-size, -size, size, 1.0),
new WYVec4(size, -size, size, 1.0),
new WYVec4(size, size, size, 1.0),
new WYVec4(-size, size, size, 1.0),
new WYVec4(-size, -size, -size, 1.0),
new WYVec4(size, -size, -size, 1.0),
new WYVec4(size, size, -size, 1.0),
new WYVec4(-size, size, -size, 1.0));
if(cx & 0 || cx & viewport.data[2])
if(cy & 0 || cy & viewport.data[3])
smallModelViewMatrix = WYMat4.mat4Mul(smallModelViewMatrix, WYMat4.makeXRotation(Math.random() / 10.0));
smallModelViewMatrix = WYMat4.mat4Mul(smallModelViewMatrix, WYMat4.makeYRotation(Math.random() / 20.0));
smallModelViewMatrix = WYMat4.mat4Mul(smallModelViewMatrix, WYMat4.makeZRotation(Math.random() / 30.0));
function drawCanvas(cvsName)
var cvsObj = document.getElementById(cvsName);
var cvsContext = cvsObj.getContext("2d");
cvsContext.fillStyle="#000";
cvsContext.clearRect(0, 0, cvsObj.width, cvsObj.height);
cvsContext.fillText("鼠标点击红色区域可以旋转大的模型", 20, 20);
cvsContext.lineWidth = 2;
cvsContext.beginPath();
cvsContext.strokeStyle = "#ff0";
drawBigModel(cvsContext);
cvsContext.stroke();
cvsContext.closePath();
cvsContext.beginPath();
cvsContext.strokeStyle = "#00f";
drawSmallModel(cvsContext);
cvsContext.stroke();
cvsContext.closePath();
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
//模型转换矩阵:(初始化为单位矩阵)var modelViewMatrix = WYMat4.makeIdentity();var smallModelViewMatrix = WYMat4.makeIdentity(); //专给小模型使用&//投影矩阵:(初始化为大模型xOy平面下尺寸大小的平行投影)var perspectiveMatrix = WYMat4.makeIdentity();var orthoMatrix = WYMat4.makeIdentity();var usePerspective = true;&&//设置Flag标记是否使用透视投影。var projMatrix = perspectiveMatrix;&&//viewport大小也初始化为大模型xOy平面下尺寸大小var viewport = new WYVec4(0.0, 0.0, modelXMax, modelYMax);&//设置flag,标记当前使用的是什么方式的投影。var usePerspective = false;&//当画布大小改变时,我们需要做的事:function resizeCanvas(w, h){ viewport.data[2] = w; viewport.data[3] = h; if(usePerspective)
projMatrix = WYMat4.makePerspective(45.0, w / h, -1.0, 1.0); else
projMatrix = WYMat4.makeOrtho(0.0, w, 0.0, h, -1.0, 1.0) //使用默认的视点就够了,所以不乘以LookAt生成的矩阵.}&//定义一系列需要用到的变量(大模型,大模型默认参数,小模型,小模型参数等)var bigModel = null;var smallModel = null;var modelXMax = 250.0;var modelYMax = 250.0;var modelZMax = 250.0;var smallModeSize = 30.0;&//小模型运动参数var cx = 0;var cy = 0;var dx = Math.random() + 1;var dy = Math.random() + 1;&&// 接下来就是初始化矩阵函数,以及三个设置函数function resizeCanvas(w, h){ viewport.data[2] = w; viewport.data[3] = h; var len = (w & h ? w : h);& orthoMatrix = WYMat4.makeOrtho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -1.0, 1.0); perspectiveMatrix = WYMat4.makePerspective(45.0, w / h, -1.0, 1.0); modelViewMatrix = WYMat4.makeLookAt(0.0, 0.0, len, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); smallModelViewMatrix = WYMat4.makeTranslation(-w / 2.0, -h / 2.0, 0.0); if(usePerspective) {
projMatrix = perspectiveMatrix; } else {
projMatrix = orthoMatrix; }
cx = 0; cy = 0;}&//设置为平行投影function setOrtho(){ usePerspective = false; projMatrix = orthoMatrix;}&//设置为透视投影function setPerspective(){ projMatrix = perspectiveMatrix;}&//重置模型大小function resetModel(){ var len = (viewport.data[2] & viewport.data[3] ? viewport.data[3] : viewport.data[2]) / 2.0; genBigModel(len, len, len); genSmallModel(len / 20.0 + Math.random() * (len / 20.0));}&//接下来就是绘制函数。如下function drawBigModel(ctx){ var modelPoint = new Array(bigModel.length);& for(var i = 0; i & bigModel.length; ++i) {
modelPoint[i] = new WYVec3();
WYMat4.projectM4(bigModel[i], modelViewMatrix, projMatrix, viewport, modelPoint[i]); }& for(var i = 0; i & bigModel.length; ++i) {
for(var j = i+1; j & bigModel.length; ++j)
ctx.moveTo(modelPoint[i].data[0], modelPoint[i].data[1]);
ctx.lineTo(modelPoint[j].data[0], modelPoint[j].data[1]);
} } if(autoRotate) {
modelViewMatrix = WYMat4.mat4Mul(modelViewMatrix, WYMat4.makeXRotation(0.01));
modelViewMatrix = WYMat4.mat4Mul(modelViewMatrix, WYMat4.makeYRotation(0.01));
modelViewMatrix = WYMat4.mat4Mul(modelViewMatrix, WYMat4.makeZRotation(Math.random() / 100.0)); }}&function drawSmallModel(ctx){ var modelPoint = new Array(smallModel.length); for(var i = 0; i & smallModel.length; ++i) {
modelPoint[i] = new WYVec3();
WYMat4.projectM4(smallModel[i], smallModelViewMatrix, orthoMatrix, viewport, modelPoint[i]); }& for(var i = 0; i & smallModel.length; ++i) {
for(var j = i+1; j & smallModel.length; ++j)
ctx.moveTo(modelPoint[i].data[0] + cx, modelPoint[i].data[1] + cy);
ctx.lineTo(modelPoint[j].data[0] + cx, modelPoint[j].data[1] + cy);
} } ctx.fillText("这不是WebGL哟", modelPoint[0].data[0] + cx, modelPoint[0].data[1] + cy); cx += dx; cy += dy; if(cx & 0 || cx & viewport.data[2])
dx = -dx; if(cy & 0 || cy & viewport.data[3])
dy = -dy; smallModelViewMatrix = WYMat4.mat4Mul(smallModelViewMatrix, WYMat4.makeXRotation(Math.random() / 10.0)); smallModelViewMatrix = WYMat4.mat4Mul(smallModelViewMatrix, WYMat4.makeYRotation(Math.random() / 20.0)); smallModelViewMatrix = WYMat4.mat4Mul(smallModelViewMatrix, WYMat4.makeZRotation(Math.random() / 30.0)); }&function drawCanvas(cvsName){ var cvsObj = document.getElementById(cvsName); var cvsContext = cvsObj.getContext("2d"); cvsContext.fillStyle="#000"; cvsContext.clearRect(0, 0, cvsObj.width, cvsObj.height); cvsContext.fillText("鼠标点击红色区域可以旋转大的模型", 20, 20); cvsContext.lineWidth = 2; cvsContext.beginPath(); cvsContext.strokeStyle = "#ff0"; drawBigModel(cvsContext); cvsContext.stroke(); cvsContext.closePath(); cvsContext.beginPath(); cvsContext.strokeStyle = "#00f"; drawSmallModel(cvsContext); cvsContext.stroke(); cvsContext.closePath();}
至此,我们的工作大致完成。当然,有一部分界面控制代码就不详细说明了。我们的demo效果如下(鼠标拖拽红色部分可以旋转模型)
也许你觉得并不稀奇,但是本demo没有用到WebGL的API,所以,是纯2D线条画出来的哟。
完整的demo点击下面的按钮打开。请自行右键另存代码并查看。第六期教程到此为止,请关注lesson 6。系列教程地址:webgl-lesson.wysaid.org
转载本Blog文章请注明出处:
2016年九月
11121314151617
18192021222324
252627282930
INDEX
2016年七月 &(2)
2015年七月 &(2)
2015年一月 &(1)
2014年十二月 &(1)
2014年九月 &(1)
2014年八月 &(1)
2014年六月 &(2)
2014年五月 &(4)
2014年四月 &(1)
2014年三月 &(3)
2014年一月 &(2)
2013年十二月 &(5)
2013年十一月 &(1)
2013年十月 &(2)
2013年九月 &(4)
2013年八月 &(1)
2013年七月 &(3)
2013年六月 &(3)
2013年五月 &(14)
2013年四月 &(8)
2013年三月 &(2)
2013年二月 &(2)
2013年一月 &(9)
2012年十二月 &(1)
2012年十一月 &(1)
选择分类目录知道2D.3D。那2.5D是什么效果?来张图片 ~求大神帮助_百度知道[text]返回顶部&/&其实我一直不明白 为什么老是有人觉着3d的成本会比2d的低围观&?&&0评论&?&&0香蕉&/&&&/&&已收藏&/&&/&其实我一直不明白 为什么老是有人觉着3d的成本会比2d的低
& 并非引战,只是来探讨一下。
首先就这个问题,我先来分析一下为何会有人持有这种意见。(以下讨论皆以最顶级的2d动画以及3d动画为标准,国产坑爹3d动画不在讨论范围)
一般来说,现在好多动画里面为了降低成本会使用一些3d画面代替。原因自然是为了节省成本,但不知道为何,这让一些人形成了3d成本比2d低的错觉。我想他们根本没有想过,高模底模的问题吧。一般2d动画里面的3d场景普遍都是低成本的底模,渲染也简单,用来代替某些手绘复杂的场景无可厚非,成本会比2d低也是很正常的。但实际在制作3d动画的时候,建模都是高模啊,那些动画渲染一台大型机渲染一秒钟都需要好几个小时,感觉电费都够画几P原画了。
其次就是,不知道为啥总是有人认为3d动画就是建好模型之后,随便动,就跟玩游戏一样。& 我实在不知道他们为何会有这种想法,真的。难道3d动画制作渲染不是最慢的吗? 而且3d动画还要考虑粒子效果,毛皮效果、碰撞体积、光阴反射等等,光是调试这些数据参数就不是一般人干的好不。而且3d动画也要画2d原画的好不,分镜也是手绘,也很麻烦的好不。
而且总感觉这些人根本不知道现在动画基本都是1拍2或者1拍3的,实际上一般一秒钟只需要12张或者8张原画就够了。 &怎么看着8张原画成本也没想象中高啊,就算是某些公司,丧心病狂1拍1,一秒24张原画, &就算一张原画100块,24张原画2400rmb,算上其他分摊的成本,2d动画一秒钟撑死10000rmb吧(这算的真的很高了,实际上我估计算上定格,重复画面,一秒标准的12张原画,一秒钟成本应该也就是rmb的样子,这应该是非常精良的制作了)
好吧,同样算算顶级的3d动画,就拿迪斯尼跟皮克斯的来说吧,成本怎么算不知道,但是一般迪斯尼、皮克斯的制作成本都能查到。
海底总动员 100 分钟 6300w美刀 1w+美刀每分钟
飞屋环游记 96分钟 1.75亿美刀 &单位时间不算了
冰雪奇缘 & &102分钟 1.5亿美刀 &同上,不算了
算了,我也不列了。 &这些3d动画成本一秒钟基本都是上几千到上万美刀。 &成本最少是最精良的2d动画的10倍。
本来想搜搜那些2d动画的制作成本的,但根本搜不到,只能自己估算。
最后说一下,这只是单纯对比两种动画制作方式的成本而已。并无他意,只是天天看到有人扯淡2d动画制作比3d动画困难成本也高有感而发而已。&
事实上两种动画类型的对视觉传单的感官是完全不一样的。
3d动画很难做出乒乓或者KLK那样的动画,毕竟手绘的东西可以随心所欲的变形,那种画面的拉伸感以及纵深感,是3d无法比拟的。但就画面的张力来说,2d绝对是3d或者真人无法比拟的。对于静态画面的表现同样如此。在表达抽象画面以及人物意境的时候,有着无法比拟的先天优势。
但相对的2d对于连贯动作的表现欠佳,对于大场景的表现也不如3d,细节的传达也颇受限制。在一些具象的画面上显得不尽人意。
总的来说,互有优势。成本更质量是没有什么太大关系的。其实我一直不明白 为什么老是有人觉着3d的成本会比2d的低该投稿暂无简介一些牢骚话而已,不喜欢的可以右上。一些牢骚话而已,不喜欢的可以右上。[+展开简介]投1蕉安利给基友官方下载友情链接反馈本站不提供任何视听上传服务,所有内容均来自视频分享站点所提供的公开引用资源。Copyright (C)
AcFun. 保留所有权利

参考资料

 

随机推荐