Author Topic: Water Shader Textures  (Read 12437 times)

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #15 on: January 11, 2011, 08:28:00 pm »
I quote myself:
Remember that the shader needs a light source to work with. Without one, everything will be black.
Your shader doesn't use a GL light source, mine does. If you don't provide one, everything will be black. Anyway, if it works fine with that one, all is well. I'm sure it's better suited for water then my simple bump mapping shader is. Any screen shots of how the result looks like (just out of interest)?
« Last Edit: January 11, 2011, 08:34:37 pm by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #16 on: January 11, 2011, 08:41:26 pm »
Mine isn't the best texture or normal map, but here you go:

« Last Edit: January 12, 2011, 07:42:33 pm by AGP »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #17 on: January 11, 2011, 08:44:58 pm »
PS: We're working on a better-scaled background! :- )

EDIT: Also, I read the comment about the light this morning. Although there were already two lights (one for the moon and one over Superman), I added four more (one to each side of Superman) to the scene and your shader still looked black.
« Last Edit: January 11, 2011, 09:12:44 pm by AGP »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #18 on: January 11, 2011, 09:25:14 pm »
Well, no idea then. Maybe the angle between the light and the surface makes it appear black...who knows. It doesn't really matter now that you seem to have something that works reasonable well.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #19 on: January 12, 2011, 04:34:52 pm »
But I'm nowhere near satisfied with this water yet. Any chance I could persuade you to try a water shader? I've tried several and the one I think could work well goes black like yours did. It's important to note that this is happening on three very different computers, with distinctly different video cards.

EDIT: Also, the first shader I made work yesterday produced the odd effect of rotating the texture along with the camera. I'm not sure if it was intentional of if I wasn't doing something I was supposed to be doing.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #20 on: January 12, 2011, 05:30:32 pm »
Then why not post-pone that shader stuff and go with something easier? A simple sin/cos-based vertex controller effect with a base water texture and and environment map on top might look good enough and will work everywhere.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #21 on: January 12, 2011, 06:17:14 pm »
Because I'd like to tackle the shader issue at some point and now is as good as any. Truth be told, if the ReflectionHelper would start working I'd be very happy. But also, aren't shaders a lot faster than a simple vertex controller?
« Last Edit: January 12, 2011, 06:19:54 pm by AGP »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #22 on: January 12, 2011, 06:29:12 pm »
Yes, they are faster...but that doesn't mean that not using them is a problem. The reflection helper might not very well suited for your application anyway. It works on planar surfaces. If you can tilt the camera, the reflection will go crazy.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #23 on: January 12, 2011, 06:32:57 pm »
Cheapo water effect (20min of work, so don't expect too much) without shaders. It skips updating the normals in the controller and calculates them every frame, which is costly. But i didn't have the time to figure out how to do it in the controller.
Textures can be found in http://www.jpct.net/download/misc

Code: [Select]
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.GenericVertexController;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;

public class CheapWater {

private World world;

private FrameBuffer buffer;

private Object3D water;

private WaterController wc = null;

public static void main(String[] args) throws Exception {
new CheapWater().loop();
}

public CheapWater() throws Exception {

Config.glForceEnvMapToSecondStage = true;
Config.glUseVBO = true;

world = new World();
world.setAmbientLight(100, 100, 100);

TextureManager tm = TextureManager.getInstance();

tm.addTexture("water", new Texture("water3.jpg"));
tm.addTexture("envmap", new Texture("environment.jpg"));

water = Primitives.getPlane(20, 3);

TextureInfo ti = new TextureInfo(tm.getTextureID("water"));
ti.add(tm.getTextureID("envmap"), TextureInfo.MODE_MODULATE);

wc = new WaterController();

water.setTexture(ti);
water.setEnvmapped(Object3D.ENVMAP_ENABLED);
water.rotateX((float) Math.PI / 2f);
water.rotateMesh();
water.clearRotation();
water.build();
water.compile(true);
water.setTransparency(2);
water.getMesh().setVertexController(wc, false);
water.setTextureMatrix(new Matrix());
world.addObject(water);

world.getCamera().setPosition(0, -50, -50);
world.getCamera().lookAt(water.getTransformedCenter());

Light light=new Light(world);
light.setAttenuation(-1);
light.setIntensity(255, 255, 255);
light.setPosition(new SimpleVector(100,-50,-20));
}

private void loop() throws Exception {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_GL_AA_2X);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

while (!org.lwjgl.opengl.Display.isCloseRequested()) {
buffer.clear(java.awt.Color.BLUE);

wc.update(0.5f);

water.getMesh().applyVertexController();
water.touch();
water.calcNormals(); // This isn't good...it should actually be done in the VertexController...
water.getTextureMatrix().translate(0.0015f, -0.0015f, 0);

world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
Thread.sleep(10);
}
buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
buffer.dispose();
System.exit(0);
}

private static class WaterController extends GenericVertexController {

private static final long serialVersionUID = 1L;

private float degreeAdd = 0;

public void update(float inc) {
degreeAdd += inc;
}

public void apply() {
SimpleVector[] source = this.getSourceMesh();
SimpleVector[] dest = this.getDestinationMesh();

int end = source.length;

for (int i = 0; i < end; i++) {
SimpleVector s = source[i];
SimpleVector d = dest[i];
float sin = (float) Math.sin((((((degreeAdd + s.x + s.z)/10f) % 360))));
d.set(s.x, s.y + sin*2, s.z);

//@todo
// Update the normals here too. Formula?
}
}
}

}

