Shader Problem

Started by AGP, January 22, 2014, 04:58:53 PM

Previous topic - Next topic

AGP

What does

float n = v;


mean when v is a vec3? It doesn't compile on jpct and I don't really think it should. Yet this is supposedly a finished a functional shader.

EgonOlsen

The gpu driver compiles the shader, not the engine. This isn't supposed to work if v is a vec3.

AGP

You'd be surprised how many shaders online have these kinds of dumb errors (yet they have videos showing them working).

I would really like a proper glsl tutorial or teacher, but all I can ever find that's reasonable are hlsl and cg stuff.

AGP

Here's a direct question: how do we make your CheapWater into a glsl shader? Or to start with a smaller question: is that in the vertex shader (I would think so) or in the fragment one?


class CheapWater {
     private World world;
     private FrameBuffer buffer;
     protected Object3D water;
     private WaterController wc = null;
     private Time waterTime;

     public CheapWater(World world, FrameBuffer buffer) throws Exception {
Config.glForceEnvMapToSecondStage = true;
Config.glUseVBO = true;
this.world = world;
this.buffer = buffer;
waterTime = new Time();

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

water = Primitives.getPlane(40, 1000);

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

wc = new WaterController(water, 15, 5, false);

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());
water.translate(0, -56f, 0);//WHY IS -18 DOWN INSTEAD OF UP?
     }

     public void perform() throws Exception {
wc.update((float)waterTime.deltaTime());
water.getMesh().applyVertexController();
     }

     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 waveScale, float damping, boolean realNormals) {
     this.scale = waveScale;
     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[] destination = this.getDestinationMesh();
     SimpleVector[] destNormals = this.getDestinationNormals();

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

     for (int i = 0; i < end; i++) {
SimpleVector sourceVector = source[i];
SimpleVector destinationVector = destination[i];
float sin = (float) Math.sin((degreeAdd + sourceVector.x + sourceVector.z) / damping);
destinationVector.set(sourceVector.x, sourceVector.y + sin * scale, sourceVector.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);
}
     }
}

EgonOlsen

That's the vertex one. You would have to do something similar to what the controller does in the shader (i.e. some sin() calculations to the object's vertices).

AGP

How do I fill a uniform vec2? Do I need something like setStaticUniform(String, awt.Point)?

Also, is there a way in which to fill a samplerCube so that it has ANY kind of usable value (even if it's just one of the images in a SKyBox)?

AGP

This, by the way, is how simple the fragment shader at hand is:


uniform samplerCube skyDome;
uniform sampler2D water;

uniform vec4 waterColour;

varying mat3 tanSpace;

void main(void) {
   vec3 ref = ((gl_TexCoord[1] + texture2D(water, gl_TexCoord[0].xy)) * 0.5).xyz;
   ref *= 2.0;
   ref -= vec3(1.0, 1.0, 1.0);
   
   ref = tanSpace * ref;
 
   vec4 sample = waterColour + ( (textureCube(skyDome, ref) - waterColour)  * (dot(ref,vec3(0.0,0.0,1.0)) * waterColour.w));
   
   gl_FragColor = vec4( sample.xyz, 0.825);
}

EgonOlsen

Ok, but that's just to make the water reflect the skycube...

AGP

You answered neither of my questions. :- )

The most important of them (since I think that I should just be able to replace samplerCube with sampler2D) is how do I pass a vec2.

AGP

#24
Figured it out. I was being thick: shader.setStaticUniform("windDir", new float[]{10, 0}) does it.

The shader now looks like this:


uniform sampler2D skyDome;//samplerCube
uniform sampler2D water;

uniform vec4 waterColour;

varying mat3 tanSpace;

void main(void) {
   vec3 ref = ((gl_TexCoord[1] + texture2D(water, gl_TexCoord[0].xy)) * 0.5).xyz;
   ref *= 2.0;
   ref -= vec3(1.0, 1.0, 1.0);
   
   ref = tanSpace * ref;
 
   vec4 sample = waterColour + ( (texture(skyDome, vec2(ref.x, ref.y)) - waterColour) * (dot(ref,vec3(0.0,0.0,1.0)) * waterColour.w));//waterColour+((textureCube(skyDome, ref)...
   
   gl_FragColor = vec4( sample.xyz, 0.825);
}


I hope that I'm right with the texture(sample2D...) thing.

EgonOlsen

Oh, sorry...i haven't noticed your actual questions... :-[

