第3章 让场景动起来

1、 学会让场景中的物体动起来

2、 学会性能监视器

1、让场景动起来

这一节课,我们要让场景动起来,不禁想到了郭富城的一首歌《动起来》。心中有很多感慨,觉得时间过得太快,自己还没有多大的成功。以淡淡的感伤开始这节课的讲解。

不过我会继续努力,寻找自己更多的成功。

大家也动起来,沉静下来,仔细的研究Three.js的每一个细节,终将成为这个领域的高手。不仅是成为three.js的高手,更重要的是理解图形学的概念,轻易掌握其他3D图形库。不是吹牛,大家阅读完这套课程(包括中级,高级),能够轻易的实现艳丽的粒子系统、模拟多种物理现象(如衣服在风中飘动),让浏览器中2D和3D混合等令人大饱眼福的效果。

以往的例子中,我们很少让物体动起来,即使动起来了,也很少讲这方面的知识。这里我们对让场景动起来做一些解释。

1、场景怎么会动起来

场景中的物体怎么才能运动起来。我们这里从《古兰经》讲起,这样,你永远不会忘记。

《古兰经》上有这样一个故事:一天穆罕穆德告诉人们说大山会向我们走来。于是人们就远望大山,看它怎么走过来,可是等了好长时间大山还是纹丝不动的在那里,人们就问穆罕穆德,大山也没向我们走来啊。默罕默德告诉人们:既然大山没向我们走来,那我们就向大山走去吧。于是人们来到了大山的山顶,人们征服了那座大山。

这个故事揭示了场景动起来的方法,第一种方法是让物体在坐标系里面移动,摄像机不动。第二种方法是让摄像机在坐标系里面移动,物体不动。这样场景就能够动起来了。

摄像机可以理解我们自己的眼睛。

2、渲染循环

物体运动还有一个关键点,就是要渲染物体运动的每一个过程,让它显示给观众。渲染的时候,我们调用的是渲染器的render() 函数。代码如下:

renderer.render( scene, camera );

如果我们改变了物体的位置或者颜色之类的属性,就必须重新调用render()函数,才能够将新的场景绘制到浏览器中去。不然浏览器是不会自动刷新场景的。

如果不断的改变物体的颜色,那么就需要不断的绘制新的场景,所以我们最好的方式,是让画面执行一个循环,不断的调用render来重绘,这个循环就是渲染循环,在游戏中,也叫游戏循环。

为了实现循环,我们需要javascript的一个特殊函数,这个函数是requestAnimationFrame。

调用requestAnimationFrame函数,传递一个callback参数,则在下一个动画帧时,会调用callback这个函数。

于是,我们的游戏循环会这样写。

function animate() {

	render();

	requestAnimationFrame( animate );

}

这样就会不断的执行animate这个函数。也就是不断的执行render()函数。在render()函数中不断的改变物体或者摄像机的位置,并渲染它们,就能够实现动画了。

2、改变相机的位置,让物体移动

有了这些简单的基础知识,我们来实现一个动画效果。它的效果如下所示:

看箭头的方向,你会发现这个物体在向左边移动。你可以在“初级教程\chapter3\3-1.html”这个源文件中发现代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Three框架</title>
		<script src="js/Three.js"></script>
		<style type="text/css">
			div#canvas-frame {
				border: none;
				cursor: pointer;
				width: 100%;
				height: 600px;
				background-color: #EEEEEE;
			}

		</style>
		<script>
            var renderer;
            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFFFFFF);
                light.position.set(100, 100, 200);
                scene.add(light);
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFF00} );
                var mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                animation();

            }
            function animation()
            {
                //renderer.clear();
                camera.position.x =camera.position.x +1;
                renderer.render(scene, camera);
                requestAnimationFrame(animation);
            }

		</script>
	</head>

	<body onload="threeStart();">
		<div id="canvas-frame"></div>
	</body>
</html>

我们将重点放在animation函数中的代码,它将不断的通过下面的代码改变相机的位置:

camera.position.x =camera.position.x +1;

将相机不断的沿着x轴移动1个单位,也就是相机向右移动。相机向右移动,那么想一想相机中的物体,是怎么移动的呢?毫无疑问,它是反方向移动的,是向左移动的。

