threejs 灯光效果,使用three.js搭建室内场景教学

这两天,在Three.js上画3D房子,放床,可以用鼠标和键盘控制移动,有3D游戏的即视感。

这篇文章论述实现原理。

代码地址: https://github.com/quarkgluonplasma/three js-exerci ze

分析想法

别着急写代码,先分析一下想法吧。

这样的房子,其实也是用几个几何图形堆起来的:

照片

具体来说,这些几何图形包括:

地板是平面的。 可以用平面几何(平面几何)进行绘制。 贴上纹理贴图就行了。

照片

两个侧面的墙是不规则的,它可以挤出几何体。 它支持绘制2D路径,并加厚到3D。

照片

同样,后面的墙壁也很简单,可以用BoxGeometry (立方体)画,也可以用ExtrudeGeometry画出形状后做成3D。

照片

前面的墙有点复杂,它也不规则,可以使用“挤出几何体”( ExtrudeGeometry )绘制形状,并将其转化为3D。 但是,因为多了两个孔,所以需要画两个孔放入形状中。

照片

门框、窗框也在形状上开孔,在ExtrudeGeometry中成为3D。

照片

屋顶呢? 屋顶也没什么特别的。 把立方体旋转一定的角度就可以了。 可以用BoxGeometry (立方体)画。

照片

其次,在墙壁、屋顶、地板上贴上不同的图,设置不同的位置,就可以组装成一所房子。

床呢?

照片

Three.js提供了许多几何体,可以绘制简单的物体,但复杂的物体会变得难以绘制。 这些物体通常使用专门的3D建模软件进行绘制,并通过导出FPX或OBJ格式的文件由Three.js加载和渲染。

在网上找床的3D模型,找FBX格式,用Three.js的FBXLoader加载即可。

就剩下草坪了。 这也是平面。 使用“PlaneGeometry”(平面几何)进行绘制时,只是长宽较大,看不到结尾。

照片

看起来有雾吗?

是的,确实设置了雾( Fog )。 Three.js只要在场景中设置雾的效果,指定颜色和雾的远近范围即可。 为了让人感到模糊,在场景中加入了雾。

绘制了所有物体后,接下来可以漫游三维场景。 您可以使用鼠标和键盘改变方向、前后左右移动。 这样的交互是使用FirstPersonControls (第一人称控制器)实现的。

我们常用的是OrbitsControls (轨道控制器),它支持像卫星一样围绕物体转动摄像机。 但是,这里我们希望键盘和鼠标控制的前后左右自由移动,而不是四处走动。

是一个简单的总结:

Three.js在三维坐标系中添加各种各样的物体,组装成不同的3D场景。 其中的简单物体可以绘制,复杂物体用建模软件绘制,并加载到场景中。 为了实现轨道控制器、第一人称控制器等各种交互效果,可以使用各种控制器来控制相机的移动。

房屋的所有墙壁、地板和屋顶都可以使用“立方体”、“拉伸几何”绘制,但像床这样复杂的东西是不行的,它会直接加载模型文件。

通过FistPersonControls (第一人称控制器)控制交互,可以达到类似3D游戏的感觉。

思路整理好了,接下来具体写代码:

代码实现

首先画草坪,也就是大平面,贴草坪的地图。

三维物体由“几何体”( Geometry )和材质组成。 创建“平面几何体”( PlaneGeometry ),将长度和宽度设定为较大的值(例如10000 ),然后加载草坪图像作为纹理以构成材质。 之后可以做草坪。

函数创建眼镜

const geometry=new three.plane geometry ( 10000,10000 );

const texture=new three.texture loader ( ).load ) img/grass.jpg;

texture.wraps=three.repeat wrapping;

texture.wrapt=three.repeat wrapping;

texture.repeat.set ( 100,100 );

constgrassmaterial=new three.meshbasicmaterial ( { map:texture } );

const grass=new three.mesh ( geometry,grassMaterial );

