three.js(六) 地形法向量生成
2019独角兽企业重金招聘Python工程师标准>>>
上一节采用 分形算法生成地形的高度值, 接着我们需要生成每个顶点的法向量。
three.js 的PlaneGeometry 自带有法向量, 法向量分为两种 即 平面法向量 和 平面每个定点法向量。
因此一个n*n 块组成的平面, 有n*n 个平面法向量, 有4*n*n 个顶点法向量。
这两种法向量区别是, 如果材质的shading属性是THREE.SmoothShading 则采用顶点法向量, 如果不是则采用平面法向量, 平面法向量 导致整个面上的法向量处处相同,所以光照可能不够真实。
平面几何体的顶点数组是(n+1)*(n+1)的长度, 因此其法向量数组长度也应该是(n+1)*(n+1) 才合适, 而如果遍历面 将会产生4*n*n个向量, 如何修正这个问题呢?
平面几何体在绘制的过程中, 由sortFacesByMaterial 函数处理生成几何体组。
首先根据材质对几何体分组,
材质编号_当前材质几何体组编号 作为几何体组的标识。
接着将相应的平面块 压入到对应的几何体组中。
控制每个几何体组的定点个数 小于 65535.
为几何体组编全局id号, 并将几何体组压入到 几何体组的List中
geometry.geometryGroups----->map形式访问几何体组
geometry.geometryGroupList-----> 数组形式访问几何体组
首先构建顶点 法向量 tangent, 颜色, 纹理坐标, 面, 线 等buffer。
接着初始化这些buffers。
接着在setMeshBuffers 中为这些buffer赋值, 根据每个独立的面都有将(n+1)*(n+1)个定点值写入到 4*n*n的顶点数组中去,
用户自己定义的属性,如果按照点绑定,则根据面的数量将(n+1)*(n+1)个值写入到 4*n*n 长度的数组中。
如果按照面绑定则把 n*n 个值 写入到 4*n*n 个长度的数组中。
通过以上我们可以看到,绘制平面的时候, 虽然我们只写了(n+1)*(n+1)个定点值,但是引擎实际扩展到 4*n*n 个值,这样最大化了空间的使用,具有最大的灵活性。
知道了引擎的处理方法,我们构建一个(n+1)*(n+1)的shader属性,默认绑定在顶点上,接着计算向量值并赋值给这个属性就可以了。
材质如下:
var pmat = new THREE.ShaderMaterial({uniforms:{texture_grass:{type:'t', value:0, texture:THREE.ImageUtils.loadTexture("grassa512.bmp")},texture_rock:{type:'t', value:1, texture:THREE.ImageUtils.loadTexture("dirt512.bmp")},light:{type:'v3', value:new THREE.Vector3()},maxHeight:{type:'f', value:0},minHeight:{type:'f', value:1},},attributes:{displacement: {type:'f', value:[]},vexNormal:{type:'v3', value:[]},},vertexShader: document.getElementById("vert").textContent,fragmentShader: document.getElementById("frag").textContent,});
其中vertexNormal 就是逐顶点法向量,当然我们也可以直接修改默认每个面块的法向量或者修改平面法向量这两种方法都不方便,所以还是使用一个额外的属性来处理。
这个属性是v3 类型即对应的THREE数据类型是Vector3, 法向量的生成,对于每一个定点其左右定点连接的向量和上下顶点连接的向量的叉乘, 作为自身的法向量。
var v1 = new THREE.Vector3();var v2 = new THREE.Vector3();var distX = 2*3/(WIDTH-1);var distY = 2*3/(HEIGHT-1);var vexNormal = pmat.attributes.vexNormal.value;var vertices = pmesh.geometry.vertices;var lmat = new THREE.LineBasicMaterial({color:0xff0000});for(var i = 0; i < vertices.length; i++){var row = ~~(i/WIDTH);var col = i%WIDTH;var left = (col-1+WIDTH)%WIDTH;var right = (col+1)%WIDTH;var up = (row-1+HEIGHT)%HEIGHT;var bottom = (row+1)%HEIGHT;var l = value[row*WIDTH+left];var r = value[row*WIDTH+right];v1.set(distX, 0, r-l);var u = value[up*WIDTH+col];var b = value[bottom*WIDTH+col];v2.set(0, distY, b-u);v1.crossSelf(v2.clone()).normalize();vexNormal.push(v1.clone());var lgeo = new THREE.Geometry();lgeo.vertices.push(new THREE.Vertex());lgeo.vertices.push(new THREE.Vertex(v1.clone()));var line = new THREE.Line(lgeo, lmat);line.position.set(vertices[i].position.x, vertices[i].position.y, value[i]);pmesh.add(line);}
这里计算的法向量是属于物体空间的, 在shader中我们需要将其转化成世界坐标, normalMatrix 是 世界视图modelView 矩阵的逆转置, 不能将法向量转化到世界坐标,因此,我们传入一个额外的矩阵, 当前引擎似乎只有mat4 的4*4 的矩阵, 因此我们传入4*4 objectMatrix 的逆转置。
normalWorldMatrix 是 要的矩阵。
var pmat = new THREE.ShaderMaterial({uniforms:{texture_grass:{type:'t', value:0, texture:THREE.ImageUtils.loadTexture("grassa512.bmp")},texture_rock:{type:'t', value:1, texture:THREE.ImageUtils.loadTexture("dirt512.bmp")},light:{type:'v3', value:new THREE.Vector3()},normalWorldMatrix:{type:'m4', value:new THREE.Matrix4()},maxHeight:{type:'f', value:0},minHeight:{type:'f', value:1},},attributes:{displacement: {type:'f', value:[]},vexNormal:{type:'v3', value:[]},},vertexShader: document.getElementById("vert").textContent,fragmentShader: document.getElementById("frag").textContent,//wireframe:true,});
将平面位置调整之后, updateMatrixWorld 更新平面的世界矩阵, 接着将平面的matrixWorld的逆转置赋值给normalWorldMatrix.
normalWorldmatrix.value.getInverse(pmesh.matrixWorld).transpose();
当然在shader里面我们只使用它的3*3 部分, 先将定点法向扩充成 4维 接着只取其前3维度即可。
nor = (normalWorldMatrix * vec4(vexNormal, 0)).xyz
当然加入法向量的目的是 计算光照, 在平面上方设置一个光源位置 作为uniform传入 light.
lightDir = light-pos;
diffuse = max(dot(normalize(lightDir), nor), 0); 作为系数影响亮度。
转载于:https://my.oschina.net/u/186074/blog/79070
three.js(六) 地形法向量生成相关推荐
- three.js 地形法向量生成
2019独角兽企业重金招聘Python工程师标准>>> 上一节采用 分形算法生成地形的高度值, 接着我们需要生成每个顶点的法向量. three.js 的PlaneGeometry 自 ...
- 支付宝支付 第六集:生成支付二维码
支付宝支付 第六集:生成支付二维码 一.资源 支付宝沙箱显示APP-ID错误:我的原因是支付宝网关地址写错了 支付宝沙箱环境报 invalid-app-id 错误原因: 无效的AppID参数 错误 支 ...
- html验证码功能如何实现原理,基于JS实现一个随机生成验证码功能
效果展示 实现原理 1. html:一般就是一个div: 2. JS:1)将所有的验证码所用的字符放在一个字符串中 2)在这个字符串的字符个数以内,随机生成索引号 3)根据索引号查找对应字符,拼接成验 ...
- 使用JS创建条形码在线生成工具-toolfk.com
本文要推荐的[ToolFk]是一款程序员经常使用的线上免费测试工具箱,ToolFk 特色是专注于程序员日常的开发工具,不用安装任何软件,只要把内容贴上按一个执行按钮,就能获取到想要的内容结果.Tool ...
- 使用gif.js根据视频片段生成GIF图
使用gif.js根据视频片段生成GIF图 文件引入 具体实现 扩展阅读 文件引入 根据视频片段来生成GIF需要用到gif.js文件,不多说,在这里先提供下载链接: gif.js. 简单介绍一下,核心库 ...
- 地形建模(一)——TIN地形的生成
地形建模可能算是三维gis的一个难点.之前在学校时做过一个简单的学校三维模型,本来是想做加上地形的,不过后来发现并不是那么容易所以就放弃了.最后做出来的学校模型除了建筑就只有几棵树,效果不是那么好. ...
- js将HTML导出生成word文档
在项目开发中中,遇到将HTML导出生成word文档,刚开始在网上找了很多资料,基本都是jQuery中的插件jquery.wordexport.js,刚开始是不想用这个的,这个要引用另一个插件FileS ...
- js版梅森旋转生成随机数
用js实现, 梅森旋转生成随机数, 来代替Math.random(); 该文章参考自 梅森旋转算法--伪随机数(加密.身份信息ID号)_Touch_Dream的博客-CSDN博客 <!DOCTY ...
- js前端根据链接生成二维码并转成图片下载
js前端根据链接生成二维码并转成图片下载 依赖于jquery.jquery.qrcode.min.js 1.html <div class="qrcode"></ ...
最新文章
- 机器视觉与计算机视觉的区别?
- java语言 U_Java语言的基础
- VMware虚拟机提示“以独占方式锁定此配置文件失败”解决方案
- jetty 通过配置文件嵌入式启动web服务
- kruskal 重构树(讲解 + 例题)
- 已知前序中序求层序 c语言递归,二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现...
- 【面试题】序列化的 10 几个问题
- C# 将PDF转为SVG的3种情况
- 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_23-页面查询服务端开发-Service及Controller...
- NYOJ题目1045看美女
- 浅谈人工智能时代下的工程伦理问题
- pad 迅雷 bt php_iOS永久版迅雷来了 BT、磁力链下载最全教程收好
- C#实现百度地图瓦片下载器(更新无水印版下载地址)
- GAMES101-现代计算机图形学入门-闫令琪 - lecture6 光栅化2(抗锯齿) - 课后笔记
- QQ聊天记录恢复、迁移教程(改变默认存储位置、个人文件夹保存位置)【转载】
- 无为而无不为——论老子哲学的深度悖论(转载)
- Arcgis根据矢量道路数据来提取道路中心线
- C语言中,求三个数中最大数
- 计算机网络 --- 物理层(学习笔记)
- 引入微信支付Java SDK WxPayAPI_JAVA.zip
热门文章
- ASP.NET 2.0 读取配置文件[INI](示例代码下载)
- Hessian源码分析(java)
- 关于模态对话框和非模态对话框的创建、显示,以及和父对话框的传值
- 【网络】通讯名词解释:带宽、速率、波特率、奈奎斯特定律、香农定理
- 【AI】caffe使用步骤(四):训练和预测
- 【C++】google gflags详解
- linux apache2.4 php,php5.6+apache2.4+linux如何搭建php环境
- php发布商品信息逻辑,php – 逻辑思考一个数据库结构:为用户发布的东西添加“标签” – 一个单独的表或……?...
- mysql 查询结果转置_转置MySQL查询 – 需要将行放入列中
- python模拟按键_python 模拟按键放在模拟器Python初学者的17个技巧