I would like to get a shape to move from middle bottom to the point I'm touching. Issue is to solve the angle (or degree?) to the touched point.
float angle = ?
float power = calculatePower(touchY);
Vec2 impulse = new Vec2(angle, power);
Vec2 point = body.getWorldCenter(); // to prevent rotation of shape
body.applyLinearImpulse(impulse, point);
Anyone got a suggestion?
EDIT: SOLVED
Thanks to Andrews answer. Here is the working code:
Point delta = new Point(touchX - bodyX, touchY - bodyY);
double angle = Math.atan2(delta.y, delta.x);
Vec2 direction = new Vec2((float)Math.cos(angle), (float)-Math.sin(angle));
float power = calculatePower(touchY);
Vec2 impulse = new Vec2(power * direction.x, power * direction.y);
Vec2 point = body.getWorldCenter();
body.applyLinearImpulse(impulse, point);
Pseudo code looks like this. atan2 is standard math function
Vec2 delta = touchPoint - body.position;
float angle = math.atan2(delta.y, delta.x);
This line Vec2 impulse = new Vec2(angle, power); looks very strange though. You are using angle as x value and power as y. That does not make much sense. I think your goal is to apply impulse of power power in direction of angle. In that case the code should look like this:
Vec2 dir = Vec2(math.cos(angle), math.sin(angle));
Vec2 impulse = power * dir;
But since delta and dir only differ in their magnitude you can simplify calculating the impulse as:
Vec2 delta = touchPoint - body.position;
Vec2 dir = delta.normalize();
Vec2 impulse = power * dir
Related
I have been trying to draw border of an Image with transparent background using OpenGL in Android. I am using Fragment Shader & Vertex Shader. (From the GPUImage Library)
Below I have added Fig. A & Fig B.
Fig A.
Fig B.
I have achieved Fig A. With the customised Fragment Shader. But Unable to make the border smoother as in Fig B. I am attaching the Shader code that I have used (to achieve rough border). Can someone here help me on how to make the border smoother?
Here is my Vertex Shader :
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
Here is my Fragment Shader :
I have calculated 8 pixels around the current pixel. If any one pixel of those 8 is opaque(having alpha greater than 0.4), It it drawn as a border color.
precision mediump float;
uniform sampler2D inputImageTexture;
varying vec2 textureCoordinate;
uniform lowp float thickness;
uniform lowp vec4 color;
void main() {
float x = textureCoordinate.x;
float y = textureCoordinate.y;
vec4 current = texture2D(inputImageTexture, vec2(x,y));
if ( current.a != 1.0 ) {
float offset = thickness * 0.5;
vec4 top = texture2D(inputImageTexture, vec2(x, y - offset));
vec4 topRight = texture2D(inputImageTexture, vec2(x + offset,y - offset));
vec4 topLeft = texture2D(inputImageTexture, vec2(x - offset, y - offset));
vec4 right = texture2D(inputImageTexture, vec2(x + offset, y ));
vec4 bottom = texture2D(inputImageTexture, vec2(x , y + offset));
vec4 bottomLeft = texture2D(inputImageTexture, vec2(x - offset, y + offset));
vec4 bottomRight = texture2D(inputImageTexture, vec2(x + offset, y + offset));
vec4 left = texture2D(inputImageTexture, vec2(x - offset, y ));
if ( top.a > 0.4 || bottom.a > 0.4 || left.a > 0.4 || right.a > 0.4 || topLeft.a > 0.4 || topRight.a > 0.4 || bottomLeft.a > 0.4 || bottomRight.a > 0.4 ) {
if (current.a != 0.0) {
current = mix(color , current , current.a);
} else {
current = color;
}
}
}
gl_FragColor = current;
}
You were almost on the right track.
The main algorithm is:
Blur the image.
Use pixels with opacity above a certain threshold as outline.
The main problem is the blur step. It needs to be a large and smooth blur to get the smooth outline you want. For blurring, we can use convolution filter Kernel. And to achieve a large blur, we should use a large kernel. And I suggest using the Gaussian Blur distribution, as it is very well known and used.
The Overview of he Algorithm is:
For each fragment, we sample many locations around it. The samples are made in an N by N grid. We average them together using weights that follow a 2D Gaussian Distribution.
This results in a blurred image.
With the blurred image, we paint the fragments that have alpha greater than a threshold with our outline color. And, of course, any opaque pixels in the original image should also appear in the result.
On a sidenote, your solution is almost a blur with a 3 x 3 kernel (you sample locations around the fragment in a 3 by 3 grid). However, a 3 x 3 kernel won't give you the amount of blur you need. You need more samples (e.g. 11 x 11). Also, the weights closer to the center should have a greater impact on the result. Thus, uniform weights won't work very well.
Oh, and one more important thing:
One single shader to acomplish this is NOT the fastest way to implement this. Usually, this would be acomplished with 2 separate renders. The first one would render the image as usual and the second render would blur and add the outline. I assumed that you want to do this with 1 single render.
The following is a vertex and fragment shader that accomplish this:
Vertex Shader
varying vec2 vecUV;
varying vec3 vecPos;
varying vec3 vecNormal;
void main() {
vecUV = uv * 3.0 - 1.0;
vecPos = (modelViewMatrix * vec4(position, 1.0)).xyz;
vecNormal = (modelViewMatrix * vec4(normal, 0.0)).xyz;
gl_Position = projectionMatrix * vec4(vecPos, 1.0);
}
Fragment Shader
precision highp float;
varying vec2 vecUV;
varying vec3 vecPos;
varying vec3 vecNormal;
uniform sampler2D inputImageTexture;
float normalProbabilityDensityFunction(in float x, in float sigma)
{
return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;
}
vec4 gaussianBlur()
{
// The gaussian operator size
// The higher this number, the better quality the outline will be
// But this number is expensive! O(n2)
const int matrixSize = 11;
// How far apart (in UV coordinates) are each cell in the Gaussian Blur
// Increase this for larger outlines!
vec2 offset = vec2(0.005, 0.005);
const int kernelSize = (matrixSize-1)/2;
float kernel[matrixSize];
// Create the 1-D kernel using a sigma
float sigma = 7.0;
for (int j = 0; j <= kernelSize; ++j)
{
kernel[kernelSize+j] = kernel[kernelSize-j] = normalProbabilityDensityFunction(float(j), sigma);
}
// Generate the normalization factor
float normalizationFactor = 0.0;
for (int j = 0; j < matrixSize; ++j)
{
normalizationFactor += kernel[j];
}
normalizationFactor = normalizationFactor * normalizationFactor;
// Apply the kernel to the fragment
vec4 outputColor = vec4(0.0);
for (int i=-kernelSize; i <= kernelSize; ++i)
{
for (int j=-kernelSize; j <= kernelSize; ++j)
{
float kernelValue = kernel[kernelSize+j]*kernel[kernelSize+i];
vec2 sampleLocation = vecUV.xy + vec2(float(i)*offset.x,float(j)*offset.y);
vec4 sample = texture2D(inputImageTexture, sampleLocation);
outputColor += kernelValue * sample;
}
}
// Divide by the normalization factor, so the weights sum to 1
outputColor = outputColor/(normalizationFactor*normalizationFactor);
return outputColor;
}
void main()
{
// After blurring, what alpha threshold should we define as outline?
float alphaTreshold = 0.3;
// How smooth the edges of the outline it should have?
float outlineSmoothness = 0.1;
// The outline color
vec4 outlineColor = vec4(1.0, 1.0, 1.0, 1.0);
// Sample the original image and generate a blurred version using a gaussian blur
vec4 originalImage = texture2D(inputImageTexture, vecUV);
vec4 blurredImage = gaussianBlur();
float alpha = smoothstep(alphaTreshold - outlineSmoothness, alphaTreshold + outlineSmoothness, blurredImage.a);
vec4 outlineFragmentColor = mix(vec4(0.0), outlineColor, alpha);
gl_FragColor = mix(outlineFragmentColor, originalImage, originalImage.a);
}
This is the result I got:
And for the same image as yours, with matrixSize = 33, alphaTreshold = 0.05
And to try to get crispier results we can tweak the parameters. Here is an example with matrixSize = 111, alphaTreshold = 0.05, offset = vec2(0.002, 0.002), alphaTreshold = 0.01, outlineSmoothness = 0.00. Note that increasing matrixSize will heavily impact performance, which is a limitation of rendering this outline with only one shader pass.
I tested the shader on this site. Hopefully you will be able to adapt it to your solution.
Regarding references, I have used quite a lot of this shadertoy example as basis for the code I wrote for this answer.
In my filters, the smoothness is achieved by a simple boxblur on the border.. You have decided that alpha > 0.4 is a border. The value of alpha between 0-0.4 in surrounding pixels gives an edge. Just blur this edge with a 3x3 window to get the smooth edge.
if ( current.a != 1.0 ) {
// other processing
if (current.a > 0.4) {
if ( (top.a < 0.4 || bottom.a < 0.4 || left.a < 0.4 || right.a < 0.4
|| topLeft.a < 0.4 || topRight.a < 0.4 || bottomLeft.a < 0.4 || bottomRight.a < 0.4 )
{
// Implement 3x3 box blur here
}
}
}
You need to tweak which edge pixels you blur. The basic issue is that it drops from an opaque to a transparent pixel - what you need is a gradual transition.
Another options is quick anti-aliasing. From my comment below - Scale up 200% and then scale down 50% to original method. Use nearest neighbour scaling. This technique is used for smooth edges on text sometimes.
there is a problem that i just can't seem to get a handle on..
i have a fragment shader:
precision mediump float;
uniform vec3 u_AmbientColor;
uniform vec3 u_LightPos;
uniform float u_Attenuation_Constant;
uniform float u_Attenuation_Linear;
uniform float u_Attenuation_Quadradic;
uniform vec3 u_LightColor;
varying vec3 v_Normal;
varying vec3 v_fragPos;
vec4 fix(vec3 v);
void main() {
vec3 color = vec3(1.0,1.0,1.0);
vec3 vectorToLight = u_LightPos - v_fragPos;
float distance = length(vectorToLight);
vec3 direction = vectorToLight / distance;
float attenuation = 1.0/(u_Attenuation_Constant +
u_Attenuation_Linear * distance + u_Attenuation_Quadradic * distance * distance);
vec3 diffuse = u_LightColor * attenuation * max(normalize(v_Normal) * direction,0.0);
vec3 d = u_AmbientColor + diffuse;
gl_FragColor = fix(color * d);
}
vec4 fix(vec3 v){
float r = min(1.0,max(0.0,v.r));
float g = min(1.0,max(0.0,v.g));
float b = min(1.0,max(0.0,v.b));
return vec4(r,g,b,1.0);
}
i've been following some tutorial i found on the web,
anyways, the ambientColor and lightColor uniforms are (0.2,0.2,0.2), and (1.0,1.0,1.0)
respectively. the v_Normal is calculated at the vertex shader using the
inverted transposed matrix of the model-view matrix.
the v_fragPos is the model result of multiplying the position with the normal model-view matrix.
now, i expect that when i move the light position closer to the cube i render, it will just appear brighter, but the resulting image is very different:
(the little square there is an indicator for the light position)
now, i just don't understand how this can happen?
i mean, i multiply the color components each by the SAME value..
so, how is it that it seems to vary so??
EDIT: i noticed that if i move the camera in front of the cube, the light is just shades of blue.. which is the same problem but maybe it's a clue i don't know..
The Lambertian reflectance is computed with the Dot product of the normal vector and the vector to the light source, instead of the component wise product.
See How does the calculation of the light model work in a shader program?
Use the dot function instead of the * (multiplication) operator:
vec3 diffuse = u_LightColor * attenuation * max(normalize(v_Normal) * direction,0.0);
vec3 diffuse = u_LightColor * attenuation * max(dot(normalize(v_Normal), direction), 0.0);
You can simplify the code in the fix function. min and max can be substituted with clamp. This functions work component wise, so they do not have to be called separately for each component:
vec4 fix(vec3 v)
{
return vec4(clamp(v, 0.0, 1.0), 1.0);
}
I have this vertex shader that i'm use to rotate or translate the obj depending of state values.
private final String vertexShader="" +
"attribute vec4 vertex;" +
"attribute vec4 colors;" +
"varying vec4 vcolors;" +
"uniform int x;" +
"uniform vec4 translate;"+
"uniform mat4 rotate;"+
"void main(){" +
"vec4 app_verte=vertex;" +
"if(x==1){" +
"app_verte=vertex+translate;" +
"}else if(x==2){" +
"app_verte=rotate*app_verte;" +
"}" +
"vcolors=colors;" +
"gl_Position=app_verte;" +
"}";
For the rotation i use the a matrix that using the matrix associeted is built from a float[16] array as follow:
|cos(angle),-sin(angle),0,0|
|sin(angle), cos(angle),0,0|
|0 , ,0,0|
Now i have different questions becouse i really hard understand. If i want to change the type of transformation i have to set the x value. Now to have a continius transformation i supposed that the vertex buffere will be the same and after a transformation the value of the buffer will be changed. Now nothing happend becouse it transform and draw with the same coordiates. i put only at first the coordinatesbuffer. There is a way to use the same buffer that is the the VRAM without put it every time and if there is not how can a pull the changed buffer to my buffer obj after the tranformation without transform the point using the array and put it into the buffer??
Sorry for my english and thanks to all indeed.
The vertex buffers are designed this way so you send them to the GPU only once to reduce the traffic. You then use matrices (or other systems such as translation vector) to apply the transform in the vertex shader so you send only up to 4x4 float buffer.
IF I understand what your issue is it lies in that you use multiple systems at the same time. You have a translation vector and a matrix but you use either one or the other. So in your case you might be able to simply apply both of them in the shader as app_verte = rotate*app_verte + translate; or app_verte = rotate*(app_verte + translate); already these 2 are not the same and I am guessing that at some point you will need something like app_verte = rotate2*(rotate1*app_verte + translate1) + translate2; which is not solvable since the number of operations will increase over time.
So you need to chose a single system which in your case should be a matrix. Rather then sending the translation matrix you can translate the matrix on the CPU part of your application and send only that to the shader. You need to find tools to multiply the matrices and to generate translation and rotation matrix. You can make them yourself but already looking at the one you posted I am pretty sure the second last value should be 1 and not 0 (though it must be a typo since the last row contains 3 values while others contain 4).
So have a single matrix which in beginning is set to identity which corresponds to x=0. Then for x=1 situation set that matrix as a translation matrix myMatrix = generateTranslationMatrix(x, y, z). And for x=2 do the same with rotation matrix myMatrix = generateRotationMatrix(x, y, z, angle). Now when you need to continue the operation, to concat the two you simply multiply them, so for both you would do myMatrix = generateTranslationMatrix(x, y, z)*generateRotationMatrix(x, y, z, angle). But there is no reason to keep the values separate as well so in the end you just want some methods to manipulate the state of the orientation:
Matrix myMatrix;
onLoad() {
myMatrix = Matrix.identity();
}
onTurnRight(float angle) {
myMatrix = myMatrix * generateRotationMatrix(0, 1, 0, angle);
}
onMove(float x, float y, float z) {
myMatrix = myMatrix * generateTranslationMatrix(x, y, z);
}
Then you can add other methods to your code as needed but for instance if you handle touch events and when a finger moves up or down you will move forward or backwards while left and right will rotate the object then it will look something like this:
onFingerMoved(float x, float y) {
const float xfactor = 0.01; // Modify to control the speed of rotation
const float yfactor = -0.1; // Modify to control the speed of movement
float dx = previousX - x;
float dy = previousy - y;
onTurnRight(dx);
onMove(.0, .0, dy); // Assuming the Z coordinate is forward
previousX = x;
previousY = y;
}
My terrain uses shader which itself uses four different textures. It runs fine on windows and linux machines, but on android it gets only ~25FPS on both galaxies. I thought, that textures are the problem, but no, as it appears the problem is with the part where I divide texture coordinates and use frac to get tiled coordinates. Without it, I get 60FPS.
// Material data.
//uniform vec3 uAmbient;
//uniform vec3 uDiffuse;
//uniform vec3 uLightPos[8];
//uniform vec3 uEyePos;
//uniform vec3 uFogColor;
uniform sampler2D terrain_blend;
uniform sampler2D grass;
uniform sampler2D rock;
uniform sampler2D dirt;
varying vec2 varTexCoords;
//varying vec3 varEyeNormal;
//varying float varFogWeight;
//------------------------------------------------------------------
// Name: fog
// Desc: applies calculated fog weight to fog color and mixes with
// specified color.
//------------------------------------------------------------------
//vec4 fog(vec4 color) {
// return mix(color, vec4(uFogColor, 1.0), varFogWeight);
//}
void main(void)
{
/*vec3 N = normalize(varEyeNormal);
vec3 L = normalize(uLightPos[0]);
vec3 H = normalize(L + normalize(uEyePos));
float df = max(0.0, dot(N, L));
vec3 col = uAmbient + uDiffuse * df;*/
// Take color information from textures and tile them.
vec2 tiledCoords = varTexCoords;
//vec2 tiledCoords = fract(varTexCoords / 0.05); // <========= HERE!!!!!!!!!
//vec4 colGrass = texture2D(grass, tiledCoords);
vec4 colGrass = texture2D(grass, tiledCoords);
//vec4 colDirt = texture2D(dirt, tiledCoords);
vec4 colDirt = texture2D(dirt, tiledCoords);
//vec4 colRock = texture2D(rock, tiledCoords);
vec4 colRock = texture2D(rock, tiledCoords);
// Take color information from not tiled blend map.
vec4 colBlend = texture2D(terrain_blend, varTexCoords);
// Find the inverse of all the blend weights.
float inverse = 1.0 / (colBlend.r + colBlend.g + colBlend.b);
// Scale colors by its corresponding weight.
colGrass *= colBlend.r * inverse;
colDirt *= colBlend.g * inverse;
colRock *= colBlend.b * inverse;
vec4 final = colGrass + colDirt + colRock;
//final = fog(final);
gl_FragColor = final;
}
Note: there's some more code for light calculation and fog, but it isn't used. I indicated the line that, when uncommented, causes massive lag. I tried using floor and calculating fractional part manually, but lag is the same. What might be wrong?
EDIT: Now here's what I don't understand.
This:
vec2 tiledCoords = fract(varTexCoords * 2.0);
Runs great.
This:
vec2 tiledCoords = fract(varTexCoords * 10.0);
Runs average on SIII.
This:
vec2 tiledCoords = fract(varTexCoords * 20.0);
Lags...
This:
vec2 tiledCoords = fract(varTexCoords * 100.0);
Well 5FPS is still better than I expected...
So what gives? Why is this happening? To my understanding this shouldn't make any difference. But it does. And a huge one.
I would run your code on a profiler (check Mali-400), but by the looks of it, you are killing the texture cache. For the first pixel computed, all those 4 texture look-ups are fetched but also the contiguous data is also fetched into the texture cache. For the next pixel, you are not accessing data in the cache but looking quite far (10, 20..etc) which completely defies the purpose of such a cache.
This of course a guess, without proper profiling is hard to tell.
EDIT: #harism also pointed you to that direction.
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;
}