three.js学习笔记(六)——创建简单鬼屋

初始场景

一个平面,一个球体用来测试环境光和月光,测得光源正常后移除球体
在这里插入图片描述

创建房屋组别

因为我们房屋可能包含许多东西像是门、屋顶之类的,所以需要创建一个房屋组,将所有属于屋子的物体给添加到这个组里面,之后当我们需要移动整个屋子时,变可以把房屋组当作一个整体去进行位置移动,而不用单个单个的去移动物体位置。

// 创建一个house组
const house = new THREE.Group()
scene.add(house)

下面先初始化房屋该有的物体,具体细节后面再设置

创建墙体

//墙体
const walls = new THREE.Mesh(
  new THREE.BoxBufferGeometry(4, 2.5, 4),
  new THREE.MeshStandardMaterial({ color: '#ac8e82' })
)
walls.position.y = 2.5 / 2
// 添加到房屋组别中
house.add(walls)

在这里插入图片描述

创建屋顶

可以使用圆锥缓冲几何体来创建屋顶

//屋顶
const roof = new THREE.Mesh(
  new THREE.ConeBufferGeometry(3.5, 1, 4),
  new THREE.MeshStandardMaterial({ color: '#b35f45' })
)
// 旋转45度以适配立方体
roof.rotation.y =  Math.PI * 0.25
roof.position.y = 2.5 + 1 / 2
house.add(roof)

在这里插入图片描述

创建门

//门
const door = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(2,2),
    new THREE.MeshStandardMaterial({color:'#aa7b7b'})
)
door.position.z = 2 + 0.01
door.position.y = 2/2
house.add(door)

在这里插入图片描述

创建灌木丛

//草丛
const bushGeometry = new THREE.SphereGeometry(1,16,16)
const bushMaterial = new THREE.MeshStandardMaterial({color:'#89c854'})
const bush1 = new THREE.Mesh(bushGeometry,bushMaterial)
//缩放
bush1.scale.set(0.5,0.5,0.5)
bush1.position.set(0.8,0.2,2.2)
const bush2 = new THREE.Mesh(bushGeometry,bushMaterial)
bush2.scale.set(0.25,0.25,0.25)
bush2.position.set(1.4,0.1,2.1)
const bush3 = new THREE.Mesh(bushGeometry,bushMaterial)
bush3.scale.set(0.4,0.4,0.4)
bush3.position.set(-0.8,0.1,2.1)
const bush4 = new THREE.Mesh(bushGeometry,bushMaterial)
bush4.scale.set(0.15,0.15,0.15)
bush4.position.set(-1,0.05,2.6)
house.add(bush1,bush2,bush3,bush4)

在这里插入图片描述

创建墓碑组别

营造鬼屋氛围,在屋子旁边放一些墓碑

/**
 * 坟墓组
 */
const graves = new THREE.Group()
scene.add(graves)

创建墓碑

我们要创建几十个墓碑,不可能一个个去加,因此使用for循环来做。
因为我们的地面中心处于原点,房屋也位于地面中心,因此各个墓碑的位置应该也是围绕着屋子以原点为中心四散分布,也就是墓碑放置轨迹应该是以原点为圆心的一个圆。
下图为例,橙色即为我们的屋子,紫叉即是各个墓碑
在这里插入图片描述

const graveGeometry = new THREE.BoxBufferGeometry(0.6, 0.8, 0.2)
const graveMaterial = new THREE.MeshStandardMaterial({ color: '#b2b6b1' })
for (let i = 0; i < 50; i++) {
  const angle = Math.random() * Math.PI * 2 //角度
  const radius = 3 + Math.random() * 6 //半径位于房屋和地面边缘之间
  const x = Math.cos(angle) * radius
  const z = Math.sin(angle) * radius
  const grave = new THREE.Mesh(graveGeometry, graveMaterial)
  grave.position.set(x, 0.3, z)
  //改变墓碑朝向以及倾斜度
  grave.rotation.y = (Math.random() - 0.5)*0.5
  grave.rotation.z = (Math.random() - 0.5)*0.5
  graves.add(grave)
}

