Martinsh watershader sun...

Hi! I have a scene with realtime day/nigh cycle made by myself and martinsh watershader. I want there to be the sun speculars, but as the sun moves, it is rather impossible to type appropirate coordinates. So, what do I want to do is to get world position of sun light and apply it to this line:

vec3 sunPos = vec3(0.0,0.0,0.0); //sun position

However, I really don’t know how to do it, especially knowing that that is a fragment shader not a python line. Could someone help me out here?

I’ve had trouble passing anything but floats to a shader, so I’m not sure how you’d get it to work.
In theory you just have to declare it as a variable at the beginning of the script, but when I try to pass more complex stuff it doesn’t really work out.

You could split it in to x,y and z components and then assemble them in the shader.
Let me see…

In the object hosting the shader you need:

sun = [ob for ob in scene.objects if ob.get("sun")][0]
sun_position = sun.worldPosition.copy()
own['sun_x'] =position.x
own['sun_y'] =position.y
own['sun_z'] =position.z 

Then in the shader you need these extra lines:


(this part needs to be at the beginning of the shader somewhere)
uniform float sun_x;
uniform float sun_y;
uniform float sun_z;

(this part needs to be in the same place you found it)
vec3 sunPos = vec3(sun_x,sun_y,sun_z);

I don’t know if that works exactly, it’s just theory. Plus although I’ve worked quite a bit with 2d shaders I haven’t done anything with material shaders, so I couldn’t tell you much about how to get it to work if it doesn’t work as intended.

I’m sorry but most of the time all anyone can offer is some theoretical help. When it comes down to the actual implementation of those theories in to your game, you’re going to be on your own.

Doesn’t work. I even called shader.uniform1f(‘sun_x’, own[‘sun_x’]) etc, but did not solve anything…

Hi! A little tip: Instead of passing 3 uniforms to the shader, you can do like that:

lightPos = scene.objects[“Lamp”].worldPosition

shader.setUniform3f(‘sunPos’, lightPos[0], lightPos[1], lightPos[2])

(3f = 3 floats, 4f = 4 floats, 4i = 4 integers…)

in the shader:
uniform vec3 sunPos;

(uniforms have to be declared before void main())

Maybe there’s a simpler way…


The same happend with this method too. BTW, here is the code I am currently using(without theese methods):


##############################################################
# Water surface GLSL shader for BGE v1.0
# by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com)
##############################################################


from bge import logic as g
from bge import render as r
import bgl


cont = g.getCurrentController()
own = cont.owner


VertexShader = """


attribute vec4 Tangent;
varying vec4 fragPos;
varying vec3 T, B, N; //tangent binormal normal
varying vec3 viewPos;
varying vec2 texCoord;


void main() 
{
	vec3 pos = vec3(gl_Vertex);
	
	T   = Tangent.xyz;
	B   = cross(gl_Normal, Tangent.xyz);
	N   = gl_Normal; 


    texCoord = gl_MultiTexCoord0.xy;
    fragPos = ftransform();
    viewPos = pos - gl_ModelViewMatrixInverse[3].xyz;
    gl_Position = ftransform();
}


"""


