Reputation: 505
I´m using an expensive ocean shader (https://threejs.org/examples/webgl_shaders_ocean.html) that kills the user experience in older mobile devices (framerates drop from 60fps to 20fps). If a set a lower pixel ratio on the renderer (2 instead of 3), I can get double FPS (about 40fps). I´m also decreasing the canvas size programatically to 50%, later increasing it via CSS to fill the screen but with lower resolution.
These two actions are the best thing I can do right now to improve performance. But the cost is high, as I lose a lot of resolution not only in the ocean, but in all other models involved on the scene.
I´m looking for a way to render the expensive parts (like this shader material) on a low resolution, to restore it after rendering, I mean: define onBeforeRender on the ocean mesh plane so I can decrease the resolution to 1/3, for example. Then, after rendering the mesh, I could use onAfterRender to restore the original pixel ratio. I can decrease the resolution onBeforeRender without problem, but when I restore the original high-quality resolution onAfterRender, the screen goes black. These are my changes to https://threejs.org/examples/js/objects/Water.js
scope.onBeforeRender = function ( renderer, scene, camera ) {
(original onBeforeRender code)
renderer.setPixelRatio( 0.5 );
renderer.render( scene, mirrorCamera, renderTarget, false );
};
scope.onAfterRender = function ( renderer, scene, camera ) {
renderer.setPixelRatio( 2 );
};
I would like to know if this strategy is even right. Am I on the right path, at least? Here´s a basic JSFiddle to ilustrate the problem. There´s a method called "overrideFunctions()", which redefines Water.js onBeforeRender() to decrease pixel ratio before rendering the ocean. Then, we define "onAfterRenderer()" to restore the original quality so the models can be renderer on a high resolution.
https://jsfiddle.net/spacorum/y5398gLm
There are three lines commented. If you uncomment line 168 the global quality decreases to only 0.25dpi. This is ok, but if you then uncomment line 174, the models dissappear, the sky renders black... and the canvas is too small. I´ve also tried your suggestion renderer.clear() before rendering the ocean, but it doesn´t make any difference right now. So close..
EDIT 3: This is the closest I got to display what I need. An isolated, low-resolution version of the ocean, including the reflections. If I could manage to display the rest at normal resolution, that would be done: https://jsfiddle.net/spacorum/f63z2ceg/
EDIT 4: Just trying with a different technique: a main scene and a background scene. I´ve already tried something similar recently but I got stuck. In this test I managed to display a low-resolution version of the sea, rendering its background scene to a WebGLRenderTarget (using just 1/10 of the window size). It seems to improve, but I´m not sure if the calculations are the same and I´m just displaying it on a lower resolution. Anyway, following this way, I can´t get the sphere to look inside the sea (which is totally normal, I guess, as they are in different scenes, right?). Could renderer.clearDepth help here somehow? https://jsfiddle.net/spacorum/wbtcx9re/
EDIT 5: My latest approach, mixing EDIT3 and EDIT4. There are two scenes, ocean/sun added to the background/secondary scene and the sphere to the main one. Without doing any renderer.clear() and setting renderer.autoClear to false, I can render both scenes and the sphere "enters" the ocean added to the secondary scene, so far so good. (Of course there is no reflection yet, but I can fix that adding a copy of the sphere to the secondary scene). Then, I can decrease resolution before rendering secondary scene (line 166). But if I restore it later to have the sphere rendered on the original resolution (uncommenting line 173), the first scene dissappears and renders white.. I can´t understand why changing the resolution two times causes this, I may be forgetting to update something after it, but I can´t see it :/ https://jsfiddle.net/spacorum/o91se8fz/
Upvotes: 0
Views: 889
Reputation: 5016
Part of what makes that ocean rendering slow is the per frame rebuild of the environment cubemap. If you don't have objects close to the water constantly changing, you might get away with only updating the environment map once in a while, or once, when you switch skies or something.
Edit: just reread your questions.. and you may be on a correct path. You will need to control the frame buffer clearing yourself. Set renderer.autoClear = false, and call renderer.clear () before you render your reduced ocean. Otherwise three is clearing your buffer automatically after the ocean gets rendered. @spacorum
My initial answer may also still apply and allow you to renderer water at full res if you don't need full envmap rebuild per frame.
Upvotes: 1