在这里插入图片描述
在这里插入图片描述

灯光

营造鬼屋氛围,先把环境光和月光颜色调蓝一点,光强弱一些

const ambientLight = new THREE.AmbientLight('#b9d5ff', 0.12)
const moonLight = new THREE.DirectionalLight('b9d5fff', 0.12)

在这里插入图片描述

创建门灯

在门顶部添加点光源

//门灯
const doorLight = new THREE.PointLight('#ff7d46',1,7)
doorLight.position.set(0,2.2,2.7)
// 添加到房屋组
house.add(doorLight)

在这里插入图片描述

烟雾

往场景添加烟雾

//Fog
//创建烟雾
const fog = new THREE.Fog('#262837',1,15)
//设置场景的fog属性
scene.fog = fog

Fog( color : Integer, near : Float, far : Float )
.color : Color
雾的颜色。比如说,如果将其设置为黑色,远处的物体将被渲染成黑色。
.near : Float
开始应用雾的最小距离。距离小于活动摄像机“near”个单位的物体将不会被雾所影响。默认值是1。
.far : Float
结束计算、应用雾的最大距离,距离大于活动摄像机“far”个单位的物体将不会被雾所影响。默认值是1000。
在这里插入图片描述
我们可以把渲染器背景颜色设为与烟雾颜色一样,这样场景边缘看起来就不会太突兀

renderer.setClearColor('#262837')

在这里插入图片描述

设置纹理

// 创建纹理加载器

const textureLoader = new THREE.TextureLoader()

加载所有关于门的纹理

const doorColorTexture = textureLoader.load('/textures/door/color.jpg')
const doorAlphaTexture = textureLoader.load('/textures/door/alpha.jpg')
const doorHeightTexture = textureLoader.load('/textures/door/height.jpg')
const doorAmbientOcclusionTexture = textureLoader.load(
  '/textures/door/ambientOcclusion.jpg'
)
const doorNormalTexture = textureLoader.load('/textures/door/normal.jpg')
const doorMetalnessTexture = textureLoader.load('/textures/door/metalness.jpg')
const doorRoughnessTexture = textureLoader.load('/textures/door/roughness.jpg')

设置门的材质

//门
const door = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(2.2, 2.2,100,100),
  new THREE.MeshStandardMaterial({
    map: doorColorTexture,
    //设置alphaMap记得开启透明度属性
    transparent: true,
    alphaMap: doorAlphaTexture,
    aoMap: doorAmbientOcclusionTexture,
    //设置displacementMap记得提供更多顶点给几何体
    displacementMap: doorHeightTexture,
    displacementScale: 0.1,
    normalMap: doorNormalTexture,
    metalnessMap: doorMetalnessTexture,
    roughnessMap: doorRoughnessTexture,
  })
)
//设置aoMap记得设置uv2属性
door.geometry.setAttribute(
  'uv2',
  new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2)
)

在这里插入图片描述

墙壁砖块

加载墙面砖块纹理

const brickColorTexture = textureLoader.load('/textures/bricks/color.jpg')
const brickAmbientOcclusionTexture = textureLoader.load(
  '/textures/bricks/ambientOcclusion.jpg'
)
const brickNormalTexture = textureLoader.load('/textures/bricks/normal.jpg')
const brickRoughnessTexture = textureLoader.load(
  '/textures/bricks/roughness.jpg'
)

设置墙体材质

//墙体
const walls = new THREE.Mesh(
  new THREE.BoxBufferGeometry(4, 2.5, 4),
  new THREE.MeshStandardMaterial({
    map: brickColorTexture,
    aoMap: brickAmbientOcclusionTexture,
    normalMap: brickNormalTexture,
    roughnessMap: brickRoughnessTexture,
  })
)
walls.geometry.setAttribute(
  'uv2',
  new THREE.Float32BufferAttribute(walls.geometry.attributes.uv.array, 2)
)

在这里插入图片描述

地面草坪