设置完相机的位置后,我们调用requestAnimationFrame(animation)函数,这个函数又会在下一个动画帧出发animation()函数,这样就不断改变了相机的位置,从而物体看上去在移动了。

另外,必须要重视render函数,这个函数是重新绘制渲染结果,如果不调用这个函数,那么即使相机的位置变化了,但是没有重新绘制,仍然显示的是上一帧的动画。Render函数调用如下:

renderer.render(scene, camera);

3、改变物体自身的位置,让物体移动

第二种方式,就是让物体动起来,只要改变物体的位置就可以了。代码如下,你可以在“初级教程\chapter3\3-2.html”中找到代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Three框架</title>
		<script src="js/Three.js"></script>
		<style type="text/css">
			div#canvas-frame {
				border: none;
				cursor: pointer;
				width: 100%;
				height: 600px;
				background-color: #EEEEEE;
			}

		</style>
		<script>
            var renderer;
            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFF0000);
                light.position.set(100, 100, 200);
                scene.add(light);
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
			var mesh;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFFFF} );
                mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                animation();

            }
            function animation()
            {
				mesh.position.x-=1;
                renderer.render(scene, camera);
                requestAnimationFrame(animation);
            }

		</script>
	</head>

	<body onload="threeStart();">
		<div id="canvas-frame"></div>
	</body>
</html>

关注animation函数处的代码,其中有一句,这也是和前一个例子唯一不同的一句:

mesh.position.x-=1;

其中mesh就是指的物体,它有一个位置属性position,这个position是一个THREE.Vector3类型变量,所以你要把它向左移动,只需要将x的值不断的减少就可以了。这里我们减去的是1个单位。

Ok,分析完毕,很轻松吧。

4、物体运动后,怎么评估程序的性能

关于性能:测试一个程序,性能上是否有瓶颈,在3D世界里,经常使用帧数的概念,首先我们来定义一下帧数的意义。

帧数:图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)来表示。如下是每秒钟59次刷新的应用:

当物体在快速运动时,当人眼所看到的影像消失后,人眼仍能继续保留其影像1/24秒左右的图像,这种现象被称为视觉暂留现象。是人眼具有的一种性质。人眼观看物体时,成像于视网膜上,并由视神经输入人脑,感觉到物体的像。一帧一帧的图像进入人脑,人脑就会将这些图像给连接起来,形成动画。

毫无疑问,帧数越高,画面的感觉就会越好。所以大多数游戏都会有超过30的FPS。为了监视FPS,看看你的程序哪里占用了很多的CPU时间,就需要学习一下性能监视器。

1、性能监视器Stats

在Three.js中,性能由一个性能监视器来管理,它的介绍在https://github.com/mrdoob/stats.js 可以看到。性能监视器的截图如下所示:

其中FPS表示:上一秒的帧数,这个值越大越好,一般都为60左右。点击上面的图,就会变成下面的另一个视图。

MS表示渲染一帧需要的毫秒数,这个数字是越小越好。再次点击又可以回到FPS视图中。

2、性能监视器Stats的使用

在Three.js中,性能监视器被封装在一个类中,这个类叫做Stats,下面是一段伪代码,表示Stats的使用。

var stats = new Stats();
stats.setMode(1); // 0: fps, 1: ms
// 将stats的界面对应左上角
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
setInterval( function () {
    stats.begin();
    // 你的每一帧的代码
    stats.end();
}, 1000 / 60 );


你现在可以自己写一段代码,来验证一下,你的程序的帧数了。

Stats到底做了什么事情呢?我们来分析一下。

1、setMode函数

参数为0的时候,表示显示的是FPS界面,参数为1的时候,表示显示的是MS界面。

2、stats的domElement

stats的domElement表示绘制的目的地(DOM),波形图就绘制在这上面。

3、stats的begin函数

begin,在你要测试的代码前面调用begin函数,在你代码执行完后调用end()函数,这样就能够统计出这段代码执行的平均帧数了。

5、性能测试实例

好了,有了上面关于Stats类的基础知识后,我们来讲一个使用这个类的实例。

