A couple of nice shaders

This code will let you switch between the shaders using parameters. On the iPad 1, it gives you a rugby ball when model=1, while on an iPad3 it makes no difference at all.

--# SphereShader
sphereShader = {
vertexShader = [[

uniform mat4 modelViewProjection;

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

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
    vTexCoord = texCoord;
    gl_Position = modelViewProjection * position;


fragmentShader = [[

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);
  if (r > 1.0) discard; 

  vec2 uv;
  float t = (h + sqrt(r - r*h + h))/(r+h);
   if (model==0.0) {
      // texture coordinates according to Ignatz
      float f = 0.5*(1.0-sqrt(1.0-r))/r;
      uv.x = mod( fraction+p.x*f + time , 1.0 );
      uv.y = mod( fraction+p.y*f + time , 1.0 );
      vec4 c  = texture2D( texture, uv );
    else {
      // texture coordinates according to Andrew   
      float phi = 1.-acos(t*p.y)/3.1415;
      float theta = atan((1.-t)*height,t*p.x) / (2.*3.1415) + time ;
      uv.x = mod( theta , 1.0 );
      uv.y = mod( phi , 1.0 );

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

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

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



--# Main
-- sphere shader 2

-- by andrew stacey
function setup()
    img0=readImage("Cargo Bot:Codea Icon") --select your image here <<<<<
    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.shader.light = vec3(1,1,0):normalize()
    light_azimuth = 0
    light_zenith = 0
    local reset_light = function()
        m.shader.light = vec3(
            * math.sin(math.rad(light_zenith)),
            * math.sin(math.rad(light_zenith))
    local setModel = function() m.shader.model = model 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.shader.model = model

Thanks for this example @ignatz.
I think what generate the problem is the atan(a,b) function. Why are there 2 argument to atan by the way? I assume it is a particularity to open GL, but it screws the ipad1…

@Jmv38 @Ignatz I could mess with both of you and say it worked OK on my iPad 1, but I got the same results.

iPad 3 here, model 1 and model 0 seem to change for me, 1 doesn’t make it an ellipse but spins a different way. Nothing else.


@Jmv38 There is one argument to the float atan(a), you’re looking at it wrong.

@SkyTheCoder but what is the , between height and t for, then?

atan can take either one or two arguments in OpenGL - it’s overloaded. If two arguments then it behaves like atan2, if one then atan.

(In short, atan can’t distinguish between (x,y) and (-x,-y) but atan2 can.)

Those with an iPad one, try commenting out the discard line. Is the rectangle a square or a rectangle?

I can’t really tell from the videos. Is the ellipse a squashed circle or a clipped one?

Sides are squashed together, same height as before

Image is not clipped

@Andrew_Stacey If I comment out the discard line on my iPad 1, I don’t see any image for model 0 or 1.

@Ignatz that’s really strange. I’ve no ideas. Try deleting lines or replacing them with simpler lines until you get the full square/circle again.

@Andrew_Stacey - I played around a bit, but I don’t understand the formulae, so it’s hit and miss. The line with atan seems to be doing the squashing, I think.

I wonder if it’s anything to do with retina, because it seems to be about 50% squashed, and that’s the only difference I can think of between iPad 1 and 3.

@Ignatz So if you put something like float theta = time; instead of the atan line then you get things the right size?

(I’ll try on my iPad2 to see if that shows the same behaviour.)

That change gives me a blank screen

But I wouldn’t worry about fixing it. It’s not like this is a crucial piece of code or anything.

@Ignatz No, but it’s a puzzle.

Does it really give you a blank screen? Even after letting it run for a few seconds? That definitely shouldn’t happen! (It’s blank initially because the edge of the image is black but once it gets beyond the edge it should show fine.) Are you updating the shader in the Codea code or in the shader lab? I’d do the latter to ensure that there are no syntax errors.

What about float theta = .5;?

@Andrew_Stacey, see video below. I used my new iPad to film my iPad 1, so please excuse the shakiness.

NB I meant to write theta=time instead of theta=0, but it gives the same blank screen as theta=0.5


Just weird. I’ll check on my iPad2 this evening.

Checked the iPad 2 and it works the same as on the iPad 4, so it’s not a non-retina issue.

I’ve read somewhere ios5.1 had incomplete implementation of open gl support. I think. This could be the reason?