ThreeJs 学习之旅(十一)—鬼屋

这篇博客介绍了如何使用Three.js创建一个鬼屋场景,包括线性雾的设定,颜色参数,以及各种灯光效果如点光源、方向光等。场景中包含房屋细节如屋顶、门、墙壁、地板,并应用了多种纹理贴图。此外,还设置了多个点光源作为鬼魂,以及阴影效果,使得场景更加生动。
摘要由CSDN通过智能技术生成

雾(Fog)

这个类中的参数定义了线性雾。也就是说,雾的密度是随着距离线性增大的。

构造器

Fog( color : Integer, near : Float, far : Float )

颜色参数传入Color构造函数中,来设置颜色属性。颜色可以是一个十六进制的整型数,或者是CSS风格的字符串。

鬼屋代码: 

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import ky from "kyouka";
const canvas= document.querySelector("canvas.webgl");
const sizes={
  width:window.innerWidth,
  height:window.innerHeight
}
const houseHeight = 2.5;
const houseWidth = 4;
const roofHeight = 1;
const scene=new THREE.Scene();
const ambientLight=new THREE.AmbientLight('#b9d5ff',0.52)
scene.add(ambientLight)
const house=new THREE.Group()

const textureLoader=new THREE.TextureLoader()
const doorColorTexture=textureLoader.load('textures/door/color.jpg')
const doorAlphaTexture=textureLoader.load('textures/door/alpha.jpg')
const doorAomapTexture=textureLoader.load('textures/door/ambientOcclusion.jpg')
const doorHeightTexture=textureLoader.load('textures/door/height.jpg')
const doorMetalnessTexture=textureLoader.load('textures/door/metalness.jpg')
const doorRoughnessTexture=textureLoader.load('textures/door/roughness.jpg')
const doorNormalTexture=textureLoader.load('textures/door/normal.jpg')
const wallsColorTexture=textureLoader.load('textures/bricks/color.jpg')
const wallsAomapTexture=textureLoader.load('textures/bricks/ambientOcclusion.jpg')
const wallsRoughnessTexture=textureLoader.load('textures/bricks/roughness.jpg')
const wallsNormalTexture=textureLoader.load('textures/bricks/normal.jpg')

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

const fog=new THREE.Fog('#262837',1,15)
scene.fog=fog

const pontLight=new THREE.PointLight('#ff7d46',1,7)
pontLight.position.set(0,2.2,2.7)
house.add(pontLight)
const moonLight = new THREE.DirectionalLight("#b9d5ff", 0.12);
moonLight.position.set(4, 5, -2);
scene.add(moonLight)
/**
 * 屋顶
 */
const roof = new THREE.Mesh(
  new THREE.ConeBufferGeometry(3.5, roofHeight, 4),
  new THREE.MeshStandardMaterial({
    color:'#b35f45'
  })
)
roof.position.y = houseHeight + roofHeight / 2;
roof.rotation.y = ky.deg2rad(45);
house.add(roof)

/**
 * 门
 */
const door=new THREE.Mesh(
  new THREE.PlaneBufferGeometry(2.2,2.2,100,100),
  new THREE.MeshStandardMaterial({
    map:doorColorTexture,
    alphaMap:doorAlphaTexture,
    transparent:true,
    aoMap:doorAomapTexture,
    displacementMap:doorHeightTexture,
    displacementScale:0.1,
    roughnessMap:doorRoughnessTexture,
    metalnessMap:doorMetalnessTexture,
    normalMap:doorNormalTexture
  })
)
door.position.set(0, 1, houseWidth / 2 + 0.01);
door.geometry.setAttribute(
  'uv2',
  new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array,2)
)
house.add(door)

/**
 * 鬼魂
 */
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)

/**
 * 墙
 */
const walls=new THREE.Mesh(
  new THREE.BoxBufferGeometry(4,2.5,4),
  new THREE.MeshStandardMaterial({
    map:wallsColorTexture,
    roughnessMap:wallsRoughnessTexture,
    transparent:true,
    normalMap:wallsNormalTexture,
    aoMap:wallsAomapTexture
  })
)
walls.position.y = houseHeight / 2;
walls.geometry.setAttribute(
  'uv2',
  new THREE.Float32BufferAttribute(walls.geometry.attributes.uv.array,2)
)
house.add(walls)
scene.add(house)


/**
 * 灌木
 */
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.2);

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();
const graveGeometry=new THREE.BoxBufferGeometry(0.6,0.8,0.2)
const graveMaterial=new THREE.MeshStandardMaterial({ color: "#b2b6b1" })
const graveCount=50
for(let i=0;i<graveCount;i++){
  const angle=Math.random()*Math.PI*2;
  const radius=3+Math.random()*6
  const grave=new THREE.Mesh(graveGeometry,graveMaterial)
  const x=Math.sin(angle)*radius
  const z=Math.cos(angle)*radius
  grave.position.set(x,0.3,z)
  grave.rotation.z=(Math.random()-0.5)*0.4
  grave.rotation.y=(Math.random()-0.5)*0.4
  graves.add(grave)
}
scene.add(graves);


/**
 * 地板
 */
 const floor=new THREE.Mesh(
  new THREE.PlaneBufferGeometry(20,20),
  new THREE.MeshStandardMaterial({
    map:grassColorTexture,
    roughnessMap:grassRoughnessTexture,
    normalMap:grassNormalTexture,
    aoMap:grassAomapTexture
  })
)
floor.geometry.setAttribute(
  'uv2',
  new THREE.Float32BufferAttribute(floor.geometry.attributes.uv.array,2)
)
grassColorTexture.repeat.set(8,8)
grassAomapTexture.repeat.set(8,8)
grassNormalTexture.repeat.set(8,8)
grassRoughnessTexture.repeat.set(8,8)
grassAomapTexture.wrapS=THREE.RepeatWrapping
grassColorTexture.wrapS=THREE.RepeatWrapping
grassNormalTexture.wrapS=THREE.RepeatWrapping
grassRoughnessTexture.wrapS=THREE.RepeatWrapping

grassAomapTexture.wrapT=THREE.RepeatWrapping
grassColorTexture.wrapT=THREE.RepeatWrapping
grassNormalTexture.wrapT=THREE.RepeatWrapping
grassRoughnessTexture.wrapT=THREE.RepeatWrapping
floor.rotation.x=-Math.PI*0.5
scene.add(floor)

/**
 * shadows
 */



const camera= new THREE.PerspectiveCamera( 75,
  sizes.width / sizes.height,
  0.1,
  100 );
camera.position.set(4,5,15)
camera.aspect=sizes.width/sizes.height
scene.add(camera)
const renderer=new THREE.WebGLRenderer({
  canvas:canvas
})
const controls=new OrbitControls(camera,canvas)


renderer.setSize(sizes.width,sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2))
renderer.shadowMap.enabled=true
moonLight.castShadow = true;
ghost1.castShadow=true;
ghost2.castShadow=true;
ghost3.castShadow=true;
pontLight.castShadow=true;
for (let i = 0; i < graveCount; i++) {
  graves.children[i].castShadow = true;
}
walls.receiveShadow=true;
door.receiveShadow=true;
floor.receiveShadow=true
moonLight.shadow.mapSize.width=1024
moonLight.shadow.mapSize.height=1024
moonLight.shadow.far=7

ghost1.shadow.mapSize.width=1024
ghost1.shadow.mapSize.height=1024
ghost1.shadow.far=7

ghost2.shadow.mapSize.width=1024
ghost2.shadow.mapSize.height=1024
ghost2.shadow.far=7

ghost3.shadow.mapSize.width=1024
ghost3.shadow.mapSize.height=1024
ghost3.shadow.far=7

pontLight.shadow.mapSize.width=1024
pontLight.shadow.mapSize.height=1024
pontLight.shadow.far=7
window.addEventListener('resize',()=>{
  camera.aspect=sizes.width/sizes.height
  camera.updateProjectionMatrix();
  renderer.setSize(sizes.width,sizes.height)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio,2))
  renderer.setClearColor('#262837')
})

const clock=new THREE.Clock()
const tick=()=>{
  const elapsedTime=clock.getElapsedTime();
  controls.update()
  renderer.render(scene,camera)
  ghost1.position.x=Math.cos(elapsedTime)*4
  ghost1.position.z=Math.sin(elapsedTime)*4
  ghost1.position.y=Math.sin(elapsedTime*3)*3

  ghost2.position.x=-Math.cos(elapsedTime)*3
  ghost2.position.z=-Math.sin(elapsedTime)*3
  ghost2.position.y=-Math.sin(elapsedTime*3)*3

  const ghost3Angle = -elapsedTime * 0.18;
  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(elapsedTime * 4) + Math.sin(elapsedTime * 2.5);
  window.requestAnimationFrame(tick)
}
tick()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值