Codea 1.5 (Beta 8)

.@tnlogy

I’ve uploaded my shaders to a public repository. You can browse the files directly or check them out using VCS (the format is bazaar, but other VCS’s can read them). They’re at: http://www.math.ntnu.no/~stacey/code/CodeaShaders/.

Of course, you also need the code to use them. However, that’ll take a bit more care before publishing because I currently have a single “test” project where all my “little” stuff starts, but I also use it for testing others’ code so I can’t really just export the whole lot.

Thanks for sharing! A small test that uses buffers would be great, because my attempts just looked crazy :). I tried to create normals with v1:cross(v2):normalize() for two points in a triangle, but the result was a bit wierd. Haven’t put enough time on it to figure out what is wrong, so a working example would help out. :slight_smile:

function createNormals(m)
    local normals = m:buffer("normal")
    normals:resize(#m.vertices)

    for i = 1,#m.vertices,3 do
        local v1 = m:vertex(i)-m:vertex(i+1)
        local v2 = m:vertex(i)-m:vertex(i+2)
        local n = v1:cross(v2):normalize()
        
        normals[math.floor(i/3)+1] = n
        normals[math.floor(i/3)+2] = n
        normals[math.floor(i/3)+3] = n
    end 
end

.@tnlogy my shadow code (credits 99% to Andrew Stacey):
The program code (nor is a table of vec3 that are the normals at each vertice location. There is no universal way to compute it, it depends for instance if your object is mooth or has faces. I can post my code for it if you want)

    ms.shader = shader("Documents:Shadow")
    ms.shader.light = vec3(1,1,0):normalize()
    local tnor = ms:buffer("normal")
    tnor:resize(#nor)
    for k,v in ipairs(nor) do 
        tnor[k] = v
    end

Vertex shader

//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;
uniform vec3 light;
//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp float vShade;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = vec2(texCoord.x,1.-texCoord.y);

    if (light != vec3(0.,0.,0.)) {
        lowp vec4 nor = modelViewProjection * vec4(normal,0);
        vShade = (dot(nor.xyz,light)+0.2)/1.2;
        if (vShade >1.0) {vShade=1.0;}
        if (vShade <0.2) {vShade=0.2;}
    } else {
        vShade = 1.;
    }
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}

fragment shader

//
// A basic fragment shader
//

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;
varying lowp float vShade;

void main()
{
    //Sample the texture at the interpolated coordinate
    lowp vec4 col;
 //   col = texture2D( texture, vTexCoord );
    col = vColor;

    col.rgb *= vShade;
    //Set the output color to the texture color
    gl_FragColor = col;
}

Here is my class i use to compute normals


Vec3sort = class()

function Vec3sort:init()
end

function Vec3sort:blend(ms,color1)
    local i=1
    local newColors = {}
    local r,g,b,a,c,c1
    while i<=#(ms.colors) do
        c = ms:color(i)
        c1 = color1[i]
        c.r = c.r * c1.r / 255
        c.g = c.g * c1.g / 255
        c.b = c.b * c1.b / 255
        
        newColors[i] = c
--print(c1)
        i = i + 1
    end
    return newColors
end

function Vec3sort:shade(t,lightDir,min,max,slope)
    local center, amplitude = (max+min)/2, (max-min)/2
    local i=1
    local a
    local newColors = {}
    local steepness = slope or 2
    while i<=#t do
        -- shadow
        a = - t[i]:dot(lightDir) * steepness
        if a>1 then a =1 elseif a<-1 then a=-1 end
        a = center + amplitude*a
        -- set color
        a = color(a,a,a,alpha)
        newColors[i] = a
        i = i + 1
    end
    return newColors
end

function Vec3sort:verticeNormals(t)
    local out = {}
    local s = Vec3sort:intSort(t)
    local nf = Vec3sort:faceNormals(t)
    local i=1
    local imax = #s
    local n,v,j,i0,i1,k,p
    -- init loop
    j=s[i].x ; v = nf[ s[i].y ] ; n=1 ; i0=i ; i1=i
    i = i + 1
    while i<= imax do
        if s[i].x == j then    -- this is the same vector
            -- accumulate
            v = v + nf[ s[i].y ]
            n = n + 1
            i1 = i
        end
        if s[i].x ~= j or i==imax then    -- this is the same vector
            -- compute normal
            v = v/n
            v = v:normalize()
            -- save last normal
            for k=i0,i1 do
                out[s[k].y] = v
            end
            -- init loop
            j=s[i].x ; v = nf[ s[i].y ] ; n=1 ; i0=i ; i1=i
        end
        i = i + 1
    end
    --[[
    -- verification
    for i=1,#t do
        v = out[i]
        print(v.x.." "..v.y.." "..v.z)
    end
    ]]
    return out
end

local clock = os.clock

function Vec3sort:faceNormals(t)
    local out = {}
    local imax = math.floor(#t/3)
    local i=1
    local v1,v2,v3,a,b,normal
    local t1 = clock()+1/40
    while i<= imax do
        -- get triangle vertices
        v1 = t[1 + i*3-3]
        v2 = t[1 + i*3-2]
        v3 = t[1 + i*3-1]
        -- compute normal vector
        a = v1-v2
        b = v1-v3
        normal = a:cross(b):normalize()
        -- compute normal vector orientation
        a = (v1+v2+v3)/3
        b = a:dot(normal)
        if b>0 then b=1 else  b=-1 end
        normal = normal * b
        -- write result
        out[1 + i*3-3] = normal
        out[1 + i*3-2] = normal
        out[1 + i*3-1] = normal
        i = i + 1
    end
    return out
end

local floor = math.floor

function Vec3sort:intSort(t)
    -- t is a table ov vec3
    local s = {}
    local i
    for i=1,#t do
        s[i] = vec4(t[i].x,t[i].y,t[i].z,i)
    end
    local function compVec3(a,b)
        local out = false
        if floor(a[1])<floor(b[1]) then out = true
        elseif floor(a[1])==floor(b[1]) then
            if floor(a[2])<floor(b[2]) then out = true
            elseif floor(a[2])==floor(b[2]) then
                if floor(a[3])<floor(b[3]) then out = true end
            end
        end
        return out
    end
    table.sort(s,compVec3)
    local v
    --[[
    for i=1,#s do
        v = s[i]
        print(v.x.." "..v.y.." "..v.z.." "..v.w)
    end
    ]]
    local out={}
    local n = 1
    out[1] = vec2(n,s[1].w)
    for i=2,#s do
        if compVec3(s[i-1],s[i]) then n = n + 1 end
        out[i] = vec2(n,s[i].w)
    end
    --[[
    for i=1,#s do
        v = out[i]
        print(v.x.." "..v.y)
    end
    ]]
    return out
end



function Vec3sort:sort(t)
    -- t is a table ov vec3
    local s = {}
    local i
    for i=1,#t do
        s[i] = vec4(t[i].x,t[i].y,t[i].z,i)
    end
    local function compVec3(a,b)
        local out = false
        if a[1]<b[1] then out = true
        elseif a[1]==b[1] then
            if a[2]<b[2] then out = true
            elseif a[2]==b[2] then
                if a[3]<b[3] then out = true end
            end
        end
        return out
    end
    table.sort(s,compVec3)
    local v
    --[[
    for i=1,#s do
        v = s[i]
        print(v.x.." "..v.y.." "..v.z.." "..v.w)
    end
    ]]
    local out={}
    local n = 1
    out[1] = vec2(n,s[1].w)
    for i=2,#s do
        if compVec3(s[i-1],s[i]) then n = n + 1 end
        out[i] = vec2(n,s[i].w)
    end
    --[[
    for i=1,#s do
        v = out[i]
        print(v.x.." "..v.y)
    end
    ]]
    return out
end

In the setup i create a ‘normals’ object to which i pass the mesh vertice table to compute the normals (smooth normals here). You can also use faceNormals() if you want not smooth shadows

normals = Vec3sort()
nor = normals:verticeNormals(obj.ms.vertices)

Hope that helps you…

Thanks for the help. It seems like my calculation of normals was incorrect. I now instead tried loading an OBJ-file with some ugly code, and then it works fine. Nice :slight_smile:

https://docs.google.com/open?id=0B8DhnQgjRtV2d2RENHBSVk5wLTg