六、应用,搭建一个鬼屋

// 雾 开始应用雾的最小距离。距离小于活动摄像机“near”个单位的物体将不会被雾所影响。 结束计算、应用雾的最大距离,距离大于活动摄像机“far”个单位的物体将不会被雾所影响。
const fog = new THREE.Fog("#262837", 1, 15);
scene.fog = fog;

// 设置渲染器的背景颜色
renderer.setClearColor(fog.color);
  • 样例
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import GUI from "lil-gui";

/**
 * Base
 */
// Debug
const gui = new GUI();

// Canvas
const canvas = document.querySelector("canvas.webgl");

// Scene
const scene = new THREE.Scene();

// 雾 开始应用雾的最小距离。距离小于活动摄像机“near”个单位的物体将不会被雾所影响。 结束计算、应用雾的最大距离,距离大于活动摄像机“far”个单位的物体将不会被雾所影响。
const fog = new THREE.Fog("#262837", 1, 15);
scene.fog = fog;

/**
 * Textures
 */
const textureLoader = new THREE.TextureLoader();

const doorColorTexture = textureLoader.load("/textures/door/color.jpg");
const doorAlphaTexture = textureLoader.load("/textures/door/alpha.jpg");
const doorAmbientOcclusionTexture = textureLoader.load(
  "/textures/door/ambientOcclusion.jpg"
);
const doorHeightTexture = textureLoader.load("/textures/door/height.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");
// doorColorTexture.colorSpace = THREE.SRGBColorSpace

const bricksColorTexture = textureLoader.load("/textures/bricks/color.jpg");
const bricksAmbientOcclusionTexture = textureLoader.load(
  "/textures/bricks/ambientOcclusion.jpg"
);
const bricksNormalTexture = textureLoader.load("/textures/bricks/normal.jpg");
const bricksRoughnessTexture = textureLoader.load(
  "/textures/bricks/roughness.jpg"
);
bricksColorTexture.colorSpace = THREE.SRGBColorSpace;

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"
);
grassColorTexture.colorSpace = THREE.SRGBColorSpace;
// 草地平铺
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;

const windowColorTexture = textureLoader.load("/textures/window/color.png");
windowColorTexture.colorSpace = THREE.SRGBColorSpace;

/**
 * House
 */

// Group
const house = new THREE.Group();
scene.add(house);
//墙壁屋子宽4米,高2.5米,长4米
const walls = new THREE.Mesh(
  new THREE.BoxGeometry(4, 2.5, 4),
  new THREE.MeshStandardMaterial({
    // color: '#ac8e82'
    map: bricksColorTexture,
    aoMap: bricksAmbientOcclusionTexture,
    aoMapIntensity: 2,
    normalMap: bricksNormalTexture,
    roughnessMap: bricksRoughnessTexture,
  })
);
walls.geometry.setAttribute(
  "uv2",
  new THREE.Float32BufferAttribute(walls.geometry.attributes.uv.array, 2)
);
walls.position.y = 2.5 / 2;
house.add(walls);
// 屋顶
const roof = new THREE.Mesh(
  new THREE.ConeGeometry(4, 2, 4),
  new THREE.MeshStandardMaterial({
    color: "#b35f45",
  })
);

roof.position.y = 2.5 + 1;
roof.rotation.y = Math.PI * 0.25;
house.add(roof);

// 门
const door = new THREE.Mesh(
  new THREE.PlaneGeometry(2.2, 2.2, 100, 100),
  new THREE.MeshStandardMaterial({
    // color: '#ff7d67'
    map: doorColorTexture,
    alphaMap: doorAlphaTexture,
    transparent: true,
    aoMap: doorAmbientOcclusionTexture, // 环境遮挡贴图,显示阴影部分
    aoMapIntensity: 2,
    displacementMap: doorHeightTexture, //位移贴图,显示高度
    displacementScale: 0.1,
    normalMap: doorNormalTexture, //法线贴图,显示高光部分
    metalnessMap: doorMetalnessTexture, // 金属贴图,显示金属部分
    // metalness: 0.45,
    roughnessMap: doorRoughnessTexture, // 粗糙度贴图,显示非金属部分
    // roughness: 0.65,
  })
);
// door.material.aoMapIntensity = 2; //环境遮挡效果的强度。默认值为1。零是不遮挡效果。
door.geometry.setAttribute(
  "uv2",
  new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2)
);
door.position.y = 1;
door.position.z = 2 + 0.01; // Slightly in front of the walls to avoid z-fighting
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.2);

const bush4 = new THREE.Mesh(bushGeometry, bushMaterial);
bush4.scale.set(0.15, 0.15, 0.15);
bush4.position.set(-1.25, 0.05, 2.2);
house.add(bush1, bush2, bush3, bush4);

// 墓园
const graves = new THREE.Group();
scene.add(graves);
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(
    new THREE.BoxGeometry(0.6, 0.8, 0.2),
    new THREE.MeshStandardMaterial({ color: "#b2b6b1" })
  );
  grave.position.set(x, 0.3, z);
  grave.rotation.y = (Math.random() - 0.5) * 0.4;
  grave.rotation.z = (Math.random() - 0.5) * 0.4;
  grave.castShadow = true;
  graves.add(grave);
}

