0
votes

there is a strange irregularity happening with my attempt of implementing the water2.js material onto a long surface that i can't explain. When I start my app, the water is rendered correctly (see screenshot 1).

->water showing correctly

The player moves forward quite a bit and suddenly the water turns into what you can see in screenshot 2.

->water not showing correctly

I can't explain why or how it happens as it starts out exactly as I want it. Anybody stumbled upon this before? How can I prevent it from turning into this solid mirror of my scene background?

DevBrowser: Chrome65
Threejs: r91

Example code

Using these three scripts from the three.js examples

<script src="js/objects/Reflector.js"></script>
<script src="js/objects/Refractor.js"></script>
<script src="js/objects/Water2.js"></script>

As seen here: https://threejs.org/examples/webgl_water.html

var splines = new THREE.CatmullRomCurve3( [
	new THREE.Vector3( -10, 0, 10 ),
	new THREE.Vector3( -5, 5, 5 ),
	new THREE.Vector3( 0, 0, 0 ),
	new THREE.Vector3( 5, -5, 5 ),
	new THREE.Vector3( 10, 0, 10 )
] );

//my curve is generated through waypoints so I inserted the standard curve as a stand in

    
var waterGeo = new THREE.TubeBufferGeometry(splines, 100, 4, 8, false);

var water = new THREE.Water( waterGeo, {
          color: 0xffffff,
          scale: 1,
          flowDirection: new THREE.Vector2( 1, 0 ),
          textureWidth: 1024,
          textureHeight: 1024
      } );

scene.add(water);
  

Example2
I recreated a similar effect, where after one camera turn the water turns black and will not go reflective anymore
working example here: http://staging.onewavestudios.com/waterexample/

    //skybox
        var path = "assets/skybox/";
        var format = ".jpg";
        var skymaterials = [
        path + "ft" + format,
        path + "bk" + format,
        path + "up" + format,
        path + "dn" + format,
        path + "rt" + format,
        path + "lf" + format
        ];
        var skybox = new THREE.CubeTextureLoader().load(skymaterials);
        skybox.format = THREE.RGBFormat;

    //scene setup
        var scene = new THREE.Scene();
        scene.background = skybox;
    
    //camera
    var camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000);
        camera.position.set( 20, 0, 25 );
		camera.lookAt( scene.position );
        scene.add(camera);

    //lights
        var ambientLight = new THREE.AmbientLight( 0xbbffff, 0.5 );
        scene.add(ambientLight);

    //objects
        //box1 - representation for the arms in my scene
        var geometry = new THREE.BoxGeometry( 10, 5, 5 );
        var material = new THREE.MeshLambertMaterial( { color: 0xbada55, envMap: skybox, reflectivity: 0.1 } );
        material.shadowSide = THREE.DoubleSide;
        material.side = THREE.DoubleSide;
		var cube = new THREE.Mesh( geometry, material );
        cube.position.y += 8;
        cube.position.z += 5;
		scene.add( cube );

        var splines = new THREE.CatmullRomCurve3([
            new THREE.Vector3(-10, 0, 10),
            new THREE.Vector3(-5, 5, 5),
            new THREE.Vector3(0, 0, 0),
            new THREE.Vector3(5, -5, 5),
            new THREE.Vector3(10, 0, 10)
        ]);
        //my original curve is generated through waypoints so I inserted the standard curve as a stand in

        //waterbody
        var waterGeo = new THREE.TubeBufferGeometry(splines, 100, 4, 8, false);
        var water = new THREE.Water(waterGeo, {
            color: 0xffffff,
            scale: 1,
            flowDirection: new THREE.Vector2(1, 0),
            textureWidth: 1024,
            textureHeight: 1024
        });
        scene.add(water);

        //waterslide - representation
        var material2 = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: skybox, reflectivity: 0.8 } );
        material2.shadowSide = THREE.DoubleSide;
        material2.side = THREE.DoubleSide;
        var container = new THREE.Mesh( waterGeo, material2 );
        container.position.y -= 5;
		scene.add( container );

    //renderer
        renderer = new THREE.WebGLRenderer();
		renderer.setPixelRatio( window.devicePixelRatio );
		renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );
        animate();

    //render
        function animate() {
                camera.rotation.z += 0.005;
				requestAnimationFrame( animate );
				render();
			}
			function render() {
				renderer.render( scene, camera );
			}
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>TubeWater Example</title>

    <style>
        body {
            margin: 0;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.js"></script>
<script src="https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/objects/Water2.js"></script>
<script src="https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/objects/Reflector.js"></script>
<script src="https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/objects/Refractor.js"></script>
<body>
</body>
</html>
1
Welcome to Stack Overflow! Please provide a Minimal, Complete, and Verifiable Example. In order to effectively help you, we need to reproduce the problem you described. - werner
Thanks for the quick reply @werner, I will see how I can single it out - onewaveadrian
I added some explanatory code - hope that helps in understanding what I'm doing. The camera follows along the same curve. - onewaveadrian
Do you have a link to the three.js demo for the water that you are using? Also, if you could post a working example of your code that would make it much easier to figure out. - manthrax
@manthrax I can't see how I can import the external water2 scripts required to get a demo running. Updated my original post with the dependencies & demo link, hope that helps to get the point across somewhat? - onewaveadrian

1 Answers

0
votes

I gotta validate what @Mugen87 is saying

THREE.Water is intended to be used with flat geometries. Same for THREE.Reflector and THREE.Refractor which are internally used

I'm getting the same/similar artifacts on a spherical object when applying the Refractor onto it. In my case (possibly yours as well) when the scene initiates and the camera's point of view doesn't have to calculate any objects behind the refracted geometry the shader looks fine, as soon as I move the camera while it has other geometry behind it, it repeats a black silhouette of the geometry and remains in that line of sight for the remainder of the scene. So what I'm thinking is the cause is when the rays that are calculating the refractions, if the ray hits the backface of the geometry from line of sight, then this artifact occurs. I'd like to point out I'm no expert and learning threejs myself so due to the likely chance that I haven't conveyed my input ideally I've created an illustration using your scenario.

Cause: Possible cause of artifact

So a possible solution for your situation might be as follows:

Possible Solution: Possible solution illustration

So by essentially creating a "semi" flat face for the shader to only have to calculate 1 side you might be able to achieve your desired effect, however be careful as to how much of a curve you place on the geometry carrying your "water" to avoid those backfaces being visible.

Also keep in mind that technically you aren't creating dynamic simulations here, so the geometry doesn't have to be fundamentally "correct". So By doing something like the following you're reducing the renderer's need to calculate something thats not really necessary. So you can just have your water geometry protruding the walls of your slide like so: (wasn't sure what the purple geometry is meant to be but looks like a slide to me lol)

Possible Geometry Setup