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
Related
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 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;
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'm trying to create a simple Android OpenGL 2.0 game to get my feet wet. I refeered to Androids tutorial on OpenGL and got it up and running, moved my square to where I want it and now i'm trying to translate it with on touch.
I've read that I have to unproject the current square... but not understanding this. Below is my code if there is any help on performing a translation on the square...
private float mPreviousY;
#Override
public boolean onTouchEvent(MotionEvent e) {
// MotionEvent reports input details from the touch screen
// and other input controls. In this case, you are only
// interested in events where the touch position changed.
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dy = y - mPreviousY;
// reverse direction of rotation to left of the mid-line
if (y < getHeight() / 2) {
dy = dy * -1 ;
}
mRenderer.mOffSet += dy;
requestRender();
}
mPreviousY = y;
return true;
}
my onDrawFrame:
#Override
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -50, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.translateM(mModleViewProjMatrix, 0, 0, mOffSet, 0);
// Calculate the projection and view transformation
Matrix.multiplyMM( mModleViewProjMatrix, 0, mProjMatrix, 0, mViewMatrix, 0);
// Draw square
mPaddle.draw(mModleViewProjMatrix);
}
Unprojecting means, reversing the process a vertex undergoes when being transformed. The forward transform is
v_eye = Modelview · v
v_clip = Projection · v_eye
v_ndc = v_clip / v_clip.w
Now what you have to do is reversing this process. I suggest you take a look at the sourcecode of the GLU function gluUnProject of Mesa, to be found here http://cgit.freedesktop.org/mesa/glu/tree/src/libutil/project.c
Update
Unprojecting is essentially reversing the process.
Let's look at Mesa's GLU gluUnProject code:
GLint GLAPIENTRY
gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
const GLdouble modelMatrix[16],
const GLdouble projMatrix[16],
const GLint viewport[4],
GLdouble *objx, GLdouble *objy, GLdouble *objz)
{
double finalMatrix[16];
double in[4];
double out[4];
First the compund transformation Projection · Modelview is evaluated…
__gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
…and inverted, i.e. reversed;
if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
in[0]=winx;
in[1]=winy;
in[2]=winz;
in[3]=1.0;
Then the window/viewport coordinates are mapped back into NDC coordinates
/* Map x and y from window coordinates */
in[0] = (in[0] - viewport[0]) / viewport[2];
in[1] = (in[1] - viewport[1]) / viewport[3];
/* Map to range -1 to 1 */
in[0] = in[0] * 2 - 1;
in[1] = in[1] * 2 - 1;
in[2] = in[2] * 2 - 1;
And multiplied with the inverse of the compound projection modelview
__gluMultMatrixVecd(finalMatrix, in, out);
Finally it is checked, that the so called homogenous component is nonzero
if (out[3] == 0.0) return(GL_FALSE);
And the homogenous divide inverted.
out[0] /= out[3];
out[1] /= out[3];
out[2] /= out[3];
Resulting in the original vertex position prior to the projection process
*objx = out[0];
*objy = out[1];
*objz = out[2];
return(GL_TRUE);
}
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;
}