« Last Edit: January 12, 2011, 06:35:51 pm by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #24 on: January 12, 2011, 06:40:19 pm »
Thanks a lot, I will try this out and report.

But I'd still like to make the shader thing work (that's the appeal to me!).
« Last Edit: January 12, 2011, 06:46:51 pm by AGP »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #25 on: January 12, 2011, 07:41:40 pm »
It's definately not fast, but I love that it moves like water on the shores. If it could be sped up, and you could solve the normals formula (to maybe look like it moves more three-dimensionally and less planar), I would have to find another excuse to play with shaders on jpct. :- )


Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #26 on: January 12, 2011, 09:24:30 pm »
Here's an improved version. It pre-calculated the normals in the controller based on a formula that i pulled out of my nose. With that change, performance is like this on my machine (Core2 Quad @3.2Ghz, AMD Radeon 5870):

1600 polygons/precalc normals: 4500fps
1600 polygons/real normals: 2500fps

10000 polygons/precalc normals: 2300fps
10000 polygons/real normals: 30fps

...so precalc normals should be fast enough IMHO.

Here's the code. You can now apply an additional scale that changes the waves' height as well as a damping factor that makes the waves narrow or wide.

Code: [Select]
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.GenericVertexController;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;

public class CheapWater {

private World world;

private FrameBuffer buffer;

private Object3D water;

private WaterController wc = null;

public static void main(String[] args) throws Exception {
new CheapWater().loop();
}

public CheapWater() throws Exception {

Config.glForceEnvMapToSecondStage = true;
Config.glUseVBO = true;
                Config.glDynamicBatchSize=4000;

world = new World();
world.setAmbientLight(100, 100, 100);

TextureManager tm = TextureManager.getInstance();

tm.addTexture("water", new Texture("water3.jpg"));
tm.addTexture("envmap", new Texture("environment2.jpg"));

water = Primitives.getPlane(40, 1.5f);

TextureInfo ti = new TextureInfo(tm.getTextureID("water"));
ti.add(tm.getTextureID("envmap"), TextureInfo.MODE_MODULATE);

water.setTexture(ti);
water.setEnvmapped(Object3D.ENVMAP_ENABLED);
water.rotateX((float) Math.PI / 2f);
water.rotateMesh();
water.clearRotation();
water.build();
water.compile(true);
water.setTransparency(2);
wc = new WaterController(water, 5, 10, false);
water.getMesh().setVertexController(wc, false);
world.addObject(water);

world.getCamera().setPosition(0, -50, -50);
world.getCamera().lookAt(water.getTransformedCenter());

Light light = new Light(world);
light.setAttenuation(-1);
light.setIntensity(255, 255, 255);
light.setPosition(new SimpleVector(100, -50, -20));
}

private void loop() throws Exception {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_GL_AA_2X);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

long s = System.nanoTime() / 1000000L;
long ss = System.currentTimeMillis();
int fps = 0;

while (!org.lwjgl.opengl.Display.isCloseRequested()) {
buffer.clear(java.awt.Color.BLUE);

long ticks = ((System.nanoTime() / 1000000L) - s) / 10;

if (ticks > 0) {
s = System.nanoTime() / 1000000L;
wc.update(0.5f * (float) ticks);
water.getMesh().applyVertexController();
}

world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
fps++;
if (System.currentTimeMillis() - ss >= 1000) {
System.out.println(fps + "fps");
fps = 0;
ss = System.currentTimeMillis();
}
}
buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
buffer.dispose();
System.exit(0);
}