Stats的begin和end 函数本质上是在统计代码执行的时间和帧数,然后用公式fps=帧数/时间 ,就能够得到FPS。Stats的这个功能,被封装成了一个更好的函数update,只需要在渲染循环中调用就可以了。请看下面的代码[初级教程\chapter3\3-3.html],这份代码是在3-2.html的基础上,加上了stats统计得到的。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Three框架</title>
		<script src="js/Three.js"></script>
        <script src="js/Stats.js"></script>

		<style type="text/css">
			div#canvas-frame {
				border: none;
				cursor: pointer;
				width: 100%;
				height: 600px;
				background-color: #EEEEEE;
			}

		</style>
		<script>
            var renderer;
            var stats;
            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';
                document.getElementById('canvas-frame').appendChild(stats.domElement);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFF0000);
                light.position.set(100, 100, 200);
                scene.add(light);
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
			var mesh;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFFFF} );
                mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                animation();

            }
            function animation()
            {
                //renderer.clear();
                //camera.position.x =camera.position.x +1;
				mesh.position.x-=1;
                renderer.render(scene, camera);
                requestAnimationFrame(animation);

                stats.update();
            }

		</script>
	</head>

	<body onload="threeStart();">
		<div id="canvas-frame"></div>
	</body>
</html>

代码的运行效果如下图所示,左上部,就是显示的帧计数器。

以上代码一共只有几个步骤:

1、new 一个stats对象,代码如下

stats = new Stats();

2、将这个对象加入到html网页中去,代码如下

stats.domElement.style.position = 'absolute';

stats.domElement.style.left = '0px';

stats.domElement.style.top = '0px';

3、调用stats.update()函数来统计时间和帧数。代码如下

stats.update();

好了,这节课就讲到这里了,我们讲了重要的游戏循环和性能测试的方法。当帧数较低的时候,你就要注意了,可能是你的代码性能太低了造成的。一般情况下,帧数都可以跑到60的。

6、使用动画引擎Tween.js来创建动画

上面介绍了通过移动相机和移动物体来产生动画的效果。使用的方法是在渲染循环里去移动相机或者物体的位置。如果动画稍微复杂一些,这种方式实现起来就比较麻烦一些了。

为了使程序编写更容易一些,我们可以使用动画引擎来实现动画效果。和three.js紧密结合的动画引擎是Tween.js,你可以再https://github.com/sole下载。

对于快速构件动画来说,Tween.js是一个容易上手的工具。首先,你需要引擎js文件,如下:

<-script src="../js/tween.min.js" data-ke-src="../js/tween.min.js"><-/script>

第二步,就是构件一个Tween对象,对Tween进行初始化,本例的代码是:

function initTween()
{
	new TWEEN.Tween( mesh.position)
			.to( { x: -400 }, 3000 ).repeat( Infinity ).start();
}

TWEEN.Tween的构造函数接受的是要改变属性的对象,这里传入的是mesh的位置。Tween的任何一个函数返回的都是自身,所以可以用串联的方式直接调用各个函数。

to函数,接受两个参数,第一个参数是一个集合,里面存放的键值对,键x表示mesh.position的x属性,值-400表示,动画结束的时候需要移动到的位置。第二个参数,是完成动画需要的时间,这里是3000ms。

repeat( Infinity )表示重复无穷次,也可以接受一个整形数值,例如5次。

Start表示开始动画,默认情况下是匀速的将mesh.position.x移动到-400的位置。

第三步是,需要在渲染函数中去不断的更新Tween,这样才能够让mesh.position.x移动位置:

function animation()
{
	renderer.render(scene, camera);
	requestAnimationFrame(animation);
	stats.update();
	TWEEN.update();
}

其中的TWEEN.update()完成了让动画动起来到目标。如果不调用这个函数场景就不能动起来了。

你可以再[初级教程\chapter3\3-4.html]和[初级教程\chapter3\3-5.html]找到这节的代码,3-4.html是让物体动起来,3-5.html是让相机动起来。

7、使用动画引擎Tween.js来创建不规则动画

本节是一扩展的小结。如果对此不敢兴趣,可以跳过此节,也不影响学习。

上面讲的运动是直线运动,有时候我们需要曲线运动,例如下面图中的运动轨迹:

