1
votes

I building a simple Framework for OpenGL UI's for MonoTouch. I set up everything and also succeeded rendering 3D Models, but a simple 2D texture object fails. The texture has a size of 256x256 so it's not to large and its power of two.

Here is some rendering code( Note: I did remove the existing, and working code ):

// Render the gui objects ( flat )
Projection = Matrix4x4.Orthographic(0, WindowProperties.Width, WindowProperties.Height, 0);
View = new Matrix4x4();
GL.Disable(All.CullFace);
GL.Disable(All.DepthTest);
_Stage.RenderGui();

Stage:

public void RenderGui ()
{
    Draw(this);
    // Renders every child control, all of them call "DrawImage" when rendering something
}


public void DrawImage (Control caller, ITexture2D texture, PointF position, SizeF size)
{
    PointF gposition = caller.GlobalPosition; // Resulting position is 0,0 in my tests
    gposition.X += position.X;
    gposition.Y += position.Y;

    // Renders the ui model, this is done by using a existing ( and working vertex buffer )
    // The shader gets some parameters ( this works too in 3d space )   
    _UIModel.Render(new RenderParameters() {
        Model = Matrix4x4.Scale(size.Width, size.Height, 1) * Matrix4x4.Translation(gposition.X, gposition.Y, 0),
       TextureParameters = new TextureParameter[] {
           new TextureParameter("texture", texture)
       }
    });
}

The model is using a vector2 for positions, no other attributes are given to the shader.

The shader below should render the texture.

Vertex:

attribute vec2 position;        
uniform mat4 modelViewMatrix;           
varying mediump vec2 textureCoordinates;

void main()
{
    gl_Position = modelViewMatrix * vec4(position.xy, -3.0, 1.0);
    textureCoordinates = position;
}

Fragment:

varying mediump vec2 textureCoordinates;
uniform sampler2D texture;          

void main()
{
    gl_FragColor = texture2D(texture, textureCoordinates) + vec4(0.5, 0.5, 0.5, 0.5);
}

I found out that the drawing issue is caused by the shader. This line produces a GL_INVALID_OPERATION( It works with other shaders ):

GL.UniformMatrix4(uni.Location, 1, false, (parameters.Model * _Device.View * _Device.Projection).ToArray());

EDIT:

It turns out that the shader uniform locations changed( Yes i'm wondering about this too, because the initialization happens when the shader is completly initialized. I changed it, and now everything works.

As mentioned in the other thread the texture is wrong, but this is another issue ( OpenGL ES 2.0 / MonoTouch: Texture is colorized red )

The shader initialization with the GL.GetUniformLocation problem mentioned above:

[... Compile shaders ...]
// Attach vertex shader to program.
GL.AttachShader (_Program, vertexShader);

// Attach fragment shader to program.
GL.AttachShader (_Program, pixelShader);        

// Bind attribute locations
for (int i = 0; i < _VertexAttributeList.Length; i++) {
    ShaderAttribute attribute = _VertexAttributeList [i];
    GL.BindAttribLocation (_Program, i, attribute.Name);
}

// Link program
if (!LinkProgram (_Program)) {
    GL.DeleteShader (vertexShader);
    GL.DeleteShader (pixelShader);
    GL.DeleteProgram (_Program);

    throw new Exception ("Shader could not be linked");
}

// Get uniform locations
for (int i = 0; i < _UniformList.Length; i++) {
    ShaderUniform uniform = _UniformList [i];
    uniform.Location = GL.GetUniformLocation (_Program, uniform.Name);
    Console.WriteLine ("Uniform: {0} Location: {1}", uniform.Name, uniform.Location);
}

// Detach shaders
GL.DetachShader (_Program, vertexShader);
GL.DetachShader (_Program, pixelShader);

GL.DeleteShader (vertexShader);
GL.DeleteShader (pixelShader);

// Shader is initialized add it to the device
_Device.AddResource (this);
2

2 Answers

3
votes

I don't know what Matrix4x4.Orthographic uses as near-far range, but if it's something simple like [-1,1], the object may just be out of the near-far-interval, since you set its z value explicitly to -3.0 in the vertex shader (and neither the scale nor the translation of the model matrix will change that). Try to use a z of 0.0 instead. Why is it -3, anyway?

EDIT: So if GL.UniformMatrix4 function throws a GL_INVALID_OPERATION, it seems you didn't retrieve the corresponding unfiorm location successfully. So the code where you do this might also help to find the issue.

Or it may also be that you call GL.UniformMatrix4 before the corresponding shader program is used. Keep in mind that uniforms can only be set once the program is active (GL.UseProgram or something similar was called with the shader program).

And by the way, you're multiplying the matrices in the wrong order, anyway (given your shader and matrix setting code). If it really works this way for other renderings, then you either were just lucky or you have some severe conceptual and mathemtical inconsistency in your matrix library.

0
votes

It turns out that the shader uniforms change at a unknown time. Everything is created and initialized when i ask OpenGL ES for the uniform location, so it must be a bug in OpenGL.

Calling GL.GetUniformLocation(..) each time i set the shader uniforms solves the problem.