# A couple of nice shaders

One is an embossing shader, but the other is really nice. It creates a fake spherical effect, wrapping a square texture around the “sphere”. This video demonstrates. There is no sphere, only a mesh with a rect and a square texture.

Code for both is here: https://gist.github.com/dermotbalson/6886024

i love shaders, nice work @ignatz

As always @Ignatz, amazing!

This is great! Thanks!

Very nice! Here’s a small variant:

I find that when I look at the very edge of the sphere then I’m not sure that what I see is what I expect to see. But I need to look at the mathematics of the code to understand whether that’s real or not.

You say in the code that “fraction” changes the behaviour. I don’t see that. It looks to me like an initial offset.

The `mod` function is overloaded and works fine on `vec2`s. So you can condense a few lines in the shader:

``````vec2 uv = mod((fraction + time)*vec2(1.,1.) + p*f,vec2(1.,1.));
vec4 c = texture2D( texture, uv);
``````

(You could condense it even further if you wanted to.)

I realise I implicitly took credit for that code. Actually I found both of them on the net, and tweaked them a little.

Thanks, @Andrew_Stacey, for your suggestion - actually, in the original code, here

there was no fraction factor (ie effectively it was 1), and the image was tiling itself several times. I found that by introducing this factor, I was able to get what looks like a single instance of the image to wrap around.

So it was all guesswork…

@Jmv38 - lol, no chance of adding those things! Not until I understand the code, anyway…

@Ignatz I had a look at that link. I can see, sort of, what was irritating me about the spherical one: it approximates the sphere by a parabaloid and the approximation is bad at the edge of the sphere.

I don’t think it’s that difficult to do correctly so here’s the fragment shader for a true sphere. You need to set the `height` parameter of the shader; it’s the height of the eye above the sphere. I used 15.

``````precision highp float;

uniform lowp sampler2D texture;
uniform float time;
uniform float fraction;
uniform float height;
highp float h = height*height;
highp float rh = h/(h-1.);
highp float sqrh = sqrt(rh);

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying vec4 vPosition;

void main()
{
vec2 p = (-1.0 + 2.0 * vTexCoord)/sqrh;
float r = dot(p,p);
float t = (h + sqrt(r - r*h + h))/(r+h);
float phi = 1.-acos(t*p.y)/3.1415;
float theta = mod(atan(
(1.-t)*height,
t*p.x)/(2.*3.1415)+time,1.);
vec4 c = texture2D( texture, vec2(theta,phi));
gl_FragColor = vec4(c.xyz, 1.0);
}
``````

@Andrew_Stacey - thank you, as always!

Now with added lightness (@Jmv38, this one’s for you).

``````function setup()
m=mesh()
mm=math.min(img0.width,img0.height)
img=img0:copy(1,1,mm,mm)            --make it square
m:addRect(WIDTH/2,HEIGHT/2,400,400)   --add a rectangle to our mesh, the size you want (square)
m.texture=img
m:setColors(color(255))
light_azimuth = 0
light_zenith = 0
local reset_light = function()
)
end
parameter.integer("light_azimuth",-180,180,0,reset_light)
parameter.integer("light_zenith",0,180,0,reset_light)
end

function draw()
background(40, 40, 50)
m.shader.time=ElapsedTime/10 --vary the time speed to change the rotation speed of the sphere
m:draw()
end

uniform mat4 modelViewProjection;

attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
vColor=color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}

]],

precision highp float;

uniform lowp sampler2D texture;
uniform float time;
uniform float height;
uniform vec3 light;

highp float h = height*height;
highp float rh = h/(h-1.);
highp float sqrh = sqrt(rh);

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying vec4 vPosition;

void main()
{
vec2 p = (-1.0 + 2.0 * vTexCoord)/sqrh;
float r = dot(p,p);
float t = (h + sqrt(r - r*h + h))/(r+h);
float l = max(0.,t*dot(p.xy,light.xy) + (1.-t)*height*light.z);
float phi = 1.-acos(t*p.y)/3.1415;
float theta = mod(atan(
(1.-t)*height,
t*p.x)/(2.*3.1415)+time,1.);
vec4 c = texture2D( texture, vec2(theta,phi));
gl_FragColor = vec4(l*c.xyz, 1.0);
}

]]}
``````

Nice work! It needs a good image to show it off properly

Who said we would never see the dark side of the moon! These shaders are great!

Thank you very much @andrew_stacey, this is great. However i get this on my ipad1: Any idea of what is going on? The oval shape? The column in the middle? How can i correct this? With ignatz first code the sphere was correct…

Obviously, your iPad is not perfectly flat. Have you dropped it? Obviously, your iPad is not perfectly flat. Have you dropped it? @Ignatz Haha… Double post.

@Jmv38 Maybe you’re in portrait mode and need to be in landscape mode?

No, I think his iPad is in ellipse mode…

Lol!
Seriously, any idea? I am in lanscape, and i just copied/pasted the code, no change.

@Dave1707 you have the same ipad as me: could you try andrew’s program to check if you have the same pb as me? Thanks in advance!

@Jmv38 - yep, I tried it on an iPad1 and got the same result you did

I think it will take a mathematician to explain why!

Thanks for checking. Meanwhile i did my homework. Here are the result:
You can see in this video i have made one shader with the 2 options. I am very unfamiliar with shaders, so i have not been able to switch from onse shader to the other from a running program. Actually, i have, but the result is crazy, so i quit. So, to go from one shader to the other you must comment one of the 2 lines as shown in the video. I really dont understand what is going on. Can anyone help please?
I have the feeling the root cause is around how the shaders are implemented in ios5.1 or ipad1 or codea support of these, or a tricky combination of the three…
Here is the code:

``````

uniform mat4 modelViewProjection;

attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
vColor=color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}

]],

precision highp float;

uniform float model;

uniform lowp sampler2D texture;
uniform float time;
uniform float fraction;
uniform float height;
uniform vec3 light;

highp float h = height*height;
highp float rh = h/(h-1.);
highp float sqrh = sqrt(rh);

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying vec4 vPosition;

void main()
{

vec2 p = (-1.0 + 2.0 * vTexCoord)/sqrh;
float r = dot(p,p);

vec2 uv;
vec2 uv1;
vec2 uv2;

// texture coordinates according to Ignatz
float f = 0.5*(1.0-sqrt(1.0-r))/r;
uv1.x = mod( fraction+p.x*f + time , 1.0 );
uv1.y = mod( fraction+p.y*f + time , 1.0 );

// texture coordinates according to Andrew
float t = (h + sqrt(r - r*h + h))/(r+h);
float phi = 1.-acos(t*p.y)/3.1415;
float theta = atan((1.-t)*height,t*p.x) / (2.*3.1415) + time ;
uv2.x = mod( theta , 1.0 );
uv2.y = mod( phi , 1.0 );

// choose uv according to model
// attempt to do it from parameter, but the result is crazy and i dont understand why.
//  if (model<0.5)  uv = uv1;
//  if (model>0.5)  uv = uv2;
// choose manually your model by commenting one of the lines:
//uv = uv1;
uv = uv2;

// set the texture coordinates
vec4 c  = texture2D( texture, uv );

float l = max(0.,t*dot(p.xy,light.xy) + (1.-t)*height*light.z);

gl_FragColor = vec4(l*c.xyz, 1.0);

}

]]}

--# Main

-- by andrew stacey
function setup()
m=mesh()
mm=math.min(img0.width,img0.height)
img=img0:copy(1,1,mm,mm)            --make it square
m:addRect(WIDTH/2,HEIGHT/2,400,400)   --add a rectangle to our mesh, the size you want (square)
m.texture=img
m:setColors(color(255))
light_azimuth = 0
light_zenith = 0
local reset_light = function()
)
end
model = 0.0
local setModel = function() m.shader.model = model*1.0 end
parameter.integer("model",0,1,0,setModel)
parameter.integer("light_azimuth",-180,180,-34,reset_light)
parameter.integer("light_zenith",0,180,90,reset_light)
end

function draw()
background(40, 40, 50)
m.shader.time=ElapsedTime/10 --vary the time speed to change the rotation speed of the sphere
m:draw()
end

``````