grass.rotation.x=-0.5 * Math.PI;

Scene.add(grass;

}

将纹理贴图设置为在两个方向上重复。 重复的次数为100次。

然后草坪的平面必须旋转。

照片

加雾使天空变得阴沉:

scene.fog=newthree.fog(0xfffff,10,1500 );

每种颜色都是白色,雾的远近范围是10~1500。

照片

其次是组建家庭。 房子由地板、两侧的墙、前面的墙、后面的墙、门框窗框、屋顶和床构成。 要制作各个部分,就把每个放在不同的组里。

const house=new THREE.Group (;

function createHouse

创建流(;

const sideWall=createSideWall (;

const sideWall2=createSideWall (;

sideWall2.position.z=300;

createFrontWall (

createBackWall (

const roof=createRoof (;

const roof2=createRoof (;

roof2.rotation.x=Math.PI/2;

roof2.rotation.y=Math.PI/4 * 0.6;

roof2.position.y=130;

roof2.position.x=-50;

roof2.position.z=155;

createWindow (

createDoor (;

createBed (;

}

地板也创建平面几何体,然后粘贴木材图并设定以下位置:

函数创建流

const geometry=new three.plane geometry ( 200,300 );

const texture=new three.texture loader ( ).load ) img/wood.jpg;

texture.wraps=three.repeat wrapping;

texture.wrapt=three.repeat wrapping;

texture.repeat.set ( 2,2 );

const material=new three.meshbasicmaterial ( { map:texture } );

const floor=new three.mesh ( geometry,material;

floor.rotation.x=-0.5 * Math.PI;

floor.position.y=1;

floor.position.z=150;

house.add(floor;

}

照片

若要创建侧墙,请使用“ExtrudeGeometry”(拉伸几何体)绘制。 也就是说,首先画出2D的形状,然后挤出到3D。 也贴上墙壁的纹理贴图。

功能创建向导

const shape=new THREE.Shape (;

shape.move to (-100,0 );

shape.lineto ( 100,0 );

shape.lineto ( 100,100 );

shape.lineto ( 0,150 );

shape.lineto (-100,100 );

shape.lineto (-100,0 );

constextrudegeometry=new three.extrude geometry;

const texture=new three.texture loader ( ).load ) ‘./img/wall.jpg );

texture.wraps=texture.wrapt=three.repeat wrapping;

texture.repeat.set ( 0.01,0.005 );

var material=new three.meshbasicmaterial ( { map:texture } );

const sidewall=new three.mesh ( extrude geometry,material;

house.add(sidewall;

返回边;

}

两个侧壁只是位置不同,修正下面z轴的位置就可以了。

const sideWall=createSideWall (;

const sideWall2=createSideWall (;

sideWall2.position.z=300;

照片

是的。 如果位置不正确,可以将“坐标系辅助工具”( AxisHelper )添加到场景中。

constaxishelper=new three.axis helper ( 2000;

Sene.add(AxisHelper );

照片

然后是后面的墙。 这个形状很简单。 是长方形。

功能创建后台

const shape=new THREE.Shape (;

shape.move to (-150,0 ) )。

shape.lineto ( 150,0 ) )。

shape.lineto ( 150,100 ) )。

shape.lineto (-150,100 );

constextrudegeometry=new three.extrude geometry ( shape ) )。

const texture=new three.texture loader ( ).load ) ‘./img/wall.jpg );

texture.wraps=texture.wrapt=three.repeat wrapping;

texture.repeat.set ( 0.01,0.005 );

const material=new three.meshbasicmaterial ( { map:texture } );

constbackwall=new three.mesh ( extrude geometry,material;

backWall.position.z=150;

backWall.position.x=-100;

back wall.rotation.y=math.pi * 0.5;

house.add(backwall );

}

照片

下一面是前面的墙。 这不仅需要画形状,还需要挖两个洞。

函数创建框架

const shape=new THREE.Shape (;

shape.move to (-150,0 );

shape.lineto ( 150,0 );

shape.lineto ( 150,100 );

shape.lineto (-150,100 );

shape.lineto (-150,0 );

const window=new THREE.Path (;

window.move to ( 30,30 ) )。

window.lineto ( 80,30 ) )。

window.lineto ( 80,80 ) )。

window.lineto ( 30,80 );

window.lineto ( 30,30 );

shape.Holes.push(window );

const door=new THREE.Path (;

door.move to (-30,0 ) ) ) )。

door.lineto (-30,80 ) )。

door.lineto (-80,80 ) )。

door.lineto (-80,0 );

door.lineto (-30,0 );

shape.Holes.push(door );

constextrudegeometry=new three.extrude geometry ( shape ) )。

const texture=new three.texture loader ( ).load ) ‘./img/wall.jpg );