private static class WaterController extends GenericVertexController {

private float scale = 0;

private float damping = 0;

private SimpleVector[] preCalcNormals = null;

private SimpleVector[] preCalcNormalsNeg = null;

private float[] lastHeight = null;

private static final long serialVersionUID = 1L;

private float degreeAdd = 0;

private Object3D water = null;

private float lastUpdate = 0;

private boolean realNormals = false;

public WaterController(Object3D water, float scale, float damping, boolean realNormals) {
this.scale = scale;
this.water = water;
this.realNormals = realNormals;
this.damping = damping;
water.setTextureMatrix(new Matrix());
}

/**
* This calculates some normals...these are rather fake and in no way
* comparable to real surface normals. But they should do the trick...
*/
public boolean setup() {
SimpleVector ax = new SimpleVector(-1, 0, 1).normalize();
preCalcNormals = new SimpleVector[(int) (100f * scale)];
preCalcNormalsNeg = new SimpleVector[(int) (100f * scale)];
int end = preCalcNormals.length;
for (int i = 0; i < end; i++) {
float height = -1f + (((float) i) / (end / 2f));
SimpleVector n = new SimpleVector(0, -1, 0);
SimpleVector n2 = new SimpleVector(0, -1, 0);
Matrix m = new Matrix();
Matrix m2 = new Matrix();
if (height <= 0) {
float val = (float) Math.sqrt((height + 1) * (Math.PI / 7f));
m.rotateAxis(ax, val);
m2.rotateAxis(ax, -val);
} else {
float val = (float) Math.sqrt((1 - height) * (Math.PI / 7f));
m.rotateAxis(ax, val);
m2.rotateAxis(ax, -val);
}
n.rotate(m);
n2.rotate(m);
preCalcNormals[i] = n;
preCalcNormalsNeg[i] = n2;
}

SimpleVector[] source = this.getSourceMesh();
lastHeight = new float[source.length];

for (int i = 0; i < source.length; i++) {
lastHeight[i] = 0;
}

return true;
}

public void update(float inc) {
degreeAdd += inc;
lastUpdate = inc;
}

public void apply() {
SimpleVector[] source = this.getSourceMesh();
SimpleVector[] dest = this.getDestinationMesh();

SimpleVector[] destNormals = this.getDestinationNormals();

int end = source.length;
int nEnd = preCalcNormals.length;

for (int i = 0; i < end; i++) {
SimpleVector s = source[i];
SimpleVector d = dest[i];
float sin = (float) Math.sin((degreeAdd + s.x + s.z) / damping);
d.set(s.x, s.y + sin * scale, s.z);

int iHeight = (int) ((sin + 1) * (nEnd / 2));

if (lastHeight[i] > sin) {
destNormals[i].set(preCalcNormalsNeg[iHeight]);
} else {
destNormals[i].set(preCalcNormals[iHeight]);
}

lastHeight[i] = sin;
}

water.touch();
if (realNormals) {
water.calcNormals();
}
float tr = lastUpdate / 333f;
water.getTextureMatrix().translate(tr, -tr, 0);
}
}

}

« Last Edit: January 12, 2011, 10:57:42 pm by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #27 on: January 12, 2011, 10:02:01 pm »
Setup() isn't being called. Where should it be?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Water Shader Textures
« Reply #28 on: January 12, 2011, 10:06:36 pm »
It's called by the engine, you don't have to call it yourself.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Water Shader Textures
« Reply #29 on: January 12, 2011, 10:11:12 pm »
Oh, I see that it's part of the IVertexController interface, sorry.

Is it defaulting to pre-calculated? And although the look on the shore is that of moving water, the water surface itself doesn't move (it's a smooth surface).