Water/Mirrored surface in WebGL using ThreeJS

15,577

Solution 1

Check this three.js example out.

Out of the box and ready to use, straight from the source:

water = new THREE.Water( renderer, camera, scene, {
    textureWidth: 512, 
    textureHeight: 512,
    waterNormals: waterNormals,
    alpha:  1.0,
    sunDirection: light.position.clone().normalize(),
    sunColor: 0xffffff,
    waterColor: 0x001e0f,
    distortionScale: 50.0,
} );


mirrorMesh = new THREE.Mesh(
    new THREE.PlaneBufferGeometry( parameters.width * 500, parameters.height * 500 ),
    water.material
);

mirrorMesh.add( water );
mirrorMesh.rotation.x = - Math.PI * 0.5;
scene.add( mirrorMesh );

Seems to look like an ocean to me :)

Solution 2

You can see this presentation http://29a.ch/slides/2012/webglwater/

and this fiddle may be useful for you jsfiddle.net/ahmedadel/44tjE

Share:
15,577
user1214513
Author by

user1214513

Updated on July 31, 2022

Comments

  • user1214513
    user1214513 almost 2 years

    I am trying to make a water surface in WebGL using Three.js. I think I will start with just a mirror as I think I know how to add displacement to make basic ripple effects.

    This is what I know: Reflection is usually made by rendering a vertically (y-axis) flipped scene on a FBO using the water plane as a culling plane. Then this FBO is used as a texture for the water plane. Using a displacement map (or a noise texture) the image can be displaced and a water effect achieved.

    The problems: First off, I can't find a way to flip the scene in ThreeJS. In OpenGL you can just use glScale and put -1 for Y, but I don't think this is possible in WebGL (or GLES on which it is based). At least I found no such thing in ThreeJS. There is a scale parameter for geometry, but there is none for scene. One solution could be changing the .matrixWorldInverse in Camera, but I am not sure how I could do that. Any ideas?

    The second hurdle is clipping/culling plane. Again, the old way was using glClipPlane, but its not supported even in the newest OpenGL standard as far as I know, so its also not in WebGL. I read somewhere that you can do that in vertex shader, but in ThreeJS I only know how to add shaders as materials and I need this during the render to FBO.

    And third, rendering the FBO to water plane with correct texture coordinates, so I think basically projecting from the camera position.

    I can't find any more information on this on the internet. There are very few WebGL reflection examples and the only thing close was here, and it used some "Oblique View Frustum" method for culling. Is this really the best way to do it nowadays? Instead of one function we now must code this ourselves in software (to be ran on CPU not GPU)? Also cube reflections provided in ThreeJS of course is not applicable for a plane, so yes, I tried those. If someone can make as easy as possible example on how to do this I would greatly appreciate it.

  • user1214513
    user1214513 about 11 years
    The fiddle only shows the displacement part (refraction), while all my quests were about scaling, clipping and rendering to plane. The presentation looks promising though, so I will look into it. Thank you.
  • user1214513
    user1214513 about 11 years
    And scene is THREE.Object3D.prototype, so it actually has scale method as well. But it doesn't seem to work. I think that is because camera is part of the scene as well, and when I do scene.scale.y the camera is also flipped, so in the end I don't see any difference (though light positions stay the same). I tried camera.scale.y = -1 and it did flip everything, though again, light stayed at top and the angle was not right. I think I have to go trough all scene.__objects and set scale.y=-1 manually. Then do that again after rendering to FBO. Could you post an example on how you managed to do it?
  • user1214513
    user1214513 about 11 years
    I still can't get this to work. I have tried: 'scene.matrix.makeScale(1, -1, 1);' and 'scene.matrixWorld.makeScale(1, -1, 1); scene.matrixWorld.matrixWorldNeedsUpdate = true;' and they all just seem to flip only some objects, but not all. All I want is to flip the whole scene like I could do in GL: 'glPushMatrix (); glScalef (1., -1., 1.); //Render glPopAttrib();' And this seems very complicated in Three.js. Maybe I could get the gl api use it there directly. Or just find which of the 100 matrices in scene object I need to scale.
  • Griffin M.
    Griffin M. over 7 years
    What is the variable waterNormals?
  • Wilt
    Wilt over 7 years
    @GriffinM. I don't know, from the example it seems to be a texture loading this image. Not sure what the purpose of this waternormals texture exactly is. You could ask a separate question on StackOverflow on this...
  • Gage Hendy Ya Boy
    Gage Hendy Ya Boy over 6 years
    @Wilt THREE.Water seems to have been removed, is there another way to accomplish this?
  • Wilt
    Wilt over 6 years
    @GageHendyYaBoy there are three examples available on the three.js website: water, ocean and ocean2. The classes for these examples are not part of the library but can be found here in /examples/js/objects