当前位置: 首页 > 编程日记 > 正文

three.js(六) 地形法向量生成

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

上一节采用 分形算法生成地形的高度值, 接着我们需要生成每个顶点的法向量。

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

相关文章:

ASP.NET中使用多个runat=server form

作者&#xff1a;未知ASP.NET 在同一个页面不支持多个 runatserver forms&#xff0c;要解决这个问题&#xff0c;可以把每个 form 放在一个单独的 panel 控件中&#xff0c;这样用户就可以简单地通过单选按钮在不同 panel 间切换。代码如下&#xff1a;2FormExample.aspx<%…

激发企业大“智慧” | 深度赋能AI全场景 揭秘你不知道的移动云

2020年是人工智能技术发展的关键年。疫情之下&#xff0c;世界见证了人工智能在抗击疫情中发挥的积极作用&#xff1b;今年4月&#xff0c;国家发改委正式将人工智能确定为新基建的重要领域之一。在历史机遇下&#xff0c;AI已实现"质变和量变"&#xff0c;正迈入与技…

ExtJS 4.x 得到资源树上任意的节点对象

上半年做ExtJS 4.x 的时候&#xff0c;遇到过对资源树操作的情况&#xff1a; Ext.tree.Panel 如下图&#xff1a;目的&#xff1a; 直接根据每个节点的{任意key : 对应value}&#xff0c;就能找到匹配的节点对象 代码如下&#xff1a; refs : [ { selector : rtree, …

【转载】mysql常用函数汇总

转载地址&#xff1a;http://www.jb51.net/article/40179.htm 一、数学函数ABS(x) 返回x的绝对值BIN(x) 返回x的二进制&#xff08;OCT返回八进制&#xff0c;HEX返回十六进制&#xff09;CEILING(x) 返回大于x的最小整数值EXP(x) 返回值e&#xff08;自然对数的底&…

有关java的一些话

2019独角兽企业重金招聘Python工程师标准>>> 跟着做完TankWar&#xff0c;java才算是入门了&#xff0c;真正学习java从看尚学堂马士兵老师的视频开始&#xff0c;至今三个月已过&#xff0c;感谢马老师的精彩讲解&#xff0c;您才是我真正的java入门老师&#xff0…

ADO.NET 2.0中的SqlCommand.ExecutePageReader

http://blog.joycode.com/liuhuimiao/在.NET 2.0 PDC或Beta1中&#xff0c;可以看到SqlCommand对象新增了个ExecutePageReader方法&#xff0c;该方法实现了分页读取数据的功能。对于分页读取数据&#xff0c;在ADO.NET1.1中&#xff08;当然2.0也适合&#xff09;一般常用动态…

组合游戏系列5: 井字棋、五子棋AlphaGo Zero 算法实战

来源 | MyEncyclopedia上一篇我们从原理层面解析了AlphaGo Zero如何改进MCTS算法&#xff0c;通过不断自我对弈&#xff0c;最终实现从零棋力开始训练直至能够打败任何高手。在本篇中&#xff0c;我们在已有的N子棋OpenAI Gym 环境中用Pytorch实现一个简化版的AlphaGo Zero算法…

2020职场人裸辞三大原因:不开心、工资低、没有盼头

近期&#xff0c;脉脉发布了《2020职场人裸辞现状调研报道》&#xff0c;报道显示2020最让职场人想裸辞的三大原因为&#xff1a;不开心、工资低、没有盼头。报告数据中还显示&#xff0c;工资不满预期是最让人想要裸辞的主要原因&#xff0c;但有超过6成职场人表示&#xff0c…

Oracle PL/SQL编程学习笔记:Merge方法的使用

Oracle11g的Merge很强大&#xff01; 1 create or replace procedure BRANCE_REPORT_MERGE is2 3 begin4 Merge into BRANCHREPORT desttable5 using TEMP_BRANCHREPORT tmptable6 on (desttable.SENDER_IDtmptable.SENDER_ID and desttable.BRANCH_IDtmptable.BRANCH_ID…