点击这里可以看到曲线运动方式。在实际工作中,经常是曲线运动,所以你有必要去快速掌握这些知识。

5、补充视频

大家除了在首页菜单中下载本课的视频外,还可以通过如下的地址看补充课程“帧循环、渲染循环、游戏循环的重要概念”,这节视频对理解WebGL的渲染原理非常有意义。点击这里观看

给WebGL中文网团队的女程序员"小果妹妹"发一个鸡腿吧,微信扫一扫赞赏,感谢。

亲爱的读者,如果你觉得WebGL中文网的课程不错,您可以购买《WebGL中文网视频课程》 课程支持我们哦,购买后记得给我们好评哦!我们强烈建议您不要在iphone上的网易云课堂软件中购买,这样苹果会收取31%左右的服务费,虽然这是明码标价,我们也表示认可和理解,具体选择权在您自己了。

感谢大家的支持,下面是课程的截图之一

[1楼] mr.t** 2016-06-24 17:16

老师,我想知道如果在这个函数里面想定义曲线运动(三角函数?)该怎么定义!

function initTween()
            {
                new TWEEN.Tween( line.position)
                        .to( { x: -400 ,y:400}, 300 ).repeat( Infinity ).start();
            }

WebGL中文网老师回答:

建议您自己写函数去控制物体的x,y,z点,不用tween.js。如果要用,请自行查看它的api。

[2楼] ange** 2016-08-30 16:56

请问下教程中很多【点击这里】,并没有相应链接啊,如何点击呢?

[3楼] lian** 2016-09-01 14:58

请问下教程中很多【点击这里】,并没有相应链接啊,如何点击呢?

[4楼] 4595** 2016-09-29 14:14

请问下教程中很多【点击这里】,并没有相应链接啊,如何点击呢?

[5楼] jian** 2016-12-20 13:30

为啥我按照上面的教程写了物体异动的方式,异动相机和异动物体,都试了,但是都没有生效,好像只有第一次是异动了的,我看了那个回调函数,是一直在循环执行,但是物体就是没有移动

[6楼] jian** 2016-12-20 13:34

我复制了上面的两份代码,然后也没有移动,并没有报错

[7楼] “惜之扵** 2017-01-10 16:27

我发现一般自己构造运动逻辑上的错误是不可能有错误提示的,不移动的也就不能确定就没有动,可能自己写的移动逻辑是短时间来回运动自己还没发现呢,也有可能角度也就是相机位置的问题

[8楼] htsi** 2017-01-17 11:39

老师您好,请问是不是版本发生了改变,我复制上面的代码,并没有光照效果?谢谢

[9楼] wode** 2017-04-13 14:03

d a 

[10楼] yy53** 2017-07-25 17:58

老师好,请问为什么我按照您写的为什么性能监视没法执行啊,可以显示出来但是就是不更新???

[11楼] joel** 2017-08-03 10:49

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Three框架</title>

<script type="text/javascript" src="js/three.js" ></script>

<script type="text/javascript" src="js/stats.js" ></script>

<style type="text/css">

#canvas-frame{

border: none;

cursor: pointer;

width: 100%;

height: 600px;

background-color: #EEEEEE;

}

</style>

<script>

var renderer;

function initThree(){

width = document.getElementById('canvas-frame').clientWidth;

height = document.getElementById('canvas-frame').clientHeight;

renderer = new THREE.WebGLRenderer({

antialias:true

});

renderer.setSize(width ,height);

document.getElementById('canvas-frame').appendChild(renderer.domElement);

renderer.setClearColor(0xFFFFFF, 1.0);

}

var camera;

function initCamera(){

camera = new THREE.PerspectiveCamera(45 ,width/ height, 1, 10000);

camera.position.x = 0;

camera.position.y = 0;

camera.position.z = 600;

camera.up.x = 0;

camera.up.y = 1;

camera.up.z = 0;

camera.lookAt({

x:0,

y:0,

z:0

})

}

var scene;

function initScene(){

scene = new THREE.Scene();

}

var light;

function initLight(){

var light = new THREE.AmbientLight(0xFFFFFF);

light.position.set(100,100,200);

scene.add(light);

light = new THREE.PointLight(0x00FF00);

light.position.set(0,0,300);

scene.add(light);

}