texture.wraps=texture.wrapt=three.repeat wrapping;

texture.repeat.set ( 0.01,0.005 );

const material=new three.meshbasicmaterial ( { map:texture } );

constfrontwall=new three.mesh ( extrude geometry,material );

frontWall.position.z=150;

frontWall.position.x=100;

front wall.rotation.y=math.pi * 0.5;

house.add(frontwall );

}

只是形状上多了两个孔,画变得复杂了,剩下的纹理、材质、还有位置等设置方法都是一样的。

照片

门窗也是画形状,挖洞,加上厚度做成3D的:

函数创建窗口

const shape=new THREE.Shape (;

shape.move to ( 0,0 );

shape.lineto ( 0,50 ) )。

shape.lineto ( 50,50 ) )。

shape.lineto ( 50,0 );

shape.lineto ( 0,0 );

const hole=new THREE.Path (;

hole.move to ( 5,5 ) )。

hole.lineto ( 5,45 ) )。

hole.lineto ( 45,45 ) )。

hole.lineto ( 45,5 );

hole.lineto ( 5,5 );

shape.holes.push(hole );

constextrudegeometry=new three.extrude geometry;

varextrudematerial=new three.meshbasicmaterial ( { color:’ silver ‘ } );

var window=new three.mesh ( extrude geometry,extrudeMaterial );

window.rotation.y=Math.PI/2;

window.position.y=30;

window.position.x=100;

window.position.z=120;

house.add(window;

返回窗口;

}

颜色被设定为银色。

门框也一样:

函数创建器

