трехмерная графика three.js: как создать эффект распространения ряби с помощью трех.js + курсор плавает
2023-07-05 03:03:55
创建涟漪效果和交互式浮动指针的非凡三维水景
引言
使用 Three.js 创建逼真的三维可视化效果是一项激动人心的挑战。本文将指导您完成一个引人入胜的项目,在这个项目中,我们将利用 Three.js 的强大功能来创建一个栩栩如生的涟漪效果,并添加一个可以在水面自由移动的交互式浮动指针。
构建三维场景
第一步是创建一个场景,容纳我们的水景。我们将使用 Three.js 的 Scene 类来创建这个场景。
const scene = new THREE.Scene();
接下来,我们需要一个摄像机来查看场景。我们将使用 PerspectiveCamera 类创建一个透视摄像机。
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
创建水波纹效果
要创建涟漪效果,我们需要编写一个着色器。着色器是一种特殊类型的程序,可用于处理图形的像素。我们将创建一个片段着色器来计算每个像素的涟漪效果。
// 片段着色器
const fragmentShader = `
uniform float time;
uniform vec2 resolution;
varying vec2 vUv;
void main() {
vec2 uv = vUv;
// 计算涟漪中心
vec2 center = vec2(0.5, 0.5);
// 计算到涟漪中心的距离
float distance = length(uv - center);
// 计算涟漪半径
float radius = 0.2;
// 计算涟漪振幅
float amplitude = 0.1;
// 计算涟漪波长
float wavelength = 0.1;
// 计算涟漪速度
float speed = 1.0;
// 计算涟漪相位
float phase = time * speed;
// 计算涟漪位移
float displacement = amplitude * sin((distance - phase) / wavelength);
// 移动 UV 坐标
uv += vec2(displacement, 0.0);
// 采样纹理
vec3 color = texture2D(map, uv).rgb;
// 输出颜色
gl_FragColor = vec4(color, 1.0);
}
`;
使用此着色器,我们将创建一个材料并将其应用到我们的水面几何体上。
const material = new THREE.ShaderMaterial({
fragmentShader: fragmentShader,
uniforms: {
time: { value: 0.0 },
resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
},
});
添加交互式浮动指针
为了增强互动性,我们将添加一个浮动指针,它可以在水面自由移动。我们将创建一个球体几何体并将其作为指针。
const geometry3 = new THREE.SphereGeometry(0.1, 32, 32);
const material3 = new THREE.MeshBasicMaterial({ color: 0xffffff });
const cursor = new THREE.Mesh(geometry3, material3);
实现动画和交互性
要使场景栩栩如生,我们需要对其进行动画处理。我们将使用 requestAnimationFrame() 来不断更新场景。
function animate() {
requestAnimationFrame(animate);
// 更新时间统一变量
material.uniforms.time.value += 0.01;
// 渲染场景
renderer.render(scene, camera);
}
为了使指针具有交互性,我们需要在鼠标移动时更新其位置。
function onMouseMove(event) {
// 计算光标位置
const x = (event.clientX / window.innerWidth) * 2 - 1;
const y = -(event.clientY / window.innerHeight) * 2 + 1;
// 更新光标位置
cursor.position.x = x;
cursor.position.y = y;
}
完成代码示例
以下是完整的代码示例:
<html>
<head>
<script src="https://unpkg.com/three@0.124.0/build/three.min.js"></script>
</head>
<body>
<script>
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 涟漪着色器
const fragmentShader = `
uniform float time;
uniform vec2 resolution;
varying vec2 vUv;
void main() {
vec2 uv = vUv;
// 涟漪中心
vec2 center = vec2(0.5, 0.5);
// 到涟漪中心的距离
float distance = length(uv - center);
// 涟漪半径
float radius = 0.2;
// 涟漪振幅
float amplitude = 0.1;
// 涟漪波长
float wavelength = 0.1;
// 涟漪速度
float speed = 1.0;
// 涟漪相位
float phase = time * speed;
// 涟漪位移
float displacement = amplitude * sin((distance - phase) / wavelength);
// 移动 UV 坐标
uv += vec2(displacement, 0.0);
// 采样纹理
vec3 color = texture2D(map, uv).rgb;
// 输出颜色
gl_FragColor = vec4(color, 1.0);
}
`;
// 涟漪材质
const material = new THREE.ShaderMaterial({
fragmentShader: fragmentShader,
uniforms: {
time: { value: 0.0 },
resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
},
});
// 交互式指针
const geometry3 = new THREE.SphereGeometry(0.1, 32, 32);
const material3 = new THREE.MeshBasicMaterial({ color: 0xffffff });
const cursor = new THREE.Mesh(geometry3, material3);
// 动画
function animate() {
requestAnimationFrame(animate);
// 更新时间统一变量
material.uniforms.time.value += 0.01;
// 渲染场景
renderer.render(scene, camera);
}
// 交互性
function onMouseMove(event) {
// 计算光标位置
const x = (event.clientX / window.innerWidth) * 2 - 1;
const y = -(event.clientY / window.innerHeight) * 2 + 1;
// 更新光标位置
cursor.position.x = x;
cursor.position.y = y;
}
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加到场景
scene.add(cursor);
// 事件监听器
window.addEventListener('mousemove', onMouseMove);
// 开始动画
animate();
</script>
</body>
</html>
常见问题解答
1. 如何调整涟漪效果的强度和波长?
通过修改涟漪材料中“振幅”和“波长”统一变量的值,可以调整涟漪效果的强度和波长。
2. 如何添加纹理以使水表面更逼真?
可以通过将纹理图像作为贴图应用到水面几何体来添加纹理。
3. 如何让指针对水面的互动更真实?
可以通过添加物理引擎(如 Cannon.js)来模拟水面的物理特性,使指针与水面的互动更加逼真。
4. 如何优化性能以提高帧速率?
可以通过降低纹理分辨率、使用更简单的几何体和减少场景中的光源数量来优化性能。
5. 可以使用 Three.js 创建其他哪些水效果?
使用 Three.js 可以创建各种水效果,包括波浪、漩涡和水下失真。