var cube;

function initObject(){

var geometry = new THREE.CylinderGeometry( 100, 150 ,400);

var material = new THREE.MeshLambertMaterial( {

color:0xFFFF00

});

var mesh = new THREE.Mesh( geometry, material);

mesh.position = new THREE.Vector3(0 ,0 ,0 );

scene.add(mesh);

}

function threeStart(){

initThree();

initCamera();

initScene();

initLight();

initObject();

animation();

}

function animation(){

camera.position.x += 1;

renderer.render(scene, camera);

requestAnimationFrame(animation);

}

</script>

</head>

<body onload="threeStart()">

<div id="canvas-frame"></div>

</body>

</html>

这是我第一个示例的代码,为什么我用three.min.js的时候就不出现物体,用three.js就出来了呢,前者也不报错,求大神指导

[12楼] cary** 2017-09-13 15:51

你好,我使用了TWEEN.js,代码跟例子一样,为什么显示 repeat()这个方法未定义呢,改成easing就可以,但我看文档上也有repeat()的啊

WebGL中文网老师回答:

不同版本的tween.js的函数可能有所变化,看一下官网文档就可以了,别纠结。

[13楼] lixi** 2017-10-11 16:38

老师感觉好难啊

WebGL中文网老师回答:

心存高远 意守平常 身体而力行 小步终成千里

[14楼] liju** 2017-10-24 15:12

去掉repeat就可以运行,repeat方法在tween官网没找到,是不是新版已经去掉了?

WebGL中文网老师回答:

是的

[15楼] emdr** 2017-12-20 15:23

点线的坐标系统和物体的坐标系统不一样?

WebGL中文网老师回答:

确实有不同的坐标系,如本地坐标系,全局坐标系等。但是你说的点线和物体坐标系统,这个概念,应该是没有的。

[16楼] lirc** 2018-04-09 11:11

在initObject函数外面定义了mesh一定要在内部去掉mesh的定义,否则mesh.position.x会报错(mesh多次定义,不知道是哪个)

[17楼] clay** 2018-04-22 12:57

赞22楼

@17楼

下面是22楼思路的代码,你改一下,应该可以了

            var mesh = new THREE.Mesh();

            function initObject(){

                var geometry = new THREE.CylinderGeometry(100, 150, 400);

                var material = new THREE.MeshLambertMaterial({ color:0xFFFF00});

                mesh.geometry = geometry;

                mesh.material = material;

                mesh.position = new THREE.Vector3(0, 0, 0);

                scene.add(mesh);

            }

这里主要是变量的作用域出现了问题,建议老师也能修改一下代码。

[18楼] clay** 2018-04-22 12:57

赞22楼

@17楼

下面是22楼思路的代码,你改一下,应该可以了

            var mesh = new THREE.Mesh();

            function initObject(){

                var geometry = new THREE.CylinderGeometry(100, 150, 400);

                var material = new THREE.MeshLambertMaterial({ color:0xFFFF00});

                mesh.geometry = geometry;

                mesh.material = material;

                mesh.position = new THREE.Vector3(0, 0, 0);

                scene.add(mesh);

            }

这里主要是变量的作用域出现了问题,建议老师也能修改一下代码。

[19楼] clay** 2018-04-22 14:25

真心希望贴出的代码是进过调试过了的

[20楼] Yuko** 2018-05-17 14:46

three.js  93dev版本没有出动画,一样的代码 换成  73的就有了。请问是什么原因呢?93dev 是某些属性去掉了么?

[21楼] 足球小将** 2018-09-26 10:41

引入stats.js后,在第171行 export { Stats as default };

报错Uncaught SyntaxError: Unexpected token export

什么情况?每次遇到export都会报错。。。

WebGL中文网老师回答:

语法哪里出错了,如果用的es6语法,请改造一下stats.js类

[22楼] fkmy** 2018-09-30 16:49

老师您好,我最近刚开始学习threejs,碰见一些问题想请教一下老师;

1、关于精灵模型:

我在别人写的一个室内模型demo上面添加精灵模型;