const shape=new THREE.Shape (;

shape.move to ( 0,0 );

shape.lineto ( 0,80 );

shape.lineto ( 50,80 );

shape.lineto ( 50,0 );

shape.lineto ( 0,0 );

const hole=new THREE.Path (;

hole.move to ( 5,5 );

hole.lineto ( 5,75 );

hole.lineto ( 45,75;

hole.lineto ( 45,5 );

hole.lineto ( 5,5 );

shape.holes.push(hole );

constextrudegeometry=new three.extrude geometry;

const material=new three.meshbasicmaterial;

const door=new three.mesh ( extrude geometry,材质;

door.rotation.y=Math.PI/2;

door.position.y=0;

door.position.x=100;

door.position.z=230;

house.add(door;

}

照片

其次是屋顶。 这将旋转两个立方体。

const roof=createRoof (;

const roof2=createRoof (;

roof2.rotation.x=Math.PI/2;

roof2.rotation.y=Math.PI/4 * 0.6;

roof2.position.y=130;

roof2.position.x=-50;

roof2.position.z=155;

屋面六面材质不同,一面加瓦纹,另一面灰即可,模拟水泥效果。 其中,瓦片纹理向下旋转,设定以下两个方向的重复次数。

函数创建

const geometry=new three.box geometry ( 120,320,10 );

const texture=new three.texture loader ( ).load )./img/tile.jpg );

texture.wraps=texture.wrapt=three.repeat wrapping;

texture.repeat.set ( 5,1 );

texture.rotation=Math.PI/2;

consttexturematerial=new three.meshbasicmaterial ( { map:texture } );

constcolormaterial=new three.meshbasicmaterial ( { color:’ grey ‘ } );

const materials=[

颜色材料,

颜色材料,

颜色材料,

颜色材料,

颜色材料,

纹理材料

];

const roof=new three.mesh ( geometry,materials );

house.add(roof;

roof.rotation.x=Math.PI/2;

roof.rotation.y=- Math.PI/4 * 0.6;

roof.position.y=130;

roof.position.x=50;

roof.position.z=155;

return roof;

}

照片

下一张床很简单。 因为直接加载现有模型就可以了,而不是自己画。 这种复杂的模型一般都是由专业建模软件绘制的。

功能创建

var loader=new THREE.FBXLoader (;

loader.load(‘./obj/bed.fbx ‘,function ( ) object )。

object.position.x=40;

object.position.z=80;

object.position.y=20;

house.add(object;

);

}

照片

灯光设置为环境光,即每个方向的光强度相同。

const light=new three.ambient light (0x cccccccc );

Scene.add(light;

创建摄影机并使用透视视图摄影机。 也就是说,使用类似透视的透视效果。

const width=window.innerWidth;

const height=window.innerHeight;

const camera=new three.perspective camera ( 60,width/height,0.1,1000 );

指定观看角度为60度、长宽比和透视范围(从0.1到1000 )。

创建渲染器,然后在requestAnimationFrame中逐帧渲染。

const renderer=new three.webglrenderer (;

函数渲染

renderer.render(Scene,camera );

requestAnimationFrame(render )

}

接下来还支持3D场景中的漫游。 这个也不用自己做。 Three.js好心地提供了很多控制器。 各自有不同的交互效果。 其中有第一人称控制器( FirstPersonControls )。 在类似游戏时的互动方式中,w、s、a、d键控制前后左右,鼠标控制方向。

const controls=new three.firstpersoncontrols ( camera );

controls.lookSpeed=0.05;

controls.movementSpeed=100;

controls.lookVertical=false;

指定了转向的速度lookSpeed、移动的速度movementSpeed,禁止了纵向旋转。

然后,按帧更新看到的画面,用时钟Clock获取进行了多少次,更新控制器。

const clock=new THREE.Clock (;

函数渲染

const delta=clock.getDelta (;

controls.update(Delta;

renderer.render(Scene,camera );

requestAnimationFrame(render )

}

查看最终效果:

所有代码都上传到github了:

代码地址: https://github.com/quarkgluonplasma/three js-exerci ze

总结

写下了Three.js绘制3D房子的实现原理。

Three.js通过场景Scene管理各种各样的物体,可以将物体分组。 物体由几何体( Geometry )和材质(材质)两部分组成,房子由立方体( BoxGeometry )、挤出几何体( ExtrudeGeometry )等各种几何体组成,设置了不同的贴图纹理

其中特殊的是ExtrudeGeometry (挤出几何),通过在二维平面上绘制形状,然后“挤出”为三维形状,也可以在形状上钻孔。

把床放在家里,这样复杂的物体用Three.js手绘比较难。 这种一般由专业的建模软件,如blender绘制,在Three.js中加载并渲染。

视角的变化实际上是摄像机的位置和方向的变化,Three.js提供了OrbitsControls、FirstPersonControls等各种控制器。

这里要求的是用键盘控制前后左右,用鼠标控制方向盘的交换就可以使用FirstPersonControls。

Three.js还是很开心的。 在业务上可能主要用于可视化、游戏,但在工作之余也可以制作有趣的东西。

动态分享

2023 《星之卡比》能力示范收藏Yasna穿衣娃娃可订购《猎天使魔女3》没有任天堂的限制。

2022-12-10 13:59:20

动态分享

值得推荐的手机视频剪辑软件排名,手机音频视频剪辑软件排名推荐

2022-12-10 14:01:23

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索