ThreeJs 学习之旅(九)—shadows(阴影)

前情代码:

import "./style.css";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as dat from "dat.gui";

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

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

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

/**
 * Lights
 */
// Ambient light
const ambientLight=new THREE.AmbientLight()
scene.add(ambientLight)

/**
 * Materials
 */
const material = new THREE.MeshStandardMaterial();
material.roughness = 0.7;
gui.add(material, "metalness").min(0).max(1).step(0.001);
gui.add(material, "roughness").min(0).max(1).step(0.001);

/**
 * Objects
 */
const sphere = new THREE.Mesh(
  new THREE.SphereBufferGeometry(0.5, 32, 32),
  material
);
const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(5, 5), material);
plane.rotation.x = -Math.PI * 0.5;
plane.position.y = -0.5;
scene.add(sphere,plane)
/**
 * 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 = 1;
camera.position.y = 1;
camera.position.z = 2;
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));

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

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

  // Update controls
  controls.update();

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

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

tick();

效果:

.castShadow : Boolean

对象是否被渲染到阴影贴图中。默认值为false

receiveShadow : Boolean

材质是否接收阴影。默认值为false

const spotLight=new THREE.SpotLight(0xffffff,0.5)
spotLight.position.set(1,2,1)
spotLight.castShadow=true
scene.add(spotLight)

sphere.castShadow=true;    
plane.receiveShadow=true;  
  

renderer.shadowMap.enabled=true    //渲染器启用阴影

 优化阴影效果

.mapSize : Vector2

一个Vector2定义阴影贴图的宽度和高度

spotLight.shadow.mapSize.width=1024
spotLight.shadow.mapSize.height=1024

CameraHelper

用于模拟相机视锥体的辅助对象.
它使用 LineSegments 来模拟相机视锥体.

构造函数
CameraHelper( camera : Camera )
camera -- 被模拟的相机.

为指定相机创建一个新的相机辅助对象 CameraHelper .

构造函数
CameraHelper( camera : Camera )
camera -- 被模拟的相机.

为指定相机创建一个新的相机辅助对象 CameraHelper .

 开启 CameraHelper

const spotLightHelper=new THREE.CameraHelper(spotLight.shadow.camera);
spotLightHelper.visible=true;
scene.add(spotLightHelper)

 加一个点光源


const pointLight=new THREE.PointLight(0xff0000)
pointLight.position.set( -1, 1, 1 );
pointLight.shadow.mapSize.width=1024
pointLight.shadow.mapSize.height=1024
pointLight.shadow.camera.far=10;
pointLight.castShadow=true
scene.add( pointLight );
const pointLightHelper=new THREE.CameraHelper(pointLight.shadow.camera);
pointLightHelper.visible=true;
scene.add(pointLightHelper)

 

 给阴影上材质


const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(5, 5),
  new THREE.MeshBasicMaterial({
    map:bakedShadow
  })
);

 通过创建平面的方式创建阴影

const sphereShadow=new THREE.Mesh(new THREE.PlaneBufferGeometry(1,1),
  new THREE.MeshBasicMaterial({
    transparent:true,
    color:0x000000,
    alphaMap:simpleShadow
  }) 
)
sphereShadow.rotation.x=-Math.PI*0.5
sphereShadow.position.y=plane.position.y+0.01
scene.add(sphereShadow)

最后让他动起来 

const tick = () => {
  const elapsedTime = clock.getElapsedTime();
 // // Update the sphere
  sphere.position.x = Math.cos(elapsedTime) * 1.5;
  sphere.position.z = Math.sin(elapsedTime) * 1.5;
  sphere.position.y = Math.abs(Math.sin(elapsedTime * 3));

  // Update the shadow
  sphereShadow.position.x = sphere.position.x;
  sphereShadow.position.z = sphere.position.z;
  sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3;
  // Update controls
  controls.update();

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

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

tick();

本期素材

本期全部代码

import "./style.css";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as dat from "dat.gui";

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

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

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

const texture=new THREE.TextureLoader();
const bakedShadow=texture.load('/textures/bakedShadow.jpg')
const simpleShadow=texture.load('/textures/simpleShadow.jpg')
/**
 * Lights
 */
// Ambient light
const ambientLight=new THREE.AmbientLight(0xffffff,0.3)
scene.add(ambientLight)

const spotLight=new THREE.SpotLight(0xffffff,0.5)
spotLight.position.set(1,2,1)
spotLight.shadow.mapSize.width=1024
spotLight.shadow.mapSize.height=1024
spotLight.shadow.camera.far=10;
spotLight.shadow.camera.top=1;
// spotLight.castShadow=true
scene.add(spotLight)
const spotLightHelper=new THREE.CameraHelper(spotLight.shadow.camera);
spotLightHelper.visible=true;
scene.add(spotLightHelper)

const pointLight=new THREE.PointLight(0xffffff,0.3)
pointLight.position.set( -1, 1, 1 );
pointLight.shadow.mapSize.width=1024
pointLight.shadow.mapSize.height=1024
pointLight.shadow.camera.far=10;
pointLight.shadow.camera.top=1;
// pointLight.castShadow=true
scene.add( pointLight );
const pointLightHelper=new THREE.CameraHelper(pointLight.shadow.camera);
pointLightHelper.visible=true;
scene.add(pointLightHelper)

/**
 * Materials
 */
const material = new THREE.MeshStandardMaterial();
material.roughness = 0.7;
gui.add(material, "metalness").min(0).max(1).step(0.001);
gui.add(material, "roughness").min(0).max(1).step(0.001);

/**
 * Objects
 */
const sphere = new THREE.Mesh(
  new THREE.SphereBufferGeometry(0.5, 32, 32),
  material
);
sphere.castShadow=true;

const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(5, 5), material);
plane.rotation.x = -Math.PI * 0.5;
plane.position.y = -0.5;
plane.receiveShadow=true;
scene.add(sphere,plane)
const sphereShadow=new THREE.Mesh(new THREE.PlaneBufferGeometry(1,1),
  new THREE.MeshBasicMaterial({
    transparent:true,
    color:0x000000,
    alphaMap:simpleShadow
  }) 
)
sphereShadow.rotation.x=-Math.PI*0.5
sphereShadow.position.y=plane.position.y+0.01
scene.add(sphereShadow)
/**
 * 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 = 1;
camera.position.y = 1;
camera.position.z = 2;
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.shadowMap.enabled=true

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

const tick = () => {
  const elapsedTime = clock.getElapsedTime();
 // // Update the sphere
  sphere.position.x = Math.cos(elapsedTime) * 1.5;
  sphere.position.z = Math.sin(elapsedTime) * 1.5;
  sphere.position.y = Math.abs(Math.sin(elapsedTime * 3));

  // Update the shadow
  sphereShadow.position.x = sphere.position.x;
  sphereShadow.position.z = sphere.position.z;
  sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3;
  // Update controls
  controls.update();

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

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

tick();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值