用的是png的图片,然而部分sprite总是显示为矩形,(精灵周围不是透明,而是和背景一样的颜色);

当camera视角垂直俯瞰场景时(或者精灵距离camera较近时),sprite显示正常,若旋转场景,则远处的精灵图会变成矩形;

/*(不知道为什么图片一直上传失败,所以没有图片)*/

2、我自己写的demo,用相机的lookAt()方法可以实现效果;

为什么在别人的场景里就不起作用呢?不知道什么原因,感觉无从下手;

希望老师能点拨一下;谢谢!

WebGL中文网老师回答:

查看精灵本身的形状。

[23楼] cona** 2018-10-15 14:08

老师你好,补充视频地址无法打开,显示“链接被重置”,麻烦修复一下谢谢

[24楼] whyw** 2018-10-30 11:08

综合了@22楼和我自己的思路,可以正常显示,大家可以参考一下

var camera;
function initCamera() {
    camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
    camera.position.x = 0;
    camera.position.y = 0;
    camera.position.z = 600;
    camera.up.x = 0;
    camera.up.y = 1;
    camera.up.z = 0;
    camera.lookAt(0, 0, 0);//主要改这一行
}

var mesh = new THREE.Mesh();
function initObject(){
    var geometry = new THREE.CylinderGeometry(100, 150, 400);
    var material = new THREE.MeshLambertMaterial({ color:0xFFFF00});
    mesh.geometry = geometry;
    mesh.material = material;
    mesh.position = new THREE.Vector3(0, 0, 0);
    scene.add(mesh);
}

[25楼] 鹤舞流云** 2018-12-21 16:45

老师你好,我拷贝了您的性能测试实例代码,运行之后网页除了画布之外啥也没有,这是为什么?

[26楼] wils** 2019-01-20 15:07

讲的很棒

[27楼] hans** 2019-03-27 10:44

第7节,所给的链接:https://www.createjs.com/tweenjs

这个网站,并不是  tweenjs/tween.js  这个库所对应的  项目链接?


createjs下的tweenjs,在new TWEEN.Twenn()的声明上,都和  tweenjs/tween.js  的库不一样

[28楼] xuyu** 2019-07-08 13:28

vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in mounted hook: "TypeError: Cannot assign to read only property 'position' of object '#<Mesh>'"

mesh.position.add(new THREE.Vector3(0, 0, 0));

浏览器报错了, 我自己根据ts的提示查出来的这个API,可以了,

[29楼] luom** 2019-07-31 17:35

我的这个改成mesh.position.add(new THREE.Vector3(0,0,0))后  又报Cannot read property 'add' of undefined这个错了有谁知道这个问题吗

[30楼] bug元** 2019-09-19 16:57

老师你好,性能检测,为什么会报 new Stats() 这个没有找到的错误?

[31楼] llll** 2019-09-27 10:30

老师你好,我按上面的代码为什么看不到光照效果

[32楼] qinq** 2019-10-22 15:10

@30楼,你引用了Stats.js文件没?

[33楼] 小汤圆0** 2020-03-24 15:21

您好,刚开始解释 webgl和threejs,首先感谢您的文章,非常详细易懂,

有个个人建议,就是对于 camera和几何坐标系的教程对于新手来说可能讲的少了点,我看了文章和案例后,还是有不少疑问的地方,在网上又找了几篇文章,并试验过后才正常理解了坐标系的变换原理.

希望作者可以完善的讲解写 坐标系间的转换和使用逻辑.

[34楼] s499** 2020-07-23 16:57

老师好,请问three.js的场景(如周围环境:山体,天空,花草、树木、绿化、公路等)一般是什么软件制作,据我了解到情况,类似用3dmax制作出来的场景,太过于精细,不太适合在web上展示。谢谢回答

[35楼] jack** 2020-09-03 14:44

古兰经中的是 穆罕穆德还是默罕默德或者还是穆罕默德

[36楼] Hicc** 2020-10-07 17:45

老师您好,想问一下为什么其他内容都显示正常了,却看不到光照效果?也并没有报错。是版本问题吗?

提问或评论

登陆后才可留言或提问哦:) 登陆 | 注册 登陆后请返回本课提问
用户名
密   码
验证码