Why the example code of buffer always return error?

In the reference document(http://codea.io/reference/Shaders.html#buffer), there is a example, I want to try it, but it failed, and return error: “attempt to index a nil value( global ‘myAttribute’)"
At the same time, the uniform example code is ok. I checked it again and again,but can not find the reason.

I added 1 line to my vertex shader code:

attribute float myAttribute;

below is the example code:

-- Accessing a shader buffer
------------------------
-- Create a mesh
myMesh = mesh()

-- Assign a shader to myMesh
--  This shader has an attribute named 'myAttribute'
myMesh.shader = shader("Documents:MyShader")

-- Fetch the attribute array
myAttrBuffer = myMesh:buffer("myAttribute")

-- Resize our buffer
myAttrBuffer:resize(30)

-- Add some random numbers
for i = 1,30 do
    myAttrBuffer[i] = math.random(-50,50)
end

-- The shader will now use this data
--  when myMesh is drawn

Can’t see a problem, sorry

@Ignatz thanks for your response, the below is the whole code:

-- MagicMirror

-- ????????????????

-- Use this function to perform your initial setup
function setup()
    displayMode(FULLSCREEN)

    -- print("Hello World!")
    cameraSource(CAMERA_FRONT)
    --cameraSource(CAMERA_BACK)
    
    spriteMode(CORNER)
    
    
    img = image(100, 100)  
    
    m = mesh()
    local w, h =WIDTH, HEIGHT
    
    -- ????????????
    -- mesh ????
    m.vertices = {
        vec2(0,0), vec2(0,h), vec2(w,h),
        vec2(0,0), vec2(w,0), vec2(w,h),
    }
    -- ????????: ???? mesh ??????????
    m.texCoords = {
        vec2(0,0), vec2(0,1), vec2(1,1),
        vec2(0,0), vec2(1,0), vec2(1,1),
    }
    
    myColor = color(255, 255, 255, 255)
    myColorV = color(255, 0, 6, 255)
    m:setColors(myColor)
    
    
    
    m.texture = CAMERA
    m.shader = shader(mShader.vS,mShader.fS)
    --m.shader = shader("Documents:Matrix")
    
    m.shader.uniformVar = 120

    
    
    setContext(img)
    m:draw()
    setContext()
    
    print(m.shader.uniformVar)
    
    myAttrBuffer = m:buffer("myAttribute")
    myAttrBuffer:resize(30)
    
    for i = 1,6 do
        myAttribute[i] = math.random(-50,50)
    end
    
    
    print(m.size)
    --m:resize(10)
    
end

-- This function gets called once every frame
function draw()
    
    -- This sets a dark background color 
    background(0, 0, 0, 255)

    -- This sets the line thickness
    strokeWidth(5)

    
    
    resetMatrix()
    translate(0,HEIGHT)
    rotate(-90)
    scale(1,1.5,1)
    
    m:draw()
    
end



mShader = { vS = [[
//
// A basic vertex shader
//

// ?? Codea ?????, ???????????
uniform mat4 modelViewProjection;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;


// ?? Codea ???: ??? attribute ? uniform ?????? 
// position ??? mesh.vertices ??????????????, ?? [x, y, z, 1]
// color ??? mesh.colors ?????????, ?? [r, g, b, a]
// texCoord ??? mesh.texCoords ??????????????, ?? [x, y]
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute float myAttribute;


// ?? fragment ???
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    vColor = color;
    vTexCoord = texCoord;

    //myAttr = myAttr+vec2(1,1);
    
    gl_Position = modelViewProjection * position;
    //gl_Position = modelMatrix*viewMatrix*projectionMatrix * position;
    //gl_Position = modelMatrix*projectionMatrix * position;
    //gl_Position = viewMatrix*projectionMatrix * position;
    //gl_Position = projectionMatrix * viewMatrix* modelMatrix* position;
    
}
]],

fS = [[
//
// A basic fragment shader
//

precision highp float;

// ?? Codea ?????, ??? Codea ?? mesh.texture ????
uniform lowp sampler2D texture;

// ???????
uniform int uniformVar;


// ? vertex ????????
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;
    
    mediump float t = col.r + col.g + col.b;
    lowp float a = t / 3.0;
    lowp float a1 = a;
    
    //myAttr = myAttr+1;
    
    // ???????
    if(a1 < 0.33)  a = 0.0; 
    else if(a1>=0.33 && a1<0.66) a = 0.5; 
    else  a = 1.0;
    
    col.r = a;
    col.g = a;
    col.b = a;

    //gl_FragColor = vec4(0.15, 0.15, 0.15, a * a);
    //gl_FragColor = vec4(0.15, 0.15, 0.15, a);
    gl_FragColor = col;
}
]]
}

This is the error info:

You will kick yourself #-o

   for i = 1,6 do
        --myAttribute[i] = math.random(-50,50)
        myAttrBuffer[i] = math.random(-50,50)
    end

@Ignatz sorry for this low level mistake, I copy the demo code and comment the line , but the error still there:

    -- Fetch the attribute array
    myAttrBuffer = m:buffer("myAttribute")
    
    -- Resize our buffer 
    myAttrBuffer:resize(30)
    
    -- Add some random numbers
    for i = 1,30 do
        --myAttrBuffer[i] = math.random(-50,50)
    end

Why did you comment out the line

myAttrBuffer[i] = math.random(-50,50)

It should not be commented out

@Ignatz What I mean is that the result is the same–error. If I do not comment the line, the error will occur at “myAttrBuffer:resize(30)” , if I comment the line, the error will also occur at “myAttrBuffer:resize(30)”.

this is the whole code without comment:

-- MagicMirror

-- ????????????????

-- Use this function to perform your initial setup
function setup()
    displayMode(FULLSCREEN)

    -- print("Hello World!")
    cameraSource(CAMERA_FRONT)
    --cameraSource(CAMERA_BACK)
    
    spriteMode(CORNER)
    
    
    img = image(100, 100)  
    
    m = mesh()
    local w, h =WIDTH, HEIGHT
    
    -- ????????????
    -- mesh ????
    m.vertices = {
        vec2(0,0), vec2(0,h), vec2(w,h),
        vec2(0,0), vec2(w,0), vec2(w,h),
    }
    -- ????????: ???? mesh ??????????
    m.texCoords = {
        vec2(0,0), vec2(0,1), vec2(1,1),
        vec2(0,0), vec2(1,0), vec2(1,1),
    }
    
    myColor = color(255, 255, 255, 255)
    myColorV = color(255, 0, 6, 255)
    m:setColors(myColor)
    
    
    
    m.texture = CAMERA
    m.shader = shader(mShader.vS,mShader.fS)
    --m.shader = shader("Documents:Matrix")
    
    m.shader.uniformVar = 120

    setContext(img)
    m:draw()
    setContext()
    
    print(m.shader.uniformVar)
    
    
    -- Fetch the attribute array
    myAttrBuffer = m:buffer("myAttribute")
    
    -- Resize our buffer 
    myAttrBuffer:resize(30)
    
    -- Add some random numbers
    for i = 1,30 do
        myAttrBuffer[i] = math.random(-50,50)
    end
    
    print(m.size+100)
    
    --m:resize(10)
    
end

-- This function gets called once every frame
function draw()
    
    -- This sets a dark background color 
    background(0, 0, 0, 255)

    -- This sets the line thickness
    strokeWidth(5)

    resetMatrix()
    translate(0,HEIGHT)
    rotate(-90)
    scale(1,1.5,1)
    
    m:draw()
    
end


mShader = { vS = [[
//
// A basic vertex shader
//

// ?? Codea ?????, ???????????
uniform mat4 modelViewProjection;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;


// ?? Codea ???: ??? attribute ? uniform ?????? 
// position ??? mesh.vertices ??????????????, ?? [x, y, z, 1]
// color ??? mesh.colors ?????????, ?? [r, g, b, a]
// texCoord ??? mesh.texCoords ??????????????, ?? [x, y]
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute float myAttribute;


// ?? fragment ???
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    vColor = color;
    vTexCoord = texCoord;

    //myAttr = myAttr+vec2(1,1);
    
    gl_Position = modelViewProjection * position;
    //gl_Position = modelMatrix*viewMatrix*projectionMatrix * position;
    //gl_Position = modelMatrix*projectionMatrix * position;
    //gl_Position = viewMatrix*projectionMatrix * position;
    //gl_Position = projectionMatrix * viewMatrix* modelMatrix* position;
    
}
]],

fS = [[
//
// A basic fragment shader
//

precision highp float;

// ?? Codea ?????, ??? Codea ?? mesh.texture ????
uniform lowp sampler2D texture;

// ???????
uniform int uniformVar;


// ? vertex ????????
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;
    
    mediump float t = col.r + col.g + col.b;
    lowp float a = t / 3.0;
    lowp float a1 = a;
    
    //myAttr = myAttr+1;
    
    // ???????
    if(a1 < 0.33)  a = 0.0; 
    else if(a1>=0.33 && a1<0.66) a = 0.5; 
    else  a = 1.0;
    
    col.r = a;
    col.g = a;
    col.b = a;

    //gl_FragColor = vec4(0.15, 0.15, 0.15, a * a);
    //gl_FragColor = vec4(0.15, 0.15, 0.15, a);
    gl_FragColor = col;
}
]]
}

@binaryblues I’m not sure what you’re doing with myAttrBuffer, but if I comment out its 3 uses, the code runs without problems. It show a black/grey image of me from the camera.

@binaryblues

The problem is this. I’ve run into this issue many times with shaders. An interesting thing about custom attribute buffers and uniform arrays in shaders is, you have to actually use them in the shader for them to exist. Just declaring them in the shader preamble is not enough. So, for instance, if in the vertex shader you change vColor = color; to vColor = color * myAttribute; the error disappears.

I ran into the exact same thing. I was thinking “always code iteratively” so you gradually add an attribute buffer one piece at a time. But until the attribute is being used for something in the main void loop, it’s as if it doesn’t exist, and you’ll get errors like this.

This also applies to uniform arrays, but not to any other kind of variable.

If only Codea Talk had an “upvote this answer” button… B-) ~O)

@dave1707 @yojimbo2000 thanks!
I understand it! We must use a var in the function, otherwise it will set nil.

Add “vColor* myAttribute;” into the main of vertex shader, then it will get the value! I will write it in my Codea FAQ :slight_smile:

Thanks guys! It took me two days, yesterday, in my dream, I am thinking about it…