Yes, a float[2] is the way to go. Replacing the cube map with a single texture might look good enough.

AGP

It's not compiling, though. I'm getting the following message:

Quote
Fragment shader failed to compile with the following errors:
ERROR: 0:1: error(#132) Syntax error: '<' parse error
ERROR: error(#273) 1 compilation errors.  No code generated


Vertex shader failed to compile with the following errors:
ERROR: 0:1: error(#132) Syntax error: 'Fragment' parse error
ERROR: error(#273) 1 compilation errors.  No code generated


[ Mon Jan 27 16:09:01 EST 2014 ] - ERROR: Vertex and Fragment shader(s) were not
successfully compiled before glLinkProgram() was called.  Link failed.

Tangent handle not found (tangents needed: false)!
Shader compiled!

The problem with these error messages is that I never exactly know where the problem is. I noticed that the method I was using didn't really exist (even reference documentation on glsl is bizarrely wanting) and replaced it now with texture2D. The following is the fragment shader, now. Would you like to have a look at the vertex shader, just in case?


uniform sampler2D skyDome;//samplerCube
uniform sampler2D water;

uniform vec4 waterColour;

varying mat3 tanSpace;

void main(void) {
   vec3 ref = ((gl_TexCoord[1] + texture2D(water, gl_TexCoord[0].xy)) * 0.5).xyz;
   ref *= 2.0;
   ref -= vec3(1.0, 1.0, 1.0);

   ref = tanSpace * ref;

   vec4 sample = waterColour + ( (texture2D(skyDome, vec2(ref.x, ref.y)) - waterColour) * (dot(ref,vec3(0.0,0.0,1.0)) * waterColour.w));

   gl_FragColor = vec4( sample.xyz, 0.825);
}

EgonOlsen

And that thing compiles now? Or does it still have problems? The error messages are generated by the driver. Depending on the vendor of your graphics card, they are more or less useful.

AGP

I think it should, but it isn't. I guess I'll try it right now on another computer and report back here.

AGP

It works, I was being stupid. But it's not perfect yet. Even though the first line of the vertex shader is attribute vec4 tangent, jpct tells me

Quote
Tangent handle not found (tangents needed: true)!

Also, it's in the wrong place, and I suspect it's because I didn't fill a uniform vec4 vViewPosition variable. The following is the short vertexshader code. Please help me find how to fill vViewPosition (I don't suppose it's just the cameraPosition because of that pesky fourth value). Is it, perhaps, a 2x2 Matrix?


attribute vec4 tangent;
uniform float fTime0_X;
uniform float waveHeight;
uniform vec2 windDir;
uniform float roughness;

uniform vec4 vViewPosition;

varying mat3 tanSpace;

void main(void) {
   float height = sin( 1.0 * (gl_Vertex.x + (windDir.x * fTime0_X)));
   height += 1.0;
   height = pow( max(0.0, height), roughness);
   
   float height2 = sin( 0.01 * (gl_Vertex.y + (windDir.y * fTime0_X)));
   height2 += 1.0;
   height2 = pow( max(0.0, height2), roughness);

   
   vec4 pos = gl_Vertex;
   pos.z = waveHeight * ((height + height2) / 2.0);
   
   gl_Position = gl_ModelViewProjectionMatrix * pos.xzyw;
   
   vec4 ref = normalize(reflect( (vViewPosition - pos.xzyw), vec4(0.0, 0.0, 1.0, 1.0)));
   ref += vec4(1.0,1.0,1.0,1.0);
   ref *= 0.5;
   
   gl_TexCoord[1] = ref;
   
   gl_TexCoord[0].xy = 4.0 * (gl_MultiTexCoord0.yx + vec2(0.0, fTime0_X * 0.01));
   
   //   Find Surface Normal
   vec3 binormal = normalize(vec3( cos(1.0 * (gl_Vertex.x + (windDir.x * fTime0_X))), 1.0, 0.0));
                         
   vec3 tangent = normalize(vec3( 0.0, 1.0, 0.01 * cos(0.01 * (gl_Vertex.y + (windDir.y * fTime0_X)))));
   vec3 normal = cross(binormal, tangent);
   normal += vec3(1.0,1.0,1.0);
   normal *= 0.5;
   
   tanSpace = mat3( vec3(1.0, 0.0, 0.0), normal, vec3(0.0, 0.0, 1.0)); 
}