加载草坪纹理

const grassColorTexture = textureLoader.load('/textures/grass/color.jpg')
const grassAmbientOcclusionTexture = textureLoader.load(
  '/textures/grass/ambientOcclusion.jpg'
)
const grassNormalTexture = textureLoader.load('/textures/grass/normal.jpg')
const grassRoughnessTexture = textureLoader.load(
  '/textures/grass/roughness.jpg'
)

设置地面材质

// Floor
const floor = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(20, 20),
  new THREE.MeshStandardMaterial({
    map: grassColorTexture,
    aoMap: grassAmbientOcclusionTexture,
    normalMap: grassNormalTexture,
    roughnessMap: grassRoughnessTexture,
  })
)
floor.geometry.setAttribute(
  'uv2',
  new THREE.Float32BufferAttribute(floor.geometry.attributes.uv.array, 2)
)

在这里插入图片描述
设置完后观察上图你会发现草坪非常违和,这是因为我们把一张草坪纹理图片给应用到整块平面上,因此我们要设置纹理repeat属性使得纹理在一块平面上多次重复

grassColorTexture.repeat.set(8,8)
grassAmbientOcclusionTexture.repeat.set(8,8)
grassNormalTexture.repeat.set(8,8)
grassRoughnessTexture.repeat.set(8,8)

grassColorTexture.wrapS = THREE.RepeatWrapping
grassAmbientOcclusionTexture.wrapS = THREE.RepeatWrapping
grassNormalTexture.wrapS = THREE.RepeatWrapping
grassRoughnessTexture.wrapS = THREE.RepeatWrapping

grassColorTexture.wrapT = THREE.RepeatWrapping
grassAmbientOcclusionTexture.wrapT = THREE.RepeatWrapping
grassNormalTexture.wrapT = THREE.RepeatWrapping
grassRoughnessTexture.wrapT = THREE.RepeatWrapping

现在和谐多了在这里插入图片描述

增加幽灵漂浮效果

我们用一些简单的灯光来制造出幽灵漂浮的效果,这些灯光会在房子四周漂浮并且会穿过草坪和墓碑

添加点光源

//ghost
const ghost1 = new THREE.PointLight('#ff00ff',2,3)
const ghost2 = new THREE.PointLight('#00ffff',2,3)
const ghost3 = new THREE.PointLight('#ffff00',2,3)
scene.add(ghost1,ghost2, ghost3)

设置动画

/**
 * Animate
 */
const clock = new THREE.Clock()

const tick = () => {
  const elapsedTime = clock.getElapsedTime()

  // Update controls
  controls.update()

  //update ghost
  const ghostAngle = elapsedTime * 0.5
  //x和z设置点光源圆周运动
  ghost1.position.x = Math.cos(ghostAngle) * 4
  ghost1.position.z = Math.sin(ghostAngle) * 4
  //设置点光源高度上下变化
  ghost1.position.y = Math.sin(ghostAngle * 3)

  const ghost2Angle = -elapsedTime * 0.32
  ghost2.position.x = Math.cos(ghost2Angle) * 5
  ghost2.position.z = Math.sin(ghost2Angle) * 4
  ghost2.position.y = Math.sin(ghost2Angle * 3) + Math.sin(elapsedTime * 2.5)

  const ghost3Angle = -elapsedTime * 0.27
  //以不同半径旋转
  ghost3.position.x = Math.cos(ghost3Angle) * (7 + Math.sin(elapsedTime * 0.32))
  ghost3.position.z = Math.sin(ghost3Angle) * (7 + Math.sin(elapsedTime * 0.5))
  ghost3.position.y = Math.sin(ghost3Angle * 3) + Math.sin(elapsedTime * 2.5)

  // Render
  renderer.render(scene, camera)

  // Call tick again on the next frame
  window.requestAnimationFrame(tick)
}

在这里插入图片描述

阴影

激活阴影

renderer.shadowMap.enabled = true

为能投射阴影的光源开启castShadow