2.0中获取数据库连接统计数据

作者&#xff1a; http://blog.joycode.com/liuhuimiao/.NET 2.0中的SqlConnection多了一个StatisticsEnabled属性和ResetStatistics()、RetrieveStatistics()两个方法&#xff0c;用于获取SQLServer的连接统计数据。当然&#xff0c;这样做是以性能损耗为代价的&#xff0c;但…

Python学习day5作业-ATM和购物商城

Python学习day5作业Python学习day5作业ATM和购物商城作业需求ATM&#xff1a;指定最大透支额度可取款定期还款&#xff08;每月指定日期还款&#xff0c;如15号&#xff09;可存款定期出账单支持多用户登陆&#xff0c;用户间转帐支持多用户管理员可添加账户、指定用户额度、冻…

60分钟看懂HMM的基本原理

作者 | 梁云1991来源 | Python与算法之美HMM模型&#xff0c;韩梅梅的中文拼音的缩写&#xff0c;所以又叫韩梅梅模型&#xff0c;由于这个模型的作者是韩梅梅的粉丝&#xff0c;所以给这个模型取名为HMM。开玩笑&#xff01;HMM模型&#xff0c;也叫做隐马尔科夫模型&#xff…

获取远程网卡MAC地址

出自&#xff1a; http://blog.joycode.com/liuhuimiao/朋友mingal急问我有关获取远程网卡MAC地址的ASP.net实现。我一开始以为是获取本机MAC地址&#xff0c;说了几种方法给他。由于他还需要获取服务器&#xff08;本机&#xff09;相关信息&#xff0c;如硬盘序列号、CPU信息…

[hadoop源码阅读][9]-mapreduce-概论

hadoop的mapreduce的运行流程大概就是如下图所示了 如果要是文字描述,估计要大篇幅了,大家可以参考下面的参考文档. 参考文档 1.http://caibinbupt.iteye.com/blog/336467 2.http://hadoop.apache.org/docs/r0.19.2/cn/mapred_tutorial.html 3.http://developer.yahoo.com/hado…

【小白的CFD之旅】小结及预告

这是小白系列的索引&#xff0c;后续会继续更新。 已更新的部分 01 引子02 江小白03 老蓝04 任务05 补充基础06 流体力学基础07 CFD常识08 CFD速成之道09 初识FLUENT10 敲门实例11 敲门实例【续】12 敲门实例【续2】13 敲门实例【续3】14 实例反思15 四种境界16 流程17 需要编程…

Kaggle金牌得主的Python数据挖掘框架,机器学习基本流程都讲清楚了

作者 | 刘早起来源 | 早起Python导语&#xff1a;很多同学在学习机器学习时往往掉进了不停看书、刷视频的&#xff0c;但缺少实际项目训练的坑&#xff0c;有时想去练习却又找不到一个足够完整的教程&#xff0c;本项目翻译自kaggle入门项目Titanic金牌获得者的Kernel&#xff…

input type右对齐与只读的

右对齐的 <input type"text" style"background:#efefef; text-align:right" readonly value"this" /> 只读的input <input type"text" name"nodeCode" readonly value"<%functionNodeForm.getNodeCode()%…

如何从sdcard读取文件

2019独角兽企业重金招聘Python工程师标准>>> 首先&#xff0c;我们必须明白文件储存格式是有许多种的&#xff0c;如utf-8,unicode等。 那么&#xff0c;我们如何将文件原封不动的读取出来呢&#xff0c;我们可以设定&#xff0c;文件储存的绝对路径为filepath。则代…

HDU 2034 人见人爱A-B

人见人爱A-B Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 77157 Accepted Submission(s): 21509 Problem Description参加过上个月月赛的同学一定还记得其中的一个最简单的题目&#xff0c;就是{A}{B}&#…

Java中的包,类的导入,静态导入

包的作用 1. 为了更好的组织代码&#xff0c;能够将自己的代码与代码库的代码分离。 2. 在需要合作完成的工作中&#xff0c;可以使用分包的方式来尽量的减少类命名的冲突。 Sun公司推荐程序员使用公司域名的反向字符作为公司项目的起始包名&#xff1a;如 baidu.com --> c…

实现800*600,1024*768两套分辨率方案

下面这段代码&#xff0c;可以实现800*600,1024*768两套分辨率方案。 <html><head><title>Untitled Document</title><script language"javascript">function go(){var myWidthscreen.widthif (myWidth>800){window.location.repl…

倒计时 4 天!高通人工智能应用创新大赛颁奖典礼线上隆重举行

经过7 个月的激烈角逐&#xff0c;由高通公司&#xff08;Qualcomm&#xff09;、中国智谷重庆经开区、CSDN、Testin云测、OPPO、极视角、中科创达、创业邦联合主办&#xff0c;重庆经开区高通中国中科创达联合创新中心协办&#xff0c;TensorFlow Lite 作为开源技术合作伙伴的…

IOS分享扩展使用JS脚本

2019独角兽企业重金招聘Python工程师标准>>> 实现一个分享扩展插件&#xff0c;功能是从Safari网页中截取当前网页的图片内容 基本的步骤总结在下面&#xff1a; 1.创建一个JS文件&#xff0c;命名为MyJavascriptFile.js&#xff0c;文件的功能是解析safari网页内容…

电脑人会得哪些病----------关注健康,关爱生命!

作者&#xff1a;未知 随着科技水平的提高&#xff0c;现代办公室综合症&#xff0c;特别是高科技病渐渐成为现代职业病。电脑可以说是本世纪最伟大的发明之一&#xff0c;有了它&#xff0c;人们工作、生活、学习的方式都出现了划时代的改变&#xff0c;随着网络与电脑的普及&…

IOS上传图片的方法

下面是图片上传的方法&#xff1a;-(void)loadImage:(NSString*)aurl{NSData *imageData;NSMutableData *postBody;NSString *stringBoundary, *contentType;NSURL *url [NSURL URLWithString:aurl]; //将字符串转换为NSURL格式NSArray *paths…

企业数字化转型,AI平台能力建设是关键

企业数字化转型迎来一波又一波热潮。 IDC研究数据显示&#xff0c;目前中国已有41.4%的企业成为数字化转型的坚定者&#xff0c;到2023年&#xff0c;全球超过一半的GDP将由数字化转型企业的产品和服务推动。 加速数字化转型、让业务智能化&#xff0c;许多行业均认可这是全面…

CSS中连接属性的排序

在CSS超链接的属性中&#xff0c;有四个连接方式: a:link a:hover a:visited a:acticve 之前在使用的时候一直是按照自认为的顺序中去写的&#xff0c;就是 L H V A的排序方式&#xff0c;然而有些时候却发现并不起作用了&#xff0c;查找了一些资料&#xff0c;也上网查找了一…

Spring源代码解析(十):Spring Acegi框架授权的实现

我们从FilterSecurityInterceptor我们从入手看看怎样进行授权的&#xff1a; Java代码 //这里是拦截器拦截HTTP请求的入口 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException …

可租赁、可定制的虚拟人居然还能这么玩?9月25日来百度大脑人像特效专场一探究竟!...

百度大脑自2016年启动开放以来&#xff0c;已打造成为业内最全面、最领先的AI开放平台&#xff0c;服务规模、调用量都居于业界第一。百度大脑开放日于2019年开办&#xff0c;覆盖北/上/深等地区&#xff0c;成为众多AI开发者、合作伙伴近距离沟通及深度交流&#xff0c;一起分…

提供前进、后退功能及其他JAVASCRIPT速成秘诀

通过了解下面的一些例子&#xff0c;并运用到你的WEB中&#xff0c;不久你马上成为JAVASCIPT的高手。 例&#xff08;一&#xff09;、在页面加入当前时间 < script languageJavaScript > tdynew Date(); document.write(当前时间:,tdy.getHours()); document.write(:,td…