FragmentShader = """


varying vec4 fragPos; //fragment coordinates
varying vec3 T, B, N; //tangent binormal normal
varying vec3 viewPos;
varying vec2 texCoord;


uniform float timer;
uniform sampler2D reflectionSampler,refractionSampler,normalSampler;


//----------------
//tweakables


vec2 windDir = vec2(-0.7, 0.1); //wind direction XY
float windSpeed = 0.75; //wind speed


float scale = 400.0; //overall wave scale


vec2 bigWaves = vec2(2.0, 3.0); //strength of big waves
vec2 midWaves = vec2(4.0, 2.0); //strength of middle sized waves
vec2 smallWaves = vec2(1.0, 0.5); //strength of small waves


vec3 waterColor = vec3(0.2,0.5,0.45); //color of the water
float waterDensity = 0.8; //water density (0.0-1.0)
    
float choppy = 0.35; //wave choppyness
float aberration = 0.001; //chromatic aberration amount
float bump = 1.0; //overall water surface bumpyness
float reflBump = 0.2; //reflection distortion amount
float refrBump = 0.2; //refraction distortion amount


vec3 sunPos = vec3(0.0,0.0,0.0); //sun position
float sunSpec = 100000.0; //Sun specular hardness


float scatterAmount = 5.0; //amount of sunlight scattering of waves
vec3 scatterColor = vec3(0.0,1.0,0.95);// color of the sunlight scattering
//----------------


vec3 tangentSpace(vec3 v)
{
	vec3 vec;
	vec.xy=v.xy;
	vec.z=sqrt(1.0-dot(vec.xy,vec.xy));
	vec.xyz= normalize(vec.x*T+vec.y*B+vec.z*N);
	return vec;
}


float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
{
    /* compute fresnel reflectance without explicitly computing
       the refracted direction */
    float c = abs(dot(Incoming, Normal));
    float g = eta * eta - 1.0 + c * c;
    float result;


    if(g > 0.0) {
        g = sqrt(g);
        float A =(g - c)/(g + c);
        float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0);
        result = 0.5 * A * A *(1.0 + B * B);
    }
    else
        result = 1.0;  /* TIR (no refracted component) */


    return result;
}


void main() {
   
    vec2 fragCoord = (fragPos.xy/fragPos.w)*0.5+0.5;
    fragCoord = clamp(fragCoord,0.002,0.998);


	//normal map
	vec2 nCoord = vec2(0.0); //normal coords
 
  	nCoord = texCoord * (scale * 0.015) + windDir * timer * (windSpeed*0.03);
	vec3 normal0 = 2.0 * texture2D(normalSampler, nCoord + vec2(-timer*0.005,-timer*0.01)).rgb - 1.0;
	nCoord = texCoord * (scale * 0.05) + windDir * timer * (windSpeed*0.05)-normal0.xy*choppy;
	vec3 normal1 = 2.0 * texture2D(normalSampler, nCoord + vec2(+timer*0.01,+timer*0.005)).rgb - 1.0;
 
 	nCoord = texCoord * (scale * 0.15) + windDir * timer * (windSpeed*0.1)-normal1.xy*choppy;
	vec3 normal2 = 2.0 * texture2D(normalSampler, nCoord + vec2(-timer*0.02,-timer*0.03)).rgb - 1.0;
	nCoord = texCoord * (scale * 0.5) + windDir * timer * (windSpeed*0.2)-normal2.xy*choppy;
	vec3 normal3 = 2.0 * texture2D(normalSampler, nCoord + vec2(+timer*0.03,+timer*0.02)).rgb - 1.0;
  
  	nCoord = texCoord * (scale* 1.5) + windDir * timer * (windSpeed*1.0)-normal3.xy*choppy;
	vec3 normal4 = 2.0 * texture2D(normalSampler, nCoord + vec2(-timer*0.06,+timer*0.08)).rgb - 1.0;  
    nCoord = texCoord * (scale * 5.0) + windDir * timer * (windSpeed*1.3)-normal4.xy*choppy;
    vec3 normal5 = 2.0 * texture2D(normalSampler, nCoord + vec2(+timer*0.08,-timer*0.06)).rgb - 1.0;


	
	
	vec3 normal = normalize(normal0 * bigWaves.x + normal1 * bigWaves.y +
                            normal2 * midWaves.x + normal3 * midWaves.y +
						    normal4 * smallWaves.x + normal5 * smallWaves.y);


    //normal.x = -normal.x; //in case you need to invert Red channel
    //normal.y = -normal.y; //in case you need to invert Green channel
   
    vec3 nVec = tangentSpace(normal*bump); //converting normals to tangent space    
    vec3 vVec = normalize(viewPos);
    vec3 lVec = normalize(sunPos);
    //normal for light scattering
	vec3 lNormal = normalize(normal0 * bigWaves.x + normal1 * bigWaves.y*0.5 +
                            normal2 * midWaves.x*0.3 + normal3 * midWaves.y*0.3 +
						    normal4 * smallWaves.x*0.2 + normal5 * smallWaves.y*0.2);
    lNormal = tangentSpace(lNormal*bump);
    
	vec3 lR = reflect(lVec, lNormal);
	float s = max(dot(lR, vVec)*2.0-1.2, 0.0);
    float lightScatter = clamp((max(dot(-lVec,lNormal)*0.75+0.25,0.0)*s)*scatterAmount,0.0,1.0);
    
    
    //fresnel term
    float ior = 1.33;
    float eta = max(ior, 0.00001);
    float fresnel = fresnel_dielectric(vVec,nVec,eta);
   
    //texture edge bleed removal
    float fade = 12.0;
    vec2 distortFade = vec2(0.0);
    distortFade.s = clamp(fragCoord.s*fade,0.0,1.0);
    distortFade.s -= clamp(1.0-(1.0-fragCoord.s)*fade,0.0,1.0);
    distortFade.t = clamp(fragCoord.t*fade,0.0,1.0);
    distortFade.t -= clamp(1.0-(1.0-fragCoord.t)*fade,0.0,1.0); 
    
    vec3 reflection = texture2D(reflectionSampler, fragCoord+(nVec.st*reflBump*distortFade)).rgb;
    
    vec3 luminosity = vec3(0.30, 0.59, 0.11);
	float reflectivity = pow(dot(luminosity, reflection.rgb*2.0),3.0);
    
    vec3 R = reflect(vVec, nVec);


    float specular = pow(max(dot(R, lVec), 0.0),sunSpec)*reflectivity;


    vec2 rcoord = reflect(vVec,nVec).st;
    vec3 refraction = vec3(0.0);
    
    refraction.r = texture2D(refractionSampler, (fragCoord-(nVec.st*refrBump*distortFade))*1.0).r;
    refraction.g = texture2D(refractionSampler, (fragCoord-(nVec.st*refrBump*distortFade))*1.0-(rcoord*aberration)).g;
    refraction.b = texture2D(refractionSampler, (fragCoord-(nVec.st*refrBump*distortFade))*1.0-(rcoord*aberration*2.0)).b;
    
    
    vec3 Transmittance = mix(refraction,refraction*waterColor,waterDensity);


    vec3 color = mix(mix(Transmittance,scatterColor,lightScatter),reflection,clamp(fresnel,0.0,1.0));
    
    gl_FragColor = vec4(color+specular,1.0);
 
}
"""


mesh = own.meshes[0]
for mat in mesh.materials:
	shader = mat.getShader()
	if shader != None:
		if not shader.isValid():
			shader.setSource(VertexShader, FragmentShader, 1)
		shader.setAttrib(g.SHD_TANGENT)
		shader.setSampler('reflectionSampler',0)
		shader.setSampler('refractionSampler',1)
		shader.setSampler('normalSampler',2)
		shader.setUniform1f('timer',own['timer'])
		#shader.setSampler('diffuseSampler',3)

vec3 sunPos = vec3(gl_ModelViewMatrixInverse*gl_LightSource[0].position);

In my version of watershader I’ve got this and it is working very well.

Could you share the .blend please? EDIT: Yes, araagon solution takes into account position of the camera and position of the light

Go to groups section, select Adris 3D development and go to Floated Away. Download the .blend from pasteall link;)

You should use Martinsh water shader v1.1 and slightly reduce water density. Works for me.

gl_LightSource[0].position - This will give you access to the position of the light. (it is deprecated in modern GLSL, but it works for blender implementation)

You will still have to do the appropriate transformations in space (object space is given, but not world space or view space), this returns the light vector to the object.

I martinsh’s shaders he transforms it into world space for the object by multiplying the model matrix by (model view matix inversed * light position).


     LightVec = vec3(ModelMatrix*(gl_ModelViewMatrixInverse*gl_LightSource[0].position));

You can find more information about gl_LightSource HERE

And where to put it?

You should take a look at Martinsh water shader v1.1, you’ll find the answer. Why don’t you use directly v1.1?

I use watersurface v1.1, but there isn’t answer. Take a look at code…

Sorry, water shader v0.99 line 92 vec3 sunPos = vec3(gl_ModelViewMatrixInverse*gl_LightSource[0].position);

http://www.pasteall.org/blend/35075

EDIT: I removed Hemi lights because gl_LightSource[0] was not the sun lamp, but in your file you can test with gl_LightSource[1], gl_LightSource[2] etc…

Put it inside your main() function, before you use it.

vec3 sunPos = vec3(ModelMatrix*(gl_ModelViewMatrixInverse*gl_LightSource[0].position));
/*or add it anywhere before you use the variable sunPos*/

You will need to bring in the model matrix thought, so add:

uniform mat4 ModelMatrix  //add to the top of the shader you are going to use it in (i.e. vertex or fragment)

 shader.setUniformDef('ModelMatrix', g.MODELMATRIX) //add to the bottom of the python script to call it


The same problem as before in this image- water becames strange(looks like so pixels get VERY huge or something like that)…

To have a nice specular effect, you should change the trajectory and the angle of your lamp (the sun have not to pass on zenith)

Not that… Take look at water- it disappears… I don’t care the look of specular as much as I care the water… I just want the specular to be always updated(like 0.99, 0.95 does when you grab that sun, but I don’t think I can figure out methods used there). Maybe the martinsh can arrive here himself?:smiley:

I sent you a PM about the underwater shader.

OK! That’s good, but actually, I got that, I just can’t implement that shader from 0.95 file(when I append all the cameras, ground and water plane, and press pe, the water doesn’t work:/)