moonLight.castShadow = true
doorLight.castShadow = true
ghost1.castShadow = true
ghost2.castShadow = true
ghost2.castShadow = true

为物体开启castShadow

walls.castShadow = true
bush1.castShadow = true
bush2.castShadow = true
bush3.castShadow = true
bush4.castShadow = true

for (let i = 0; i < 50; i++) {
  ......
  grave.castShadow = true
  ......
}

在这里插入图片描述

出于性能考虑,需要优化阴影贴图

一般来讲,优化步骤是通过设置相机助手,把用于渲染阴影的灯光的摄像机给添加到助手里面,再调整相机的远近等属性,缩小灯光相机可视范围。可以参考另外一篇笔记Shadows阴影

doorLight.shadow.mapSize.width = 256
doorLight.shadow.mapSize.height = 256
doorLight.shadow.camera.far = 7

ghost1.shadow.mapSize.width = 256
ghost1.shadow.mapSize.height = 256
ghost1.shadow.camera.far = 7

ghost2.shadow.mapSize.width = 256
ghost2.shadow.mapSize.height = 256
ghost2.shadow.camera.far = 7

ghost3.shadow.mapSize.width = 256
ghost3.shadow.mapSize.height = 256
ghost3.shadow.camera.far = 7

最后改变阴影贴图的算法类型

// PCF柔软阴影贴图
renderer.shadowMap.type = THREE.PCFSoftShadowMap

在这里插入图片描述

好的,我会为您解答关于WebGL three.js的阴影与实现物体动画的问题。首先,让我们来了解一下WebGL three.js是什么。 WebGL three.js是一款基于WebGL的JavaScript 3D库,可以帮助我们快速搭建3D场景和应用。接下来我们来讲解阴影和实现物体动画的方法。 一、阴影 阴影是模拟物体之间的阴影效果,让3D场景更加真实。在three.js中,我们可以通过设置Mesh的castShadow和receiveShadow属性来实现阴影效果。 1. 首先,我们需要在场景中添加光源,例如SpotLight或DirectionalLight。 2. 然后,在需要投射阴影的物体上设置castShadow为true。 3. 最后,在需要接收阴影的物体上设置receiveShadow为true。 代码示例: ```javascript // 添加光源 const light = new THREE.SpotLight(0xffffff); light.position.set(0, 100, 0); light.castShadow = true; scene.add(light); // 添加需要投射阴影的物体 const cube = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), new THREE.MeshLambertMaterial({ color: 0xff0000 })); cube.castShadow = true; scene.add(cube); // 添加需要接收阴影的物体 const plane = new THREE.Mesh(new THREE.PlaneGeometry(200, 200, 1, 1), new THREE.MeshLambertMaterial({ color: 0xffffff })); plane.receiveShadow = true; plane.rotation.x = -Math.PI / 2; scene.add(plane); ``` 二、物体动画 在three.js中,我们可以通过Tween.js库来实现物体的动画效果。Tween.js是一款JavaScript动画库,可以帮助我们实现非常丰富的动画效果。 1. 首先,我们需要在HTML文件中引入Tween.js库文件。 2. 然后,在需要动画的物体上设置初始状态。 3. 最后,通过Tween.js库来设置物体的目标状态和动画效果,例如缓动动画(ease)或弹跳动画(bounce)。 代码示例: ```javascript // 引入Tween.js库文件 <script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.min.js"></script> // 添加需要动画的物体 const cube = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), new THREE.MeshLambertMaterial({ color: 0xff0000 })); cube.position.set(0, 0, 0); scene.add(cube); // 设置初始状态 const start = { x: 0, y: 0, z: 0 }; // 设置目标状态 const end = { x: 50, y: 50, z: 50 }; // 设置动画效果 const tween = new TWEEN.Tween(start) .to(end, 1000) .easing(TWEEN.Easing.Quadratic.InOut) .onUpdate(() => { cube.position.set(start.x, start.y, start.z); }) .start(); ``` 以上是关于WebGL three.js阴影与实现物体动画的方法,希望能够对您有所帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值