diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water.frag b/engine/src/core-effects/Common/MatDefs/Water/Water.frag index 928ee2275..867c335b3 100644 --- a/engine/src/core-effects/Common/MatDefs/Water/Water.frag +++ b/engine/src/core-effects/Common/MatDefs/Water/Water.frag @@ -36,6 +36,10 @@ uniform float m_SunScale; uniform float m_WaveScale; uniform float m_UnderWaterFogDistance; uniform float m_CausticsIntensity; +#ifdef ENABLE_AREA +uniform vec3 m_Center; +uniform float m_Radius; +#endif vec2 scale = vec2(m_WaveScale, m_WaveScale); float refractionScale = m_WaveScale; @@ -231,15 +235,29 @@ void main(){ vec3 color = color2; vec3 position = getPosition(sceneDepth,texCoord); - float level = m_WaterHeight; // If we are underwater let's go to under water function if(level >= m_CameraPosition.y){ + #ifdef ENABLE_AREA + vec3 dist = m_CameraPosition-m_Center; + if(dot(dist,dist) >m_Radius){ + gl_FragColor = vec4(color2, 1.0); + return; + } + #endif gl_FragColor = underWater(); return ; } + #ifdef ENABLE_AREA + vec3 dist = position-m_Center; + if(dot(dist,dist) >m_Radius){ + gl_FragColor = vec4(color2, 1.0); + return; + } + #endif + //#ifndef ENABLE_RIPPLES // This optimization won't work on NVIDIA cards if ripples are enabled if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){ diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water.j3md b/engine/src/core-effects/Common/MatDefs/Water/Water.j3md index 3bef8a9f4..b09003a54 100644 --- a/engine/src/core-effects/Common/MatDefs/Water/Water.j3md +++ b/engine/src/core-effects/Common/MatDefs/Water/Water.j3md @@ -45,6 +45,9 @@ MaterialDef Advanced Water { Boolean UseCaustics Boolean UseRefraction + Float Radius + Vector3 Center + } Technique { @@ -64,6 +67,8 @@ MaterialDef Advanced Water { ENABLE_FOAM : UseFoam ENABLE_CAUSTICS : UseCaustics ENABLE_REFRACTION : UseRefraction + ENABLE_AREA : Center + } } @@ -81,7 +86,7 @@ MaterialDef Advanced Water { ENABLE_FOAM : UseFoam ENABLE_CAUSTICS : UseCaustics ENABLE_REFRACTION : UseRefraction - + ENABLE_AREA : Center } } } \ No newline at end of file diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water15.frag b/engine/src/core-effects/Common/MatDefs/Water/Water15.frag index 64cf280de..1acad4eb5 100644 --- a/engine/src/core-effects/Common/MatDefs/Water/Water15.frag +++ b/engine/src/core-effects/Common/MatDefs/Water/Water15.frag @@ -41,6 +41,11 @@ uniform float m_WaveScale; uniform float m_UnderWaterFogDistance; uniform float m_CausticsIntensity; +#ifdef ENABLE_AREA +uniform vec3 m_Center; +uniform float m_Radius; +#endif + vec2 scale = vec2(m_WaveScale, m_WaveScale); float refractionScale = m_WaveScale; @@ -122,7 +127,7 @@ vec4 underWater(int sampleNum){ float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r; vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb; - vec3 position = getPosition(sceneDepth, texCoord); + vec3 position = getPosition(sceneDepth, texCoord); float level = m_WaterHeight; vec3 eyeVec = position - m_CameraPosition; @@ -228,7 +233,12 @@ vec4 underWater(int sampleNum){ vec4 main_multiSample(int sampleNum){ // If we are underwater let's call the underwater function if(m_WaterHeight >= m_CameraPosition.y){ - + #ifdef ENABLE_AREA + vec2 dist = m_CameraPosition.xz-m_Center.xz; + if(dot(dist,dist) >m_Radius){ + return fetchTextureSample(m_Texture, texCoord, sampleNum); + } + #endif return underWater(sampleNum); } @@ -238,6 +248,13 @@ vec4 main_multiSample(int sampleNum){ vec3 color = color2; vec3 position = getPosition(sceneDepth, texCoord); + #ifdef ENABLE_AREA + vec2 dist = position.xz-m_Center.xz; + if(dot(dist,dist) >m_Radius){ + return vec4(color2, 1.0); + } + #endif + float level = m_WaterHeight; float isAtFarPlane = step(0.99998, sceneDepth); diff --git a/engine/src/core-effects/com/jme3/water/WaterFilter.java b/engine/src/core-effects/com/jme3/water/WaterFilter.java index e91810cea..d4cb8b410 100644 --- a/engine/src/core-effects/com/jme3/water/WaterFilter.java +++ b/engine/src/core-effects/com/jme3/water/WaterFilter.java @@ -115,6 +115,9 @@ public class WaterFilter extends Filter { private float underWaterFogDistance = 120; private boolean useCaustics = true; private float causticsIntensity = 0.5f; + //positional attributes + private Vector3f center; + private float radius; /** * Create a Water Filter @@ -207,7 +210,7 @@ public class WaterFilter extends Filter { } private DirectionalLight findLight(Node node) { - for (Light light : node.getWorldLightList()) { + for (Light light : node.getWorldLightList()) { if (light instanceof DirectionalLight) { return (DirectionalLight) light; } @@ -294,6 +297,10 @@ public class WaterFilter extends Filter { material.setFloat("FoamIntensity", foamIntensity); material.setFloat("UnderWaterFogDistance", underWaterFogDistance); material.setFloat("CausticsIntensity", causticsIntensity); + if (center != null) { + material.setVector3("Center", center); + material.setFloat("Radius", radius * radius); + } } @@ -1047,4 +1054,39 @@ public class WaterFilter extends Filter { material.setFloat("CausticsIntensity", causticsIntensity); } } + + public Vector3f getCenter() { + return center; + } + + /** + * Set the center of the effect. + * By default the water will extent to the entire scene. + * By setting a center and a radius you can restrain it to a portion of the scene. + * @param center the center of the effect + */ + public void setCenter(Vector3f center) { + this.center = center; + if (material != null) { + material.setVector3("Center", center); + } + } + + public float getRadius() { + return radius; + + } + + /** + * Set the radius of the effect. + * By default the water will extent to the entire scene. + * By setting a center and a radius you can restrain it to a portion of the scene. + * @param radius the radius of the effect + */ + public void setRadius(float radius) { + this.radius = radius; + if (material != null) { + material.setFloat("Radius", radius * radius); + } + } } diff --git a/engine/src/test/jme3test/water/TestMultiPostWater.java b/engine/src/test/jme3test/water/TestMultiPostWater.java new file mode 100644 index 000000000..5296da0cb --- /dev/null +++ b/engine/src/test/jme3test/water/TestMultiPostWater.java @@ -0,0 +1,197 @@ +package jme3test.water; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioNode; +import com.jme3.audio.LowPassFilter; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.DepthOfFieldFilter; +import com.jme3.post.filters.LightScatteringFilter; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.Texture2D; +import com.jme3.util.SkyFactory; +import com.jme3.water.WaterFilter; +import java.util.ArrayList; +import java.util.List; + +/** + * test + * @author normenhansen + */ +public class TestMultiPostWater extends SimpleApplication { + + private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f, 5.896916f); + private WaterFilter water; + TerrainQuad terrain; + Material matRock; + AudioNode waves; + LowPassFilter underWaterAudioFilter = new LowPassFilter(0.5f, 0.1f); + LowPassFilter underWaterReverbFilter = new LowPassFilter(0.5f, 0.1f); + LowPassFilter aboveWaterAudioFilter = new LowPassFilter(1, 1); + + public static void main(String[] args) { + TestMultiPostWater app = new TestMultiPostWater(); + app.setSettings(new AppSettings(true)); + app.start(); + } + + @Override + public void simpleInitApp() { + +// setDisplayFps(false); +// setDisplayStatView(false); + + Node mainScene = new Node("Main Scene"); + rootNode.attachChild(mainScene); + + createTerrain(mainScene); + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(1.7f)); + mainScene.addLight(sun); + + flyCam.setMoveSpeed(100); + + //cam.setLocation(new Vector3f(-700, 100, 300)); + //cam.setRotation(new Quaternion().fromAngleAxis(0.5f, Vector3f.UNIT_Z)); + cam.setLocation(new Vector3f(-327.21957f, 61.6459f, 126.884346f)); + cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0})); + + + Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false); + sky.setLocalScale(350); + + mainScene.attachChild(sky); + cam.setFrustumFar(4000); + + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + + water = new WaterFilter(rootNode, lightDir); + water.setCenter(new Vector3f(9.628218f, -15.830074f, 199.23595f)); + water.setRadius(260); + water.setWaveScale(0.003f); + water.setMaxAmplitude(2f); + water.setFoamExistence(new Vector3f(1f, 4, 0.5f)); + water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg")); + water.setRefractionStrength(0.2f); + water.setWaterHeight(0.8f); + fpp.addFilter(water); + + WaterFilter water2 = new WaterFilter(rootNode, lightDir); + water2.setCenter(new Vector3f(-280.46027f, -24.971727f, -271.71976f)); + water2.setRadius(260); + water2.setWaterHeight(0.8f); + water2.setUseFoam(false); + water2.setUseRipples(false); + water2.setDeepWaterColor(ColorRGBA.Brown); + water2.setWaterColor(ColorRGBA.Brown.mult(2.0f)); + water2.setWaterTransparency(0.2f); + water2.setMaxAmplitude(0.3f); + water2.setWaveScale(0.008f); + water2.setSpeed(0.7f); + water2.setShoreHardness(1.0f); + water2.setRefractionConstant(0.2f); + water2.setShininess(0.3f); + water2.setSunScale(1.0f); + water2.setColorExtinction(new Vector3f(10.0f, 20.0f, 30.0f)); + fpp.addFilter(water2); + + + WaterFilter water3 = new WaterFilter(rootNode, lightDir); + water3.setCenter(new Vector3f(319.6663f, -18.367947f, -236.67674f)); + water3.setRadius(260); + water3.setWaterHeight(0.8f); + water3.setWaveScale(0.003f); + water3.setMaxAmplitude(2f); + water3.setFoamExistence(new Vector3f(1f, 4, 0.5f)); + water3.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg")); + water3.setRefractionStrength(0.2f); + water3.setWaterHeight(0.8f); + water3.setDeepWaterColor(ColorRGBA.Red); + water3.setWaterColor(ColorRGBA.Red.mult(2.0f)); + water3.setLightColor(ColorRGBA.Red); + fpp.addFilter(water3); + + viewPort.addProcessor(fpp); + + + } + + private void createTerrain(Node rootNode) { + matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/test.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + } catch (Exception e) { + e.printStackTrace(); + } + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(5, 5, 5)); + terrain.setLocalTranslation(new Vector3f(0, -30, 0)); + terrain.setLocked(false); // unlock it so we can edit the height + + terrain.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(terrain); + + } + + @Override + public void simpleUpdate(float tpf) { + + } +}