I have a texel (rectangle) and I need to access its 4 corners.
vec2 offset = vec2(1,1)/vec2(texWidth, texHeight)
texture2D (texSource, texCoord + 0.5 * offset * ???? )
what should I fill here to get both top 2 and bottom 2 corners.?
[Edit] : Code as per Tommy's answer
" vec2 pixelSize = vec2(offsetx,offsety);\n" +
" vec2 halfPixelSize = pixelSize * vec2(0.5);\n" +
" vec2 texCoordCentre = vTextureCoord - mod(vTextureCoord, pixelSize) + halfPixelSize;\n" +
" vec2 topLeft = texCoordCentre - halfPixelSize;\n" +
" vec2 bottomRight = texCoordCentre + halfPixelSize;\n" +
" vec2 topRight = texCoordCentre + vec2(halfPixelSize.x, -halfPixelSize.y);\n" +
" vec2 bottomLeft = texCoordCentre + vec2(-halfPixelSize.x, halfPixelSize.y);\n" +
" vec4 p00 = texture2D(sTexture, topLeft);\n" +
" vec4 p02 = texture2D(sTexture, bottomRight);\n" +
" vec4 p20 = texture2D(sTexture, topRight);\n" +
" vec4 p22 = texture2D(sTexture, bottomLeft);\n" +
" vec4 pconv = 0.25*(p00 + p02 + p20 + p22);\n" +
A texture is always addressed by numbers in the range [0, 1). Taking a texel as being an individual pixel within a texture, each of those is an equal subdivision of the range [0, 1), hence if there are 16 of them the first occupies the region [0, 1/16), the next [1/16, 2/16), etc.
So the boundaries of the texel at n in a texture of size p are at n/p and n+1/p, and the four corners are at the combinations of the boundary positions for x and y.
If you have linear filtering enabled then you'll get an equal mix of the four adjoining texels by sampling at those locations; if you've got nearest filtering enabled then you'll get one of the four but be heavily subject to floating point rounding errors.
So, I think:
vec2 pixelSize = vec2(1.0) / vec2(texWidth, texHeight);
vec2 halfPixelSize = pixelSize * vec2(0.5);
vec2 texCoordCentre = texCoord - mod(texCoord, pixelSize) + halfPixelSize;
vec2 topLeft = texCoordCentre - halfPixelSize;
vec2 bottomRight = texCoordCentre + halfPixelSize;
vec2 topRight = texCoordCentre + vec2(halfPixelSize.x, -halfPixelSize.y);
vec2 bottomLeft = texCoordCentre + vec2(-halfPixelSize.x, halfPixelSize.y);
(... and if you were targeting ES 3 instead of 2, you could just use the textureSize function instead of messing about with uniforms)
Related
I am using https://github.com/natario1/CameraView this library for capturing a negative image to positive and it is using the openGl shaders. I need a filter in which I can capture a negative image to positive in Black & White mode not in the normal color mode (which is currently available in the library). I tried to mix the two filters i.e first capture the negative image to positive in color mode and then apply the Black & White mode filter but as I am new to openGl, I was unable to do this. Please help me in this regard. It would be highly appreciated. The shaders which I am using are as follows :
This shader is used to convert the negative to positive in color mode.
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n"
+ " float colorR = (1.0 - color.r) / 1.0;\n"
+ " float colorG = (1.0 - color.g) / 1.0;\n"
+ " float colorB = (1.0 - color.b) / 1.0;\n"
+ " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n"
+ "}\n";
This shader is used to change the normal positive image in Black & White mode.
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n"
+ "uniform samplerExternalOES sTexture;\n" + "void main() {\n"
+ " vec4 color = texture2D(sTexture, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n"
+ " float colorR = (color.r + color.g + color.b) / 3.0;\n"
+ " float colorG = (color.r + color.g + color.b) / 3.0;\n"
+ " float colorB = (color.r + color.g + color.b) / 3.0;\n"
+ " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n"
+ "}\n";
Please help in making a filter which can direct capture the negative image to positive in Black & White mode.
Thanks.
You can do that with a one-liner in a single shader:
gl_FragColor = vec4(vec3(dot(1.0 - color.rgb, vec3(1.0/3.0))), color.a);
Explanation:
the inverse color is:
vec3 inverseColor = 1.0 - color.rgb;
For the gray scale there are 2 opportunities. Either straight forward
float gray = (inverseColor.r + inverseColor.g + inverseColor.b) / 3.0;
Or by using the dot product:
float gray = dot(1.0 - inverseColor.rgb, vec3(1.0/3.0));
Finally construct a vec3 from gray:
gl_FragColor = vec4(vec3(gray), color.a);
My code is
vec4 textureColor = texture2D(uTextureSampler, vTextureCoord);
if(textureColor.r* 0.299 + textureColor.g * 0.587 + textureColor.b * 0.114 < 0.1) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
} else {
gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, textureColor.w);
}
My problem is how to judge the pixel is black? How can I do that, should change rgb to hsv?
return "precision mediump float; \n"+
" varying highp vec2 " + VARYING_TEXTURE_COORD + ";\n" +
" \n" +
" uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n" +
" \n" +
" void main()\n" +
" {\n" +
" vec3 keying_color = vec3(0.0, 0.0, 0.0);\n" +
" float thresh = 0.45; // [0, 1.732]\n" +
" float slope = 0.1; // [0, 1]\n" +
" vec3 input_color = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + VARYING_TEXTURE_COORD + ").rgb;\n" +
" float d = abs(length(abs(keying_color.rgb - input_color.rgb)));\n" +
" float edge0 = thresh * (1.0 - slope);\n" +
" float alpha = smoothstep(edge0, thresh, d);\n" +
" gl_FragColor = vec4(input_color,alpha);\n" +
" }";
In the keying_color variable is stored the actual color we want to replace. It is using classic RGB model, but intensity is not expressed as 0-255 integer. It is a float value in range 0-1. (So 0 = 0, 255 = 0, 122 = 0.478…) In our case, the green color has value (0.647, 0.941, 0.29), but if you are using different video, measure the color yourself.
Note: Make sure you have the right color. Some color measurement software automatically converts colors to slightly different formats, such as AdobeRGB.
So where’s the magic?
We load current pixel color in the input_color, then calculate difference between input and keying color. Based on this difference, alpha value is calculated and used for specific pixel.
You can control how strict the comparison is using the slope and threshold values. It is a bit more complicated, but the most basic rule is: The more threshold you have, the bigger tolerance.
So, we are done, right? Nope.
You can look this link: http://blog.csdn.net/u012847940/article/details/47441923
I want to do a fisheye effect on android useing opengl 2.0,i can do it not use the opengl,but this not i want ,because this is inefficient and not support video texture. I also test the fisheye effect using Android Media Effects API,but the effect looks not good.
i also search fishshader as follows:
private static final String FISHEYE_FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D u_Texture;\n" +
"uniform vec2 vScale;\n" +
"const float alpha = float(4.0 * 2.0 + 0.75);\n" +
"varying vec2 v_TexCoordinate;\n" +
"void main() {\n" +
" float bound2 = 0.25 * (vScale.x * vScale.x + vScale.y * vScale.y);\n" +
" float bound = sqrt(bound2);\n" +
" float radius = 1.15 * bound;\n" +
" float radius2 = radius * radius;\n" +
" float max_radian = 0.5 * 3.14159265 - atan(alpha / bound * sqrt(radius2 - bound2));\n" +
" float factor = bound / max_radian;\n" +
" float m_pi_2 = 1.570963;\n" +
" vec2 coord = v_TexCoordinate - vec2(0.5, 0.5);\n" +
" float dist = length(coord * vScale);\n" +
" float radian = m_pi_2 - atan(alpha * sqrt(radius2 - dist * dist), dist);\n" +
" float scalar = radian * factor / dist;\n" +
" vec2 new_coord = coord * scalar + vec2(0.5, 0.5);\n" +
" gl_FragColor = texture2D(u_Texture, new_coord);\n" +
"}\n";
this is i want to ,but i donot know how to use it .Can someone give me some clue.
Android OpenGL ES does (normally) support video textures. It's not strictly part of the OpenGL ES API, but you can normally import video surfaces as EGL External Images via Android SurfaceViews.
There are lots of similar questions on the web, but this SO question should provide a useful starting point:
Android. How play video on Surface(OpenGL)
I try to write a small program in OpenGL ES 2.0. But i found i quit hard to inspect the variable in shader language.
For example i want to know the value in ver vertex shader. I will pass the value to fragment shader and put the value as the Red in glFragColor. But i found it quit hard to pass the value. If i declare the value using varying, then the value will change.
Here is the code, the log is the value i want to print.
public static final String VERTEX_SHADER =
"attribute vec4 position;\n" +
"attribute vec2 inputTextureCoordinate;\n" +
"\n" +
"uniform float texelWidthOffset; \n" +
"uniform float texelHeightOffset; \n" +
"\n" +
"varying vec2 centerTextureCoordinate;\n" +
"varying vec2 oneStepLeftTextureCoordinate;\n" +
"varying vec2 twoStepsLeftTextureCoordinate;\n" +
"varying vec2 oneStepRightTextureCoordinate;\n" +
"varying vec2 twoStepsRightTextureCoordinate;\n" +
"varying float log;\n" +
"\n" +
"void main()\n" +
"{\n" +
"log = -0.1;\n" +
"gl_Position = position;\n" +
"vec2 firstOffset;\n" +
"vec2 secondOffset;\n" +
// "if (sqrt(pow(position.x, 2) + pow(position.y, 2)) < 0.2) {\n" +
// "log = -position.x;\n" +
"if (position.x < 0.3) {\n" +
"log = 0.7;\n" +
"firstOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset);\n" +
"secondOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset);\n" +
"} else {\n" +
"firstOffset = vec2(texelWidthOffset, texelHeightOffset);\n" +
"secondOffset = vec2(texelWidthOffset, texelHeightOffset);\n" +
"log = -0.1;\n" +
"}\n" +
"\n" +
"centerTextureCoordinate = inputTextureCoordinate;\n" +
"oneStepLeftTextureCoordinate = inputTextureCoordinate - firstOffset;\n" +
"twoStepsLeftTextureCoordinate = inputTextureCoordinate - secondOffset;\n" +
"oneStepRightTextureCoordinate = inputTextureCoordinate + firstOffset;\n" +
"twoStepsRightTextureCoordinate = inputTextureCoordinate + secondOffset;\n" +
"}\n";
public static final String FRAGMENT_SHADER =
"precision highp float;\n" +
"\n" +
"uniform sampler2D inputImageTexture;\n" +
"\n" +
"varying vec2 centerTextureCoordinate;\n" +
"varying vec2 oneStepLeftTextureCoordinate;\n" +
"varying vec2 twoStepsLeftTextureCoordinate;\n" +
"varying vec2 oneStepRightTextureCoordinate;\n" +
"varying vec2 twoStepsRightTextureCoordinate;\n" +
"varying float log;\n" +
"\n" +
"void main()\n" +
"{\n" +
"if (log != -0.1) {\n" +
"gl_FragColor.rgba = vec4(log, 0.0, 0.0, 1.0);\n" +
// "return;\n" +
// "}\n" +
"} else { \n" +
"lowp vec4 fragmentColor;\n" +
"fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.2;\n" +
"\n" +
"gl_FragColor = fragmentColor;\n" +
// "gl_FragColor.rgba = vec4(0.0, 1.0, 0.0, 1.0);\n" +
// "}\n" +
"}\n";
Or is there any better method to do this.
When comparing floating point values, instead of doing this :
if (log != -0.1)
You should allow a little delta/tolerance on the value to account for floating point precision and the eventual value "change" you may get from passing it as a varying.
So you should do something like :
if (abs(log - (-0.1)) >= 0.0001)
Here the 0.0001 I chosen is a bit arbitrary ... It has to be a small value ...
Another example with ==
Instead of :
if (log == 0.7)
do
if (abs(log - 0.7) <= 0.0001)
However here you probably also have another issue:
The vertex shader executes for each 3 vertex of all your triangles (or quads)
So for a specific triangle, you may set different values (-0.1 or 0.7) for log for each vertex
Now the problem is that in the fragment shader the GPU will interpolate between the 3 log values depending on which pixel it is rendering ... so in the end you can get any value in [-0.1,0.7] interval displayed on screen :-(
To avoid this kind of issue, I personally use #ifdefs in my shaders to be able to switch them between normal and debug mode, and can switch between the two with a keypress. I never try to mix normal and debug displays based on if tests, especially when the test is based on a vertex position.
So in your case I would first create a specific debug version of the shader, and then use 0.0 and 1.0 as values for log, like this what you will see are red gradients, the more red the color is, the closer you are to the case you want to test.
I am developing for Android with OpenGL ES 2 and two devices: Google Nexus 3 and Archos 80 G9 (8" tablet). On these devices my shaders works fine.
Now, i have bought a Samsung Galaxy Tab 2, and a single vertex shader does not work on this device. This shader (from OSGEarth) remove the problem of z-fighting for tracks on a 3D terrain, modulating the z value of the vertex. On Samsung Galaxy Tab 2 this modulation does not work (!)
This is the shader
std::string vertexShaderSource =
"#version 100\n\n"
"float remap( float val, float vmin, float vmax, float r0, float r1 ) \n"
"{ \n"
" float vr = (clamp(val, vmin, vmax)-vmin)/(vmax-vmin); \n"
" return r0 + vr * (r1-r0); \n"
"} \n\n"
"mat3 castMat4ToMat3Function(in mat4 m) \n"
"{ \n"
" return mat3( m[0].xyz, m[1].xyz, m[2].xyz ); \n"
"} \n\n"
"uniform mat4 osg_ViewMatrix; \n"
"uniform mat4 osg_ViewMatrixInverse; \n"
"uniform mat4 osg_ModelViewMatrix; \n"
"uniform mat4 osg_ProjectionMatrix; \n"
"uniform mat4 osg_ModelViewProjectionMatrix; \n"
"uniform float osgearth_depthoffset_minoffset; \n"
"attribute vec4 osg_Vertex;\n"
"attribute vec4 osg_Color;\n"
"varying vec4 v_color; \n\n"
"varying vec4 adjV; \n"
"varying float simRange; \n\n"
"void main(void) \n"
"{ \n"
// transform the vertex into eye space:
" vec4 vertEye = osg_ModelViewMatrix * osg_Vertex; \n"
" vec3 vertEye3 = vertEye.xyz/vertEye.w; \n"
" float range = length(vertEye3); \n"
// vec3 adjVecEye3 = normalize(vertEye3); \n"
// calculate the "up" vector, that will be our adjustment vector:
" vec4 vertWorld = osg_ViewMatrixInverse * vertEye; \n"
" vec3 adjVecWorld3 = -normalize(vertWorld.xyz/vertWorld.w); \n"
" vec3 adjVecEye3 = castMat4ToMat3Function(osg_ViewMatrix) * adjVecWorld3; \n"
// remap depth offset based on camera distance to vertex. The farther you are away,
// the more of an offset you need.
" float offset = remap( range, 1000.0, 10000000.0, osgearth_depthoffset_minoffset, 10000.0); \n"
// adjust the Z (distance from the eye) by our offset value:
" vertEye3 -= adjVecEye3 * offset; \n"
" vertEye.xyz = vertEye3 * vertEye.w; \n"
// Transform the new adjusted vertex into clip space and pass it to the fragment shader.
" adjV = osg_ProjectionMatrix * vertEye; \n"
// Also pass along the simulated range (eye=>vertex distance). We will need this
// to detect when the depth offset has pushed the Z value "behind" the camera.
" simRange = range - offset; \n"
" gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
" v_color = osg_Color; \n"
// transform clipspace depth into [0..1] for FragDepth:
" gl_Position.z = max(0.0, (adjV.z/adjV.w)*gl_Position.w ); \n"
// if the offset pushed the Z behind the eye, the projection mapping will
// result in a z>1. We need to bring these values back down to the
// near clip plan (z=0). We need to check simRange too before doing this
// so we don't draw fragments that are legitimently beyond the far clip plane.
" float z = 0.5 * (1.0+(adjV.z/adjV.w)); \n"
" if ( z > 1.0 && simRange < 0.0 ) { gl_Position.z = 0.0; } \n"
"} \n" ;
With this code the track on the terrain is not displayed at all on SGT2.
If a comment the instruction
gl_Position.z = max(0.0, (adjV.z/adjV.w)*gl_Position.w );
the shader works, and the track is displayed, but of course the z-figthing is not removed.
My Google Nexus and Samsung Galaxy Tab 2 both use PowerVR SGX 540, so maybe the problem is in the Floating Point Math precision of the different CPU's? (Or some bug?)
Any ideas?
Thanks
[SOLVED]
I removed from the vertex shader
"varying vec4 adjV; \n"
"varying float simRange; \n\n"
and declared them ad vec4/float.
I think they where assigned mediump precision as varyings.