在three.js中已经为我们封装好了这一效果,我们只需要引入特定的包就可以使用;
引入三个js包,它们相互关联,缺一不可,否则会报错,可在工程文件夹下example文件夹找到
<script type="text/javascript" src="js/objects/Water2.js" ></script>//水的主要模型包
<script type="text/javascript" src="js/objects/Reflector.js" ></script>//实现水的反射效果
<script type="text/javascript" src="js/objects/Refractor.js" ></script>//实现水的折射效果
构造函数:
new THREE.Water(geometry,options)
-geometry:object,图形(一般使用平面PlaneGeometry图形)
-options:objects,
可选参数(颜色color,水波大小scale,流动方向flowDirection,画布宽度textureWidth,画布高度 textureHeight,流线图贴图flowMap等)
{
-
color:new THREE.Color(),
-
scale:number,
-
flowDirection:new THREE.Vector2(x,y),//二维方向向量
-
textureWidth:2的次方倍,
-
textureHeight:2的次方倍,
-
flowMap:map//流线贴图,
…
}
注意,flowDiretion和flowMap两个属性不能连用,会起冲突;
有些朋友问shapeGeometry可以不?我的回答是可以,但是更推荐使用threejs内置的geometry,使用自定义形状是有效果的,但是不太明显,因为shapeGeomtry本身顶点过于复杂,Water包·运算较慢,水流效果较缓,尤其是浅色的,几乎看不到效果
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试water的属性</title>
<script type="text/javascript" src="js/three.js" ></script>
<script type="text/javascript" src="js/libs/stats.min.js" ></script>
<script type="text/javascript" src="js/WebGL.js" ></script>
<script type="text/javascript" src="js/libs/dat.gui.min.js" ></script>
<script type="text/javascript" src="js/controls/OrbitControls.js" ></script>
<script type="text/javascript" src="js/objects/Water2.js" ></script>
<script type="text/javascript" src="js/objects/Reflector.js" ></script>
<script type="text/javascript" src="js/objects/Refractor.js" ></script>
<style>
body{
padding:0;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script>
if(WEBGL.isWebGLAvailable()===false){alert("该浏览器不支持WebGL!");document.body.appendChild(WEBGL.getWebGLErrorMessage());}
var scene,renderer,camera,controls,stats;
var cubeTexture=new THREE.CubeTextureLoader().setPath("img/skybox1/").load([
'px.jpg','nx.jpg',
'py.jpg','ny.jpg',
'pz.jpg','nz.jpg'
]);//天空盒子
function init(){
scene=new THREE.Scene();
scene.background=cubeTexture;
renderer=new THREE.WebGLRenderer({
antialias:true
});
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
camera=new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.1,1000);
camera.position.set(0,30,0);
camera.lookAt(scene.position);
controls=new THREE.OrbitControls(camera,renderer.domElement);
controls.enableDamping=true;
controls.minDistance=0.1;
controls.maxDistance=1000;
stats=new Stats();
document.body.appendChild(stats.dom);
scene.add(new THREE.AmbientLight(0x404040));
var dLight=new THREE.DirectionalLight(0xffffff,0.8);
dLight.position.set(-1,1,1);
scene.add(dLight);
}
var axes;var torusKnot;
var water1;var water2;var helper;
function initModel(){
axes=new THREE.AxesHelper(10);
scene.add(axes);
axes.visible=false;
var geometry=new THREE.PlaneBufferGeometry(20,20,1);
//平面1
var plane=new THREE.Mesh(geometry,new THREE.MeshStandardMaterial({
side:THREE.DoubleSide,
roughness:0.8,
metalness:0.4
}));
plane.position.set(-12,0,0);
plane.rotation.x=-0.5*Math.PI;
scene.add(plane);
new THREE.TextureLoader().load("textures/hardwood2_diffuse.jpg",function(map){
map.wrapS=map.wrapT=THREE.RepeatWrapping;
map.anisotropy=16;
map.repeat.set(4,4);
plane.material.map=map;
plane.material.needsUpdate=true;
});
torusKnot=new THREE.Mesh(new THREE.TorusKnotBufferGeometry(3,1,256,32),new THREE.MeshNormalMaterial());
torusKnot.scale.set(0.5,0.5,0.5);
torusKnot.position.set(-12,4,0);
scene.add(torusKnot);
//水1
water1=new THREE.Water(geometry,{
color:'#ffffff',
scale:2,
flowDirection:new THREE.Vector2(1,1),
textureWidth:1024,
textureHeight:1024,
});
water1.rotation.x=-0.5*Math.PI;
water1.position.set(-12,1,0);
scene.add(water1);
//平面二
var texture=new THREE.TextureLoader().load('textures/FloorsCheckerboard_S_Diffuse.jpg',function(map){
map.wrapS=map.wrapT=THREE.RepeatWrapping;
map.anisotropy=16;
map.repeat.set(4,4);
});
var ground=new THREE.Mesh(geometry,new THREE.MeshBasicMaterial({
color:0xcccccc,
map:texture
}));
ground.position.set(12,0,0);
ground.rotation.x=-Math.PI/2;
scene.add(ground);
//水2
var flowMap=new THREE.TextureLoader().load('textures/water/Water_1_M_Flow.jpg');
water2=new THREE.Water(geometry,{
scale:2,
textureWidth:1024,
textureHeiht:1024,
flowMap:flowMap
});
water2.rotation.x=-Math.PI/2;
water2.position.set(12,1,0);
scene.add(water2);
//贴图原图显示
helper=new THREE.Mesh(geometry,new THREE.MeshBasicMaterial({
map:flowMap
}));
helper.position.set(12,1.05,0);
helper.rotation.x=-Math.PI/2;
scene.add(helper);
helper.visible=false;
}
var setting;
function initGui(){
setting={
axesVisible:false,
color:"#ffffff",
scale:2,
flowX:1,
flowY:1,
helper:false,
}
var gui=new dat.GUI();
gui.add(setting,"axesVisible").onChange(function(e){
axes.visible=e;
});
//水的属性设置
var waterProperty=gui.addFolder("water1");
waterProperty.addColor(setting,"color").onChange(function(e){
water1.material.uniforms['color'].value.set(e);
});
waterProperty.add(setting,"scale",1,10).onChange(function(e){
water1.material.uniforms['config'].value.w=e;
});
waterProperty.add(setting,"flowX",-1,1).onChange(function(e){
water1.material.uniforms['flowDirection'].value.x=e;
water1.material.uniforms['flowDirection'].value.normalize();//归一化
});
waterProperty.add(setting,"flowY",-1,1).onChange(function(e){
water1.material.uniforms['flowDirection'].value.y=e;
water1.material.uniforms['flowDirection'].value.normalize();
});
waterProperty.open();
var waterPro2=gui.addFolder("water2");
waterPro2.add(setting,"helper").name("show flowMap").onChange(function(e){
helper.visible=e;
});
waterPro2.addColor(setting,"color").onChange(function(e){
water2.material.uniforms['color'].value.set(e);
});
waterPro2.add(setting,"scale",1,10).onChange(function(e){
water2.material.uniforms['config'].value.w=e;
});
waterPro2.open();
}
function onWindowResize(){
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
}
var clock=new THREE.Clock();
function render(){
var delta=clock.getDelta();
torusKnot.rotation.x+=delta;
torusKnot.rotation.y+=delta*0.5;
renderer.render(scene,camera);
}
function animate(){
render();
controls.update();
stats.update();
window.onresize=onWindowResize();
requestAnimationFrame(animate);
}
function threeStart(){
init();
initModel();
initGui();
animate();
}
threeStart();
</script>
</body>
</html>