//门灯
const doorLight = new THREE.PointLight("#ff7d67", 1, 7);
doorLight.position.set(0, 2.2, 2.7);
house.add(doorLight);

// 窗户
const planeGeometry = new THREE.PlaneGeometry(1, 1)
const windowMaterial = new THREE.MeshStandardMaterial({
    transparent: true,
    map:windowColorTexture
})
// 右边
const window1 = new THREE.Mesh(planeGeometry, windowMaterial)
window1.position.y = 1.25
window1.position.z = 0
window1.position.x = 2 + 0.01
window1.rotation.y = Math.PI / 2
// 左边
const window2 = new THREE.Mesh(planeGeometry, windowMaterial)
window2.position.y = 1.25
window2.position.z = 0
window2.position.x = -2.01
window2.rotation.y = Math.PI * 1.5
// 后边
const window3 = new THREE.Mesh(planeGeometry, windowMaterial)
window3.position.y = 1.25
window3.position.z = -2.01
window3.position.x = 0
window3.rotation.y = Math.PI 

house.add(window1, window2, window3)

//鬼魂
const ghost1 = new THREE.PointLight("#ff00ff", 2, 3);
ghost1.position.set(0, 1, 0);
ghost1.castShadow = true;
scene.add(ghost1);
const ghost2 = new THREE.PointLight("#00ffff", 2, 3);
ghost2.position.set(4, 1, 0);
ghost2.castShadow = true;
scene.add(ghost2);
const ghost3 = new THREE.PointLight("#ffff00", 2, 3);
ghost3.position.set(-4, 1, 0);
ghost3.castShadow = true;
scene.add(ghost3);

// Floor
const floor = new THREE.Mesh(
  new THREE.PlaneGeometry(20, 20),
  new THREE.MeshStandardMaterial({
    //  color: "#a9c388"
    map: grassColorTexture,
    aoMap: grassAmbientOcclusionTexture,
    aoMapIntensity: 2,
    normalMap: grassNormalTexture,
    roughnessMap: grassRoughnessTexture,
  })
);
floor.geometry.setAttribute(
  "uv2",
  new THREE.Float32BufferAttribute(floor.geometry.attributes.uv.array, 2)
);
floor.rotation.x = -Math.PI * 0.5;
floor.position.y = 0;
scene.add(floor);

/**
 * Lights
 */
// Ambient light
const ambientLight = new THREE.AmbientLight("#b9d5ff", 0.12);
gui.add(ambientLight, "intensity").min(0).max(1).step(0.001);
scene.add(ambientLight);

// Directional light
const moonLight = new THREE.DirectionalLight("#b9d5ff", 0.6);
moonLight.position.set(4, 5, -2);
gui.add(moonLight, "intensity").min(0).max(1).step(0.001);
gui.add(moonLight.position, "x").min(-5).max(5).step(0.001);
gui.add(moonLight.position, "y").min(-5).max(5).step(0.001);
gui.add(moonLight.position, "z").min(-5).max(5).step(0.001);
scene.add(moonLight);

/**
 * Sizes
 */
const sizes = {
  width: window.innerWidth,
  height: window.innerHeight,
};

window.addEventListener("resize", () => {
  // Update sizes
  sizes.width = window.innerWidth;
  sizes.height = window.innerHeight;

  // Update camera
  camera.aspect = sizes.width / sizes.height;
  camera.updateProjectionMatrix();

  // Update renderer
  renderer.setSize(sizes.width, sizes.height);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});

/**
 * Camera
 */
// Base camera
const camera = new THREE.PerspectiveCamera(
  75,
  sizes.width / sizes.height,
  0.1,
  100
);
camera.position.x = 4;
camera.position.y = 2;
camera.position.z = 5;
scene.add(camera);

// Controls
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// 设置渲染器的背景颜色
renderer.setClearColor(fog.color);

// 开启阴影
renderer.shadowMap.enabled = true;
floor.receiveShadow = true;
moonLight.castShadow = true;
for (let index = 0; index < house.children.length; index++) {
  const element = house.children[index];
  element.castShadow = true;
}
// 阴影优化
doorLight.shadow.mapSize.width = 256
doorLight.shadow.mapSize.height = 256
doorLight.shadow.camera.far = 7

moonLight.shadow.mapSize.width = 256
moonLight.shadow.mapSize.height = 256
moonLight.shadow.camera.far = 15

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

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

const tick = () => {
  const elapsedTime = clock.getElapsedTime();
  //   鬼魂移动
  ghost1.position.x = Math.cos(elapsedTime * 0.5) * 4;
  ghost1.position.z = Math.sin(elapsedTime * 0.5) * 4;
  ghost1.position.y = Math.sin(elapsedTime * 3.5) * 1 + 1;
  ghost2.position.x = Math.cos(elapsedTime * 0.5) * 5;
  ghost2.position.z = Math.sin(elapsedTime * 0.5) * 5;
  ghost2.position.y = Math.sin(elapsedTime * 4) * 1 + 1;
  ghost3.position.x = Math.cos(elapsedTime * 0.5) * 3;
  ghost3.position.z = Math.sin(elapsedTime * 0.5) * 3;
  ghost3.position.y = Math.sin(elapsedTime * 3) * 1 + 1;

  // Update controls
  controls.update();

  // Render
  renderer.render(scene, camera);

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

tick();

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容