游戏场景中的动态道路
今天在shadertoy上看到了一个效果,是个游戏的道路场景,十分亲切。一看代码10行?UC震惊部来了。太牛了,真的10行,佩服,直呼看不懂。
不过不影响我们拿来用,恩,移植到three中跑了一下,完美实现。
移植流程
1. 导入 Three.js
在使用 Three.js 之前,我们需要先导入 Three.js 库。可以通过以下代码进行导入:
import * as THREE from 'three';
2. 创建场景和相机
在 Three.js 中,我们需要先创建一个场景和一个相机。可以通过以下代码进行创建:
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, _w / _h, 1, 1000);
camera.position.z = 112;
const vertexShader = `
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
let fragmentShader = `
uniform float iTime;
varying vec2 vUv;
void main() {
vec2 p = vUv;
vec3 q=vec3(1.0,1.0,1.0),d=vec3(p-.5*q.xy,q.y)/q.y,c=vec3(0,.5,.7);
q=d/(.1-d.y);
float a=iTime, k=sin(.2*a), w = q.x *= q.x-=.05*k*k*k*q.z*q.z;
vec3 col = vec3(0);
col.xyz=d.y>.04?c:
sin(4.*q.z+40.*a)>0.?
w>2.?c.xyx:w>1.2?d.zzz:c.yyy:
w>2.?c.xzx:w>1.2?c.yxx*2.:(w>.004?c:d).zzz;
gl_FragColor = vec4(col,1.0);
}
`;
let width = 160;
const geometry = new THREE.PlaneGeometry(width,width*_b)
const material = new THREE.ShaderMaterial({
uniforms: {
iTime: { value: 0 },
},
fragmentShader: fragmentShader,
vertexShader: vertexShader,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(_w,_h);
// new OrbitControls(camera, renderer.domElement);
renderer.setClearColor(0xFFFFFF, 1.0);
document.body.appendChild(renderer.domElement);
let speed = 0.01;
function animate() {
requestAnimationFrame(animate);
material.uniforms.iTime.value += speed;
renderer.render(scene, camera);
}
animate();
let div = document.getElementById("speed");
div.innerHTML = `速度:${speed*3000 | 0}`
window.addEventListener('keydown',(event)=>{
switch (event.key) {
case 'w':
speed += 0.0005;
break;
case 's':
speed -= 0.0005;
break;
case ' ':
speed = 0 ;
break;
}
div.innerHTML = `速度:${speed*3000 | 0}`
})
在这里,我们使用了透视相机 PerspectiveCamera
,并设置了视角 fov
、宽高比 aspect
、近截面 near
和远截面 far
。然后,我们将相机的位置设置为 (0, 0, 5)
,也就是在场景中的坐标为 (0, 0, 0)
的位置后面。
3. 创建渲染器
接下来,我们需要创建一个渲染器,用于将场景渲染到屏幕上。在这里,我们创建了一个 WebGL 渲染器 WebGLRenderer
,并将它的大小设置为窗口大小。然后,我们将渲染器的 DOM 元素添加到了页面中。
4. 创建几何体和材质
在 Three.js 中,我们需要将几何体和材质结合起来,才能形成一个完整的物体。可以通过以下代码进行创建.在这里,我们创建了一个平面几何体 PlaneGeometry
,并使用了基础网格材质 ShaderMaterial
,将它们结合起来形成了一个物体。然后,我们将这个物体添加到了场景中。
5. 渲染场景
最后,我们需要在动画循环中渲染场景。可以通过以下代码进行循环.我们使用了 requestAnimationFrame
函数来进行动画循环,并在每次循环中旋转物体 cube
,然后使用渲染器 renderer
渲染场景 scene
和相机 camera
。
代码是shader写的,核心代码如下。
uniform float iTime;
varying vec2 vUv;
void main() {
vec2 p = vUv;
vec3 q=vec3(1.0,1.0,1.0),d=vec3(p-.5*q.xy,q.y)/q.y,c=vec3(0,.5,.7);
q=d/(.1-d.y);
float a=iTime, k=sin(.2*a), w = q.x *= q.x-=.05*k*k*k*q.z*q.z;
vec3 col = vec3(0);
col.xyz=d.y>.04?c:
sin(4.*q.z+40.*a)>0.?
w>2.?c.xyx:w>1.2?d.zzz:c.yyy:
w>2.?c.xzx:w>1.2?c.yxx*2.:(w>.004?c:d).zzz;
gl_FragColor = vec4(col,1.0);
}
为了增加趣味性,我添加了三个按键,加速、减速、归零。在线体验地址,为了体验我固定了宽高。