# 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…

@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

``````