在three.js中,世界three.js 坐标转换换成屏幕坐标应该怎么做

6229人阅读
最简单的地形是单一的平面, 这个通过
var geo = new THREE.PlaneGeometry(2, 2, 256, 256) 几何体构建, 可以设定平面的切分块的数量。
var pmesh = new THREE.Mesh(geo, material);
可以为平面提供纹理, 从而是地面看起来更真实一些,而纹理坐标在geo中已经自动设定好了。 因此只需要写材质就可以了。
这里使用ShaderMaterial 用于材质。
顶点shader:
varying vec2 vUV; //从定点shader 传递到 片段shader的纹理坐标
void main()
& & & vUV = //uv 是默认存在的顶点属性, 用于做纹理坐标
& & & gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);// projectionMatrix 默认存在的投影矩阵 modelViewMatrix默认模型视图矩阵 position定点坐标&
片段shader:
uniform sampler2D texture_//纹理
varying vec2 vUV;
void main()
& & &gl_FragColor = texture2D(texture_grass, vUV);
材质则是:
var mat = new THREE.ShaderMaterial({
& & &uniforms:{
& & & & & texture_grass:{type:'t', value:0, &texture:TRHEE.ImageUtils.loadTexture(&texture_grass.png&)},//类型纹理, 纹理编号0, 加载图片数据&
& & &attributes:{},
& & &vertexShader:text,
& & &fragmentShader:text,
var pmesh = new THREE.Mesh(geo, mat);
这样就得到一个添加了纹理的平面, 平面在x,y 平面上, 平面的正方向指向z正向, 可以调整平面x轴逆时针旋转90度, 得到x,z 方向的平面。
现在我们期望能够调整地面的高度, 采用的方式是鼠标点击屏幕位置, 计算实际的地面的位置, 接着调整地面上该点附近的所有定点的高度。
调整高度有两种方式, 一是调整geo几何体中的vertices 中的y值, 或者在修改shader程序 增加一个顶点属性, displacement 用于记录所有顶点的高度,这样只需要修改这一个数据就可以了,而不需要修改整个定点数组。
顶点shader调整:
varying vec2 vUV;
void main()
& & & &vUV =
& & & &gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy, &displacement, 1);
var mat = new THREE.ShaderMaterial({
& & & //其它部分相同
& & & &attributes:{
& & &displacement:{type:'f', &value:[]},
需要根据平面顶点个数 来初始化displacement值为0
for(var i = 0; i & geo.vertices. i++)
& & & mat.attributes.displacement.value.push(0);
因为需要动态调整displacement的值 所以需要设定geo是动态更新的
geo.dynamic =
这样现在仍只是看到一个平面;接下来需要设定鼠标点击的时间处理函数。
var projector = new THREE.Projector(); //计算从屏幕坐标到 世界坐标的工具
renderer.domElement.onmousedown = function(e){
& & &var mx = e.offsetX;
& & &var my = e.offsetY;
& & &//计算相机近平面上的坐标
& & & mx = 2*mx/SCREEN_WIDTH-1;
& & &my = 1 - 2*my/SCREEN_HEIGHT;
& & var vec = new THREE.Vector3(mx, my, 0);//只有 x y 坐标有意义
& & &var ray = project.pickingRay(vec, camera);//计算从相机发出的穿过近平面上mx my 点的射线
& & var intersects = ray.intersectObject(pmesh); //计算射线和 平面的所有交点 0 或者 1个
& & &if(intersects.length & 0)
& & & & & & //存在交点
& & & & & &updateDisplacement(intersects[0].point); //调整该点附近顶点的高度。
function updateDisplacement(point)
//平面方位 -1, 1 &-1, 1 x轴切分256份, WIDTH= 257, &y轴切分256份 , HEIGHT=257
//计算交点附近 0.1为边长的矩形框的上下左右范围, 接着计算geo中相应的定点的行和列范围。
//调整所有顶点的高度, 设定材质中的 mat.attributes.displacement.needsUpdate = &设定displacement需要更新
var radius = 0.05;
var left = point.x-
var right = point.x+
var bottom = point.z-
var up = point.z +
var rowGrid = 2/(HEIGHT-1);
var colGrid = 2/(WIDTH-1);
var rowBegin = ~~Math.max((bottom+1)/rowGrid, 0);
var rowEnd = ~~Math.min((up+1)/rowGrid, HEIGHT);
var colBegin = ~~Math.max((left+1)/colGrid, 0);
var colEnd = ~~Math.min((right+1)/colGrid, WIDTH);
for(var i = rowB i &= rowE i++)
for(var j = colB j &= colE j++)
var num = ~~(i*WIDTH+j);
//console.log(num);
pmesh.displacement.value[num] += 0.05;
//console.log(&new&, pmesh.displacement, pmesh.displacement.needsUpdate);
pmesh.displacement.needsUpdate =
& &通过设定几何体可以动态更新, &设定 材质中的属性需要更新, 则实现了调整displacement的目的。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:35154次
排名:千里之外
原创:19篇
(4)(3)(1)(9)(2)聚合阅读:关于 “Three.js” 的最新资讯内容
在这篇文章中,你们会看见一些收集到的Three.js demo演示效果,包括一些很实用的资源教程,从而能够鼓励我们深入学习关于这个库的原理和用法。
微信扫一扫Three.js教程
还记得点、线、面吗(一)
1、 学会画点、画线、画面的知识
2、 学会绘制复杂的图形
1、因为精彩,所以值得
还记得2000年左右有一个很不错的OpenGL教程《Nehe OpenGL》,大学时,我才有机会读到那么好的教程。那时,废寝忘食,花了一个月的时间看完了整个教程。觉得不过瘾,又读了一遍师兄翻译的中文教程。在当时,Nehe教程实为经典,第一个原因是当时OpenGL的资料非常罕见,无论是新华书店,还是互联网上都很难找到一本详尽的OpenGL教程。第二个原因是NeHe教程的作者确实非常用心,写出来很精彩的实例,并浅显易懂的讲解了它。
我一直认为,我写《WebGL中文网》的目的是为3D爱好者们提供一套精彩的入门和精通资料,这套资料不仅包含基础知识,而且包含工程级别的实例,更重要的是,那能让大家理解图形学知识。长此以来,很多同学在学习了计算机图形学后,对图形学的知识还是不能应用。有很大的原因,就是缺少理论化的实践,所以,这点,我们也考虑到了,一定在讲解示例的过程中,将其中的图形学原理也给阐述清楚。
以使大家认真学习后,能够在较短的时间学到我所学习的知识。
关于图形学这些知识,我是用了很多时间去摸索的,在资料匮乏的时候去掌握一门新的知识,确实是很费时间和脑力的事情,但是现在,有了本教程,你可以直通光明顶,学到可以胜任WebGL工作的技能。我想,这也是《WebGL中文网》的宗旨吧。
2、不从画鸡蛋开始,我们从画点开始
睁开您的眼睛,看看你的周围,它是一个多么美妙的3D世界啊。3D世界由什么组成,除了上帝,还有谁能够回答呢?
是的,没有人能够回答这个问题。但是在计算机世界里,3D世界由什么组成就很好回答。
1、3D世界的组成
在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,无数三角形面就能够组成各种形状的物体,如下图:
我们通常把这种网格模型叫做Mesh模型。给物体贴上皮肤,或者专业点就叫做纹理,那么这个物体就活灵活现了。最后无数的物体就组成了我们的3D世界。
那么3D世界的组成,是否真的这样简单?是的,从编程的角度,目前为此,你只需要知道这些。下一节,我们从点说起。
2、在Threejs中定义一个点
在三维空间中的某一个点可以用一个坐标点来表示。一个坐标点由x,y,z三个分量构成。在three.js中,点可以在右手坐标系中表示:
空间几何中,点可以用一个向量来表示,在Three.js中也是用一个向量来表示的,代码如下所示:
THREE.Vector3 = function ( x, y, z ) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
我们来分析这段代码:前面我们已经知道了THREE是Three.js引擎的一个全局变量。只要你想用它,就可以在任何地方用它。有点充气娃娃的意思,不需要你同意,你想用就用吧。
那么THREE.Vector3呢,就是表示Vector3是定义在THREE下面的一个类。以后要用Vector3,就必须要加THREE前缀。当然Three.js的设计者,也可以不加THREE这个前缀,但是他们预见到,Three.js引擎中会有很多类型,最好给这些类型加一个前缀,以免与开发者的代码产生冲突。
THREE.Vector3被赋值为一个函数。这个函数有3个参数,分别代表x坐标,y坐标和z坐标的分量。函数体内的代码将他们分别赋值给成员变量x,y,z。看看上面的代码,中间使用了一个“||”(或)运算符,就是当x=null或者undefine时,this.x的值应该取0。
3、点的操作
在3D世界中点可以用THREE.Vector3D来表示。对应源码为/src/math/Vector3.js(注意:源码所在的位置,可能不同版本不一样,请自己搜索Vector3关键词来确定)。在您继续学习之前,你可以打开该文件浏览一下,推荐使用WebStorm,如果没有,你也可以用NotePad++。
现在来看看怎么定义个点,假设有一个点x=4,y=8,z=9。你可以这样定义它:
var point1 = new THREE.Vecotr3(4,8,9);
另外你也可以使用set方法,代码如下:
var point1 = new THREE.Vector3();
point1.set(4,8,9);
我们这里使用了set方法,为了以后深入学习的方便,这里将Vector3的常用方法列出如下,为了不影响文章的连贯性,我们专门列出了一个网页来介绍它。
3、实例:画一条彩色线
初中数学中有一个定理:两个不重合的点能够决定一条直线。在three.js中,也可以通过定义两个点,来画一条直线。我们先看看,这一节,我们要完成实例的效果图:
例子说明:这是一条每个点不同颜色的线条
这个例子的代码如下所示,可以在“【初级教程\chapter2\2-1.html】”中找到这份代码:
&!DOCTYPE html&
&meta charset="UTF-8"&
&title&Three框架&/title&
&script src="js/Three.js"&&/script&
&style type="text/css"&
div#canvas-frame {
width: 100%;
height: 600
background-color: #EEEEEE;
function initThree() {
width = document.getElementById('canvas-frame').clientW
height = document.getElementById('canvas-frame').clientH
renderer = new THREE.WebGLRenderer({
antialias : true
renderer.setSize(width, height);
document.getElementById('canvas-frame').appendChild(renderer.domElement);
renderer.setClearColor(0xFFFFFF, 1.0);
function initCamera() {
camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.x = 0;
camera.position.y = 1000;
camera.position.z = 0;
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.lookAt({
function initScene() {
scene = new THREE.Scene();
function initLight() {
light = new THREE.DirectionalLight(0xFF, 0);
light.position.set(100, 100, 200);
scene.add(light);
function initObject() {
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial( { vertexColors: true } );
var color1 = new THREE.Color( 0x444444 ), color2 = new THREE.Color( 0xFF0000 );
// 线的材质可以由2点的颜色决定
var p1 = new THREE.Vector3( -100, 0, 100 );
var p2 = new THREE.Vector3(
100, 0, -100 );
geometry.vertices.push(p1);
geometry.vertices.push(p2);
geometry.colors.push( color1, color2 );
var line = new THREE.Line( geometry, material, THREE.LinePieces );
scene.add(line);
function threeStart() {
initThree();
initCamera();
initScene();
initLight();
initObject();
renderer.clear();
renderer.render(scene, camera);
&body onload="threeStart();"&
&div id="canvas-frame"&&/div&
看看A begin 和A end之间的代码,就是画线的代码。
1、首先,我们声明了一个几何体geometry,如下:
var geometry = new THREE.Geometry();
几何体里面有一个vertices变量,可以用来存放点。
2、定义一种线条的材质,使用THREE.LineBasicMaterial类型来定义,它接受一个集合作为参数,其原型如下:
LineBasicMaterial( parameters )
Parameters是一个定义材质外观的对象,它包含多个属性来定义材质,这些属性是:
Color:线条的颜色,用16进制来表示,默认的颜色是白色。
Linewidth:线条的宽度,默认时候1个单位宽度。
Linecap:线条两端的外观,默认是圆角端点,当线条较粗的时候才看得出效果,如果线条很细,那么你几乎看不出效果了。
Linejoin:两个线条的连接点处的外观,默认是“round”,表示圆角。
VertexColors:定义线条材质是否使用顶点颜色,这是一个boolean值。意思是,线条各部分的颜色会根据顶点的颜色来进行插值。(如果关于插值不是很明白,可以QQ问我,QQ在前言中你一定能够找到,嘿嘿,虽然没有明确写出)。
Fog:定义材质的颜色是否受全局雾效的影响。
好了,介绍完这些参数,你可以试一试了,在课后,我们会展示不同同学的杰出作品。下面,接着上面的讲,我们这里使用了顶点颜色vertexColors: THREE.VertexColors,就是线条的颜色会根据顶点来计算。
var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
3、接下来,定义两种颜色,分别表示线条两个端点的颜色,如下所示:
var color1 = new THREE.Color( 0x444444 ),
color2 = new THREE.Color( 0xFF0000 );
4、定义2个顶点的位置,并放到geometry中,代码如下:
var p1 = new THREE.Vector3( -100, 0, 100 );
var p2 = new THREE.Vector3(
100, 0, -100 );
geometry.vertices.push(p1);
geometry.vertices.push(p2);
5、为4中定义的2个顶点,设置不同的颜色,代码如下所示:
geometry.colors.push( color1, color2 );
geometry中colors表示顶点的颜色,必须材质中vertexColors等于THREE.VertexColors 时,颜色才有效,如果vertexColors等于THREE.NoColors时,颜色就没有效果了。那么就会去取材质中color的值,这个很重要,大家一定记住。
6、定义一条线
定义线条,使用THREE.Line类,代码如下所示:
var line = new THREE.Line( geometry, material, THREE.LinePieces );
第一个参数是几何体geometry,里面包含了2个顶点和顶点的颜色。第二个参数是线条的材质,或者是线条的属性,表示线条以哪种方式取色。第三个参数是一组点的连接方式,我们会在后面详细讲解。
然后,将这条线加入到场景中,代码如下:
scene.add(line);
这样,场景中就会出现刚才的那条线段了。
各位,先休息一下吧,可以在线编辑一下本课的代码,会有实时的效果显示在你的眼前。哈哈,这可是我们精心为您准备的在线编辑功能啊。本课未完,未完部分见下章
Linewidth参数怎么不行呢
WebGL中文网老师回答:
在3D世界中是没有单位的概念的,Linewidth设置为100,webgl也不知道应该在屏幕中占据多少像素。 WebGLRenderer是不支持线宽度的,所以如果要画线并设置宽度请用CanvasRenderer,它是用二维canvas画布模拟3D效果,所以能够设置宽度。
介绍VertexColors:定义线条材质是否使用顶点颜色,这是一个boolean值。这个参数值,教程中代码中是true。但是在后边介绍的时候为什么出现了取值为THREE.VertexColors和THREE.NoColors的情况呢?
WebGL中文网老师回答:
最新版本的定义是:
NoColors: 0,
FaceColors: 1,
VertexColors: 2,
其实就是一个整形,请以相应的版本为准,不同版本的定义不一样。
width\height 都没有提前声明,看的好纠结。。。
WebGL中文网老师回答:
js代码可以事先声明也可以不用声明,纠结的事情很多,请将心情放平,放到重要的事情上。
var p1 = new THREE.Vector3( -100, 0, 100 );这几个参数是什么意思呢?
有些问题,学员之间也可以相互沟通解决,建议普通注册用户也能回复其他用户的问题。WebGL中文网老师对答的不好的问题可以补充回答,这样方便问题更快速的解决。
有点不理解,up是z轴,那么转换成二维,应该是右边X轴正方向,上方是Z轴正方向,画出来的应该是从左向右斜向下的线条啊
明白了,因为y的position是1000,所以是从Y轴正方向向负方向看的,还是谢谢
老师您好,我请问个问题,我现在版本是最新版83的,运行代码出现一下黄色警告:three.js:23268 THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.画面只有一条线段,请问如何修改呢
@8楼var line = new THREE.Line( geometry, material, THREE.LinePieces );换成var line = new THREE.Line( geometry, material, THREE.LineSegments);应该是类库升级
大家好,6楼的问题我看了7楼的回答还没搞明白为什么不是从左上方指向右下方的线条 啊?camera.up.z=1是什么意思?y轴的正方是垂直于屏幕向内还是向外?
10楼的问题解决了,如果还有不懂的去百度 “three.js中camera的属性设置” 就了解了,不然的话后续的教程会越看越迷糊的。谢谢。
提问或评论
登陆后才可留言或提问哦:)
登陆后请返回本课提问
渝ICP备号-1
WebGL中文网
友情链接:
我们将通过微信公众号发布最新消息}

我要回帖

更多关于 three.js 纹理坐标 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信