threejs之波浪球效果(初级实现思路)
今天看到了一个官网上的一个波纹球的效果,感觉很好看,于是便想用自己已经学的threejs的知识写一个
threejs管网的示例是这样的:
我的最后写完是这样式的(emmm,能跑就行):
虽然感觉看起来差点,但是大同小异哈哈哈哈
首先我们要思考,如何来生成这些圆,生成一个肯定很点单对吧(如果你认真看过我上一期的文章《初识threejs》的话)
好的,我们来先放个圆
//生成一个球var geometry = new THREE.SphereGeometry(10, 10, 10);//材质var material = new THREE.MeshNormalMaterial({color: 0xff0000,});//创建对象let mesh = new THREE.Mesh(geometry, material);//球的坐标mesh.position.x=100;mesh.position.y=200;//渲染scene.add(mesh);
然后,它就这样了:
因为我们要做动画,肯定有很多个圆,所以,如何实现呢?
基于我现在还不知道有BufferAttribute这个东西,所以呢我们肯定要用循环啦!(大佬勿喷,我是新手)
var geometry = new THREE.SphereGeometry(10, 10, 10);var material = new THREE.MeshNormalMaterial({color: 0xff0000,});for(let i=-20;i<=20;i++){for(let j=-20;j<=20;j++){let mesh = new THREE.Mesh(geometry, material);mesh.position.x=i*100;mesh.position.y=j*200;scene.add(mesh);}}
然后界面上就有很多圆了,成功得到了一个圆的矩阵!
然后呢,重点来了,我们怎么让它动起来呢???
在animate里改变它的Z坐标吗?
好的我们先加个试试,但是要怎么改变呢,我也获取不到每个圆,所以,我神操作把圆存进了一个数组里!没毛病吧!哈哈哈哈!(能跑就行!)
我只需要循环数组改变它的Z值就可以了吧!
由于想让他们上下看起来像波浪,所以要用到Math.cos函数,emmm,先随便试试!
var animate = function () {requestAnimationFrame( animate );var time = performance.now();for(let i=0;i<arr.length;i++){arr[i].position.z = 200*Math.cos(time*Math.PI/180)}renderer.render( scene, camera );};
它这样了!
动是可以了,但是你不能一起动啊!!!我要的是波浪啊!!
思考:波浪怎么实现
要让每个圆的Z变化量不能一样,emm,对了,我们不是循环吗,可以根据循环的值来改变Z值啊!
说干就干,我改成了这样!
arr[i].position.z = 200*Math.cos((time-i*0.2)*Math.PI/180)
效果:
横着能动了,但是竖着应该也在动只不过差的有点小看不出来吧应该
所以竖着怎么动啊!
在我掉了一缕头发后,我想到了,我是一个正方形啊,我横着能动了,我再把竖着的取个余数剪了不就是变量了吗???
所以在我剪了个余数乘某个值后,乘的这个值主要是为了改变它动的速度。
arr[i].position.z = 200*Math.cos((time-i%41*10-i*0.2)*Math.PI/180)
他看着有内味了!剩下的就是微调的玩意了!
然后我看了一眼官方的demo,我写的是个什么 * * 东西啊???
最终代码直接贴下边:
<html lang="en"><head><title>three.js webgl - instancing test (single triangle)</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><link type="text/css" rel="stylesheet" href="main.css"><style>a {color: #08f;}#notSupported {width: 50%;margin: auto;background-color: #f00;margin-top: 20px;padding: 10px;}</style><script src="three.min.js"></script><script src="OrbitControls.js"></script></head><body><div id="container"></div><script type="module">var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 0.1, 1000000 );var renderer = new THREE.WebGLRenderer();renderer.setSize( window.innerWidth, window.innerHeight );document.body.appendChild( renderer.domElement );//允许阴20renderer.shadowMapEnabled = true;camera.position.x = 0;camera.position.y = -6000;camera.position.z = 500;var arr = [];var geometry = new THREE.SphereGeometry(10, 10, 10);var material = new THREE.MeshNormalMaterial({color: 0xff0000,});for(let i=-20;i<=20;i++){for(let j=-20;j<=20;j++){let mesh = new THREE.Mesh(geometry, material);mesh.position.x=i*100;mesh.position.y=j*200;scene.add(mesh);arr.push(mesh);}}var spotLight = new THREE.AmbientLight(0xffffff);spotLight.castShadow = true;scene.add(spotLight);// 相机允许鼠标变化var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象controls.addEventListener('change', renderer);//监听鼠标、键盘事件controls.autoRotate=true;var animate = function () {requestAnimationFrame( animate );var time = performance.now()/5;for(let i=0;i<arr.length;i++){arr[i].position.z = 200*Math.cos((time-i%41*10-i*0.2)*Math.PI/180)}renderer.render( scene, camera );};animate();</script></body>
官方代码:
<html lang="en"><head><title>three.js webgl - particles - waves</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><link type="text/css" rel="stylesheet" href="main.css"></head><body><div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl particles waves example</div><script type="x-shader/x-vertex" id="vertexshader">attribute float scale;void main() {vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_PointSize = scale * ( 300.0 / - mvPosition.z );gl_Position = projectionMatrix * mvPosition;}</script><script type="x-shader/x-fragment" id="fragmentshader">uniform vec3 color;void main() {if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;gl_FragColor = vec4( color, 1.0 );}</script><script type="module">import * as THREE from '../build/three.module.js';import Stats from './jsm/libs/stats.module.js';var SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50;var container, stats;var camera, scene, renderer;var particles, count = 0;var mouseX = 0, mouseY = 0;var windowHalfX = window.innerWidth / 2;var windowHalfY = window.innerHeight / 2;init();animate();function init() {container = document.createElement( 'div' );document.body.appendChild( container );camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );camera.position.z = 1000;scene = new THREE.Scene();//var numParticles = AMOUNTX * AMOUNTY;var positions = new Float32Array( numParticles * 3 );var scales = new Float32Array( numParticles );var i = 0, j = 0;for ( var ix = 0; ix < AMOUNTX; ix ++ ) {for ( var iy = 0; iy < AMOUNTY; iy ++ ) {positions[ i ] = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 ); // xpositions[ i + 1 ] = 0; // ypositions[ i + 2 ] = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 ); // zscales[ j ] = 1;i += 3;j ++;}}var geometry = new THREE.BufferGeometry();geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );geometry.setAttribute( 'scale', new THREE.BufferAttribute( scales, 1 ) );var material = new THREE.ShaderMaterial( {uniforms: {color: { value: new THREE.Color( 0xffffff ) },},vertexShader: document.getElementById( 'vertexshader' ).textContent,fragmentShader: document.getElementById( 'fragmentshader' ).textContent} );//particles = new THREE.Points( geometry, material );scene.add( particles );//renderer = new THREE.WebGLRenderer( { antialias: true } );renderer.setPixelRatio( window.devicePixelRatio );renderer.setSize( window.innerWidth, window.innerHeight );container.appendChild( renderer.domElement );stats = new Stats();container.appendChild( stats.dom );document.addEventListener( 'mousemove', onDocumentMouseMove, false );document.addEventListener( 'touchstart', onDocumentTouchStart, false );document.addEventListener( 'touchmove', onDocumentTouchMove, false );//window.addEventListener( 'resize', onWindowResize, false );}function onWindowResize() {windowHalfX = window.innerWidth / 2;windowHalfY = window.innerHeight / 2;camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );}//function onDocumentMouseMove( event ) {mouseX = event.clientX - windowHalfX;mouseY = event.clientY - windowHalfY;}function onDocumentTouchStart( event ) {if ( event.touches.length === 1 ) {event.preventDefault();mouseX = event.touches[ 0 ].pageX - windowHalfX;mouseY = event.touches[ 0 ].pageY - windowHalfY;}}function onDocumentTouchMove( event ) {if ( event.touches.length === 1 ) {event.preventDefault();mouseX = event.touches[ 0 ].pageX - windowHalfX;mouseY = event.touches[ 0 ].pageY - windowHalfY;}}//function animate() {requestAnimationFrame( animate );render();stats.update();}function render() {camera.position.x += ( mouseX - camera.position.x ) * .05;camera.position.y += ( - mouseY - camera.position.y ) * .05;camera.lookAt( scene.position );var positions = particles.geometry.attributes.position.array;var scales = particles.geometry.attributes.scale.array;var i = 0, j = 0;for ( var ix = 0; ix < AMOUNTX; ix ++ ) {for ( var iy = 0; iy < AMOUNTY; iy ++ ) {positions[ i + 1 ] = ( Math.sin( ( ix + count ) * 0.3 ) * 50 ) +( Math.sin( ( iy + count ) * 0.5 ) * 50 );scales[ j ] = ( Math.sin( ( ix + count ) * 0.3 ) + 1 ) * 8 +( Math.sin( ( iy + count ) * 0.5 ) + 1 ) * 8;i += 3;j ++;}}particles.geometry.attributes.position.needsUpdate = true;particles.geometry.attributes.scale.needsUpdate = true;renderer.render( scene, camera );count += 0.1;}</script></body></html>
好了,今天就到这里了,我要继续研究官方的demo了,蚌埠住了!
结尾福利:
