i'm quite new to opengl , and I'm trying to display a square with opengl es 2.0 with an orthographics projection ( on android using c++ and ndk ) , but all I get is a blank screen.
If i don't use the projection matrix I can get the square but it's stretched depending on surface's aspect ratio.
I'm building the matrix with the following code ( referring to https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml ):
GLfloat projMat[16];
void ortho(float left, float right, float top, float bottom, float near, float far){
float tx = ((right+left)/(right-left))*-1;
float ty = ((top+bottom)/(top-bottom))*-1;
float tz = ((far+near)/(far-near))*-1;
projMat[0] = 2/right-left;
projMat[1] = 0.0f;
projMat[2] = 0.0f;
projMat[3] = 0.0f;
projMat[4] = 0.0f;
projMat[5] = 2/top-bottom;
projMat[6] = 0.0f;
projMat[7] = 0.0f;
projMat[8] = 0.0f;
projMat[9] = 0.0f;
projMat[10] = -2/far-near;
projMat[11] = 0.0f;
projMat[12] = tx;
projMat[13] = ty;
projMat[14] = tz;
projMat[15] = 1.0f; }
And i call this function with : ortho(0.0,width,0.0, height,-1.0,1.0); , where width and height are surface's width and height.
My vertex shader :
attribute vec4 vPosition;
uniform mat4 projMatrix;
void main() {
gl_Position = projMatrix * vPosition;
};
My fragment shader :
precision mediump float;
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
And my draw function :
// 3D drawing
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(mProgram);
glUniformMatrix4fv(mPerspectivehandler, 1, GL_FALSE, projMat);
glEnableVertexAttribArray(mvPositionHandle);
glVertexAttribPointer(mvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, quadverts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(mvPositionHandle);
Do you know where's the mistake?
Edit :
I added parentheses as suggested, but it still doesn't work
GLfloat projMat[16];
void ortho(float left, float right, float top, float bottom, float near, float far){
float tx = ((right+left)/(right-left))*-1;
float ty = ((top+bottom)/(top-bottom))*-1;
float tz = ((far+near)/(far-near))*-1;
projMat[0] = 2/(right-left);
projMat[1] = 0.0f;
projMat[2] = 0.0f;
projMat[3] = 0.0f;
projMat[4] = 0.0f;
projMat[5] = 2/(top-bottom);
projMat[6] = 0.0f;
projMat[7] = 0.0f;
projMat[8] = 0.0f;
projMat[9] = 0.0f;
projMat[10] = -2/(far-near);
projMat[11] = 0.0f;
projMat[12] = tx;
projMat[13] = ty;
projMat[14] = tz;
projMat[15] = 1.0f; }
You're missing parentheses in the matrix calculation for the diagonal elements. They should be:
projMat[0] = 2.0f / (right - left);
projMat[5] = 2.0f / (top - bottom);
projMat[10] = -2.0f / (far - near);
It can be hard to debug issues where nothing is rendered. You should simplify until you can isolate what is going wrong.
You've declared vPosition as a vec4, but in your comment, your vertex position array only has 12 floats (3 per vertex). a vec4 needs 4 floats per vertex. this is also a problem here:
glVertexAttribPointer(mvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, quadverts);
You use 3 as the second parameter in the line above, but vec4 in your shader means use 4 here. Be sure that quadVerts holds 4 floats per vertex!
To debug, don't use a projection matrix - just render your geometry directly to clip-coordinates in your shader like so:
attribute vec4 vPosition;
uniform mat4 projMatrix;
void main() {
gl_Position = vPosition;
};
If the above shader renders (after you fix your vec4 problem), then you can start to debug your projection matrix.
Does your glClear() call actually take effect? try changing the color with glClearColor() and make sure the background color changes accordingly. If it doesn't, you might have set up your GL window incorrectly.
This question is 4 months old and I don't know if you still need an aswer.
I also had a lot of problems with orto projection matrices in OpenGL, but this works (for me):
result[0] = 2.0 / (right - left);
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = 2.0 / (top - bottom);
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = (1.0f / (near - far));
result[11] = 0.0;
result[12] = ((left + right) / (left - right));
result[13] = ((top + bottom) / (bottom - top));
result[14] = (near / (near - far));
result[15] = 1;
Related
How can we use the smoothstep function in renderscript to smoothen a mask image (already blurred using gaussian blur with kernel size 3 or 5) and make its edges smoother. I tried the following code in other frameworks and they worked as expected.
iOS shader code:-
let kernelStr = """
kernel vec4 myColor(__sample source) {
float maskValue = smoothstep(0.3, 0.5, source.r);
return vec4(maskValue,maskValue,maskValue,1.0);
}
"""
In opengl glsl fragment shader:-
float mask = btex.r;
float maskValue = smoothstep(0.3, 0.5, mask);
vec4 ress = vec4(maskValue,maskValue,maskValue,1.0);
RenderScript doesn't have a buit-in smoothstep function, so the simplest thing is to implement it yourself. Next the source ready to be used in your scripts:
static inline float smoothstep(float edge0, float edge1, float x)
{
float value = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return value * value * (3.0f - 2.0f * value);
}
Example of usage:
static inline float smoothstep(float edge0, float edge1, float x)
{
float value = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return value * value * (3.0f - 2.0f * value);
}
uchar4 RS_KERNEL root(uint32_t x, uint32_t y)
{
....
float mask = btex.r;
float maskValue = smoothstep(0.3f, 0.5f, mask);
float4 ress = (float4){maskValue, maskValue, maskValue, 1.0f};
....
}
And next a link about how smoothstep internally works, in case you have any other doubts:
smoothstep
Enjoy
I'm drawing a simple quad using gles2.0 in c++. If i draw it with a basic vertex shader there is no problem and this is the result
uniform mat4 u_mvp;
attribute vec4 a_Position;
void main(){
gl_Position = a_Position;
}
if i add MVP matrix
gl_Position = u_mvp * a_Position;
then there's nothing on screen.
This is the perspective matrix:
Matrix4 Matrix4::getPerspective(float angle, float ratio, float near, float far) {
// angle = 45; ratio = 1.438; near = 1; far = 100
Matrix4 matrix;
float top = (float)(near * Math::tangentDegrees(angle / 2.0f));
float bottom = -top;
float right = top * ratio;
float left = -right;
matrix.m[0] = (2 * near) / (right - left);
matrix.m[1] = 0.0f;
matrix.m[2] = (right + left) / (right - left);
matrix.m[3] = 0.0f;
matrix.m[4] = 0.0f;
matrix.m[5] = (2 * near) / (top - bottom);
matrix.m[6] = (top + bottom) / (top - bottom);
matrix.m[7] = 0.0f;
matrix.m[8] = 0.0f;
matrix.m[9] = 0.0f;
matrix.m[10] = -(far + near) / (far - near);
matrix.m[11] = -(2 * far * near) / (far - near);
matrix.m[12] = 0.0f;
matrix.m[13] = 0.0f;
matrix.m[14] = -1.0f;
matrix.m[15] = 0.0f;
return matrix;
}
The modelView matrix is obtained as follow:
modelView = translation * rotation * scale
mvp = perspective * modelView
Each element of this multiplication is obtaied following this example
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
and all of them are initalized at the identity matrix.
With this command i obtain the handle
transformUniformHandle = (GLuint)glGetUniformLocation(getProgramId(), "u_mvp");
With this command i set the mvp matrix in the shader (tried both GL_FALSE, GL_TRUE)
glUniformMatrix4fv(transformUniformHandle, 1, GL_TRUE, modelViewProjection.m);
OpenGL uses column-major storage for matrices, while your projection matrix is set up in row-major order. So you need to transpose the order of the matrix elements:
matrix.m[0] = (2 * near) / (right - left);
matrix.m[4] = 0.0f;
matrix.m[8] = (right + left) / (right - left);
matrix.m[12] = 0.0f;
matrix.m[1] = 0.0f;
matrix.m[5] = (2 * near) / (top - bottom);
matrix.m[9] = (top + bottom) / (top - bottom);
matrix.m[13] = 0.0f;
matrix.m[2] = 0.0f;
matrix.m[6] = 0.0f;
matrix.m[10] = -(far + near) / (far - near);
matrix.m[14] = -(2 * far * near) / (far - near);
matrix.m[3] = 0.0f;
matrix.m[7] = 0.0f;
matrix.m[11] = -1.0f;
matrix.m[15] = 0.0f;
You tried to transpose the matrix by passing GL_TRUE as the 3rd argument here:
glUniformMatrix4fv(transformUniformHandle, 1, GL_TRUE, modelViewProjection.m);
This is not supported in ES 2.0, the only valid argument value is GL_FALSE. You will see a GL_INVALID_VALUE error when you call glGetError() after this. Calling glGetError() should be routine if you have any problems with your OpenGL code.
You could keep the matrix row-major if you really wanted to, and change the shader code accordingly by multiplying the vector from the right:
gl_Position = a_Position * u_mvp;
But it's probably better to just use column-major order for your matrices.
Also, you're not showing your model-view matrix. You'll have to make sure that the view transformation translates the geometry in the negative z-direction, so that it's placed between the near and far planes of the projection transformation your are using.
Given you haven't shown your whole code, I can't be sure, but it could be that you haven't called glUseProgram before calling glUniformMatrix4fv. It might also be that your triangles are clipped out by the projection matrix. Make sure the points are within the clipping ranges. If that doesn't fix it you should get errors from glGetError. This page will explain its use: OpenGL error checking
I'm trying to figure out how to draw a centered circle using fragment shader. I don't quite understand how to accomplish this. This is what I got so far, but the result is a white screen.
I want to be able to draw it any size and be able to change the offsets as I like (move the circle around).
void main()
{
float radius = 10.0;
float viewWidth = 340.0;
float viewHeight = 500.0;
float offsetX = viewWidth / 2.0;
float offsetY = viewHeight / 2.0;
float factorX = viewWidth / ( 360.0 / 6.3 );
float factorY = viewHeight / ( 360.0 / 6.3 );
float angleX = gl_FragCoord.x / factorX;
float angleY = gl_FragCoord.y / factorY;
float x = offsetX + ( sin( angleX ) * radius );
float y = offsetY + ( cos( angleY ) * radius );
float c = x + y;
gl_FragColor = vec4( c, c, c, 1.0 );
}
Remember, this program runs separately for each individual fragment. Each one need only decide if it's in or out of the circle. No need to use sin and cos here, just measure the distance from the center of the viewport, to see if the fragment is in the circle.
Here's a disc, which is even simpler: http://glslsandbox.com/e#28997.0
uniform vec2 resolution;
void main( void ) {
vec2 position = ( gl_FragCoord.xy / resolution.xy ) - 0.5;
position.x *= resolution.x / resolution.y;
float circle = 1.0 - smoothstep(0.2, 0.21, length(position));
gl_FragColor = vec4( vec3( circle ), 1.0 );
}
And here's a circle, made by tweaking the disc a little: http://glslsandbox.com/e#28997.1
uniform vec2 resolution;
void main( void ) {
vec2 position = ( gl_FragCoord.xy / resolution.xy ) - 0.5;
position.x *= resolution.x / resolution.y;
float circle = 1.0 - smoothstep(0.003, 0.005, abs(length(position) - 0.2));
gl_FragColor = vec4( vec3( circle ), 1.0 );
}
I've just stated learning Opengl ES 2.0 in android and I run into a problem that i don't know how to solve.
I want to create a large plane field, I created it, put on texture but here comes my problem
It doesn't draw all of it it only displays about 10 unit on the Z axe.. X i fine.
So i want to create a big square but it displays a rectangle. It is like someone took a scissors and cut it off a certaint Z coordinate.
I don't even know what part of my code should i put it here, shader ? plane coordinates ? camera settings ?
Thank you for your patient.
It sounds like your plane is getting clipped by the frustum or viewing volume. That is typically set by either glOrtho() or glPerspective(). Try increasing the distance between the near and far plane parameters to these functions.
If you are relying on a default frustum provided by Android, you may have to construct your own frustum, which would look something like this for glOrtho():
typedef struct
{
float f0;
float f1;
float f2;
float f3;
float f4;
float f5;
float f6;
float f7;
float f8;
float f9;
float f10;
float f11;
float f12;
float f13;
float f14;
float f15;
} Mat4;
void Ortho(Mat4 * pMat4, float left, float top, float right, float bottom, float nearPlane, float farPlane)
{
float rcplmr = 1.0f / (left - right);
float rcpbmt = 1.0f / (bottom - top);
float rcpnmf = 1.0f / (nearPlane - farPlane);
pMat4->f0 = -2.0f * rcplmr;
pMat4->f1 = 0.0f;
pMat4->f2 = 0.0f;
pMat4->f3 = 0.0f;
pMat4->f4 = 0.0f;
pMat4->f5 = -2.0f * rcpbmt;
pMat4->f6 = 0.0f;
pMat4->f7 = 0.0f;
pMat4->f8 = 0.0f;
pMat4->f9 = 0.0f;
pMat4->f10 = -2.0f * rcpnmf;
pMat4->f11 = 0.0f;
pMat4->f12 = (right + left) * rcplmr;
pMat4->f13 = (top + bottom) * rcpbmt;
pMat4->f14 = (nearPlane + farPlane) * rcpnmf;
pMat4->f15 = 1.0f;
}
I am on Android API Level 9. I have a Camera preview loaded into a SurfaceView. I am trying to draw a vignette mask over this. In order to do so I am using a GLSurfaceView. I prepared a mask in XCode shader builder using the following fragment shader code (or is it a pixel shader?) which compiles successfully so far:
uniform sampler2D tex;
void main()
{
float innerAlpha = 0.0;
float outerAlpha = 1.0;
float len = 1.7;
float startAdjustment = -0.2;
float diff = 0.4;
float alphaStep = outerAlpha / len;
vec2 center = vec2(0.5, 0.5);
vec2 foc1 = vec2(diff,0.);
vec2 foc2 = vec2(-diff,0.);
float r = distance(center+foc1,gl_TexCoord[0].xy) + distance(center+foc2,gl_TexCoord[0].xy);
float alpha = r - (diff * 2.0) * alphaStep - startAdjustment;
vec4 vColor = vec4(0.,0.,0., innerAlpha + alpha);
gl_FragColor = vColor;
}
However, I do not know how to implement this into code for Android. Basically I think I would need to create a rectangle, which would cover the whole view and apply this kind of code generated texture on it. I just can not manage to figure out the actual code. Ideally, it should be in OpenGL ES 2.0.
Edit1:
#Tim - I tried to follow the tutorials here http://developer.android.com/training/graphics/opengl/draw.html
and here
http://www.learnopengles.com/android-lesson-one-getting-started/
and I basically understand, how to draw a triangle. But I do not understand, how to draw rectangle - I mean do I really need to draw two triangles actually or can I just define rectangle (or other complex shapes) right away?
As for the textures - in all tutorials I have seen, textures are actually being loaded from image files, but I would be interested in knowing, how can I actually kind of generate one using the pixel shader above.
Meanwhile, I have found the answer, how to draw the oval shaped mask.
Actually, the problem was, that I was thinking of gl_FragCoord in the range of 0.0 to 1.0,
but they have to be specified in actual pixels instead, e.g. 600.0 x 900.0 etc.
With little tweaks (changing vec2's to floats) I have been able to draw nice oval shaped mask over the whole screen in OpenGL. Here is the final fragment shader. Note, that you must specify the uniforms before drawing. If you are gonna try this, make sure to keep uSlope to somewhere between 0.1 and 2.0 to get meaningful results. Also, please, note that uInnerAlpha has to be lower than uOuterAlpha with this particular piece of code. For a typical vignette,
uInnerAlpha is 0.0 and uOuterAlpha is 1.0.
precision mediump float;
uniform float uWidth;
uniform float uHeight;
uniform float uSlope;
uniform float uStartAdjustment;
uniform float uEllipseLength;
uniform float uInnerAlpha;
uniform float uOuterAlpha;
void main() {
float gradientLength = uHeight * uSlope;
float alphaStep = uOuterAlpha / gradientLength;
float x1 = (uWidth / 2.0);
float y1 = (uHeight / 2.0) - uEllipseLength;
float x2 = (uWidth / 2.0);
float y2 = (uHeight / 2.0) + uEllipseLength;
float dist1 = sqrt(pow(abs(gl_FragCoord.x - x1), 2.0) + pow(abs(gl_FragCoord.y - y1), 2.0));
float dist2 = sqrt(pow(abs(gl_FragCoord.x - x2), 2.0) + pow(abs(gl_FragCoord.y - y2), 2.0));
float dist = (dist1 + dist2);
float alpha = ((dist - (uEllipseLength * 2.0)) * alphaStep - uStartAdjustment) + uInnerAlpha;
if (alpha > uOuterAlpha) {
alpha = uOuterAlpha;
}
if (alpha < uInnerAlpha) {
alpha = uInnerAlpha;
}
vec4 newColor = vec4(1.0, 1.0, 1.0, alpha);
gl_FragColor = newColor;
}