ScreenShot:
As you can see the pic above,I created the HSL color palette in iOS, and I draw central part with OpenGL shader,but it's rect, can we make it a circle, not crop, we need draw all color to a circle? I tried for a long time but all failed. Can you help me? Thanks a lot indeed!
Here is the code:
- (void)loadShaders {
// create shader program
program = glCreateProgram();
const GLchar *vertexProgram = "precision highp float; \n\
\n\
attribute vec4 position; \n\
varying vec2 uv; \n\
\n\
void main() \n\
{ \n\
gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, 0.0, 1.0); \n\
uv = position.xy; \n\
}";
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexProgram, NULL);
glCompileShader(vertexShader);
glAttachShader(program, vertexShader);
// https://gist.github.com/eieio/4109795
const GLchar *fragmentProgram = "precision highp float; \n\
varying vec2 uv; \n\
uniform float hue; \n\
vec3 hsb_to_rgb(float h, float s, float l) \n\
{ \n\
float c = l * s; \n\
h = mod((h * 6.0), 6.0); \n\
float x = c * (1.0 - abs(mod(h, 2.0) - 1.0)); \n\
vec3 result; \n\
\n\
if (0.0 <= h && h < 1.0) { \n\
result = vec3(c, x, 0.0); \n\
} else if (1.0 <= h && h < 2.0) { \n\
result = vec3(x, c, 0.0); \n\
} else if (2.0 <= h && h < 3.0) { \n\
result = vec3(0.0, c, x); \n\
} else if (3.0 <= h && h < 4.0) { \n\
result = vec3(0.0, x, c); \n\
} else if (4.0 <= h && h < 5.0) { \n\
result = vec3(x, 0.0, c); \n\
} else if (5.0 <= h && h < 6.0) { \n\
result = vec3(c, 0.0, x); \n\
} else { \n\
result = vec3(0.0, 0.0, 0.0); \n\
} \n\
\n\
result.rgb += l - c; \n\
\n\
return result; \n\
} \n\
\n\
void main() \n\
{ \
gl_FragColor = vec4(hsb_to_rgb(hue, uv.x, uv.y), 1.0); \
}";
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentProgram, NULL);
glCompileShader(fragmentShader);
glAttachShader(program, fragmentShader);
// bind attribute locations
// this needs to be done prior to linking
glBindAttribLocation(program, ATTRIB_VERTEX, "position");
glLinkProgram(program);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
I do not code for your platform but I do not see where or what are you rendering but I assuming single QUAD so no surprise you are seeing rectangle. If you do not want to add circular mesh then you can do this in fragment shader without change in rendering code.
So let assume your palette is centered around x0,y0 and have radiuses inner r0 and outer r1 so r0<r1.
GL: render QUAD covering your palette disc
Fragment: compute distance of fragment from palette center
if not in range between inner and outer radius discard(); fragment.
dd=(x-x0)*(x-x0)+(y-y0)*(y-y0);
if ((dd<r0*r0)||(dd>r1*r1)) discard();
Fragment: compute angle of fragment via atan(dy,dx)
float ang=atan(y-y0,x-x0); // <-pi,+pi>
Fragment: convert angle to RGB output fragment color
so convert the ang range to what ever parameter you want to your palette (like hue and set the others to some default value) convert it to RGB and output it ... similar to these:
HSV histogram
RGB values of visible spectrum
Star B-V color index to apparent RGB color
Related
I'm trying to convert this particular shader to CIKernel Code.
https://www.shadertoy.com/view/4scBRH
I've got this soo far,
kernel vec4 thresholdFilter(__sample image, float time)
{
vec2 uv = destCoord();
float amount = sin(time) * 0.1;
amount *= 0.3;
float split = 1. - fract(time / 2.0);
float scanOffset = 0.01;
vec2 uv1 = vec2(uv.x + amount, uv.y);
vec2 uv2 = vec2(uv.x, uv.y + amount);
if (uv.y > split) {
uv.x += scanOffset;
uv1.x += scanOffset;
uv2.x += scanOffset;
}
float r = sample(image, uv1).r;
float g = sample(image, uv).g;
float b = sample(image, uv2).b;
float a = 1.0;
vec3 outPutPixel = sample(image, samplerTransform(image, uv)).rgb;
return vec4(outPutPixel, 1.0);
}
The output of this code is not even close to the shaderToy output.
super simple question: how do i properly declare a float variable in webgl?
Background:
I'm playing with this codepen: http://codepen.io/jlfwong/pen/Wxjkxv
the point of this codepen is to allow you set the color of each pixel in a shader based on a render function.
I get the basics and I got things working pretty well, but then I tried to get "fancy".
I'm focussing on this section:
var fragmentShader = compileShader(' \n\
void main(){ \n\
gl_FragColor = vec4(step(25.0, mod(gl_FragCoord.x, 50.0)), \n\
step(25.0, mod(gl_FragCoord.x, 50.0)), \n\
step(25.0, mod(gl_FragCoord.x, 50.0)), \n\
1.0); \n\
} \n\
', context.FRAGMENT_SHADER);
All I want to do is save step(25.0, mod(gl_FragCoord.x, 50.0)) off to a variable so i tried this:
var fragmentShader = compileShader(' \n\
void main(){ \n\
float x_thing = step(25.0, mod(gl_FragCoord.x, 50.0)); \n\
\n\
gl_FragColor = vec4(x_thing, x_thing, x_thing, 1.0); \n\
} \n\
', context.FRAGMENT_SHADER);
This doesn't work because it seems to be missing a precision declaration for float. here is the error:
uncaught exception: Shader compile failed with: ERROR: 0:3: '' : No precision specified for (float)
I have tried a few things to remedy this:
precision float x_thing = step(25.0, mod(gl_FragCoord.x, 50.0));
precision highp float x_thing = step(25.0, mod(gl_FragCoord.x, 50.0));
precision highp float; float x_thing = step(25.0, mod(gl_FragCoord.x, 50.0));
Also i've been googling and fiddling with this for a while and I'm just annoyed with having issues declaring a variable :P
TL;DR
how do i properly declare a float variable in webgl? / what am i doing wrong?
I found the secret! looks like float precision needs to be declared outside functions...
var fragmentShader = compileShader(' \n\
precision highp float; \n\
\n\
void main(){ \n\
float x_thing = step(25.0, mod(gl_FragCoord.x, 50.0)); \n\
gl_FragColor = vec4(x_thing, \n\
x_thing, \n\
x_thing, \n\
1.0); \n\
} \n\
', context.FRAGMENT_SHADER);
I am trying to use GLSL to implement a Harris Corner Detection. But it does not work properly(I am guessing). First off it doesn't detect all corners and it detects alot of points that are not corners, another big problem is that it the threshold is very specific for each image. Maybe that is normal with a Harris detector?
All help is appreciated.
Shader Passes:
1st: Standard passthrough.
2nd: I turn the image into a grayscale image.
3rd: Sobel filtering the image and passing the x, y gradient intensitys and the product of the xy intensitys.
uniform sampler2D texture;
varying vec2 vUV;
void main() {
vec2 uv = vUV;
// Offset used to get access to neighbours
float w = 1.0/800.0;
float h = 1.0/600.0;
vec3 temp;
vec3 sum = vec3(0.0);
// Sobel - Edge Detection
// y gradient
vec3 texel0 = texture2D(texture, uv + vec2(-w, h)).xyz;
vec3 texel1 = texture2D(texture, uv + vec2(-w, 0)).xyz;
vec3 texel2 = texture2D(texture, uv + vec2(-w, -h)).xyz;
vec3 texel6 = texture2D(texture, uv + vec2(w, h)).xyz;
vec3 texel7 = texture2D(texture, uv + vec2(w, 0)).xyz;
vec3 texel8 = texture2D(texture, uv + vec2(w, -h)).xyz;
vec3 vertEdge = 1.0 * texel0 + (2.0*texel1) + 1.0 * texel2 -
(1.0 * texel6 + (2.0*texel7) + 1.0 * texel8);
// x gradient
vec3 texe0 = texture2D(texture, uv + vec2(-w,h)).xyz;
vec3 texe1 = texture2D(texture, uv + vec2(0, h)).xyz;
vec3 texe2 = texture2D(texture, uv + vec2(w, h)).xyz;
vec3 texe6 = texture2D(texture, uv + vec2(-w,-h)).xyz;
vec3 texe7 = texture2D(texture, uv + vec2(0,-h)).xyz;
vec3 texe8 = texture2D(texture, uv + vec2(w,-h)).xyz;
vec3 horizEdge = 1.0 * texe0 + (2.0*texe1) + 1.0 * texe2 -
(1.0 * texe6 + (2.0*texe7) + 1.0 * texe8);
// Gradient intensity values
float iy = (vertEdge.r + vertEdge.g + vertEdge.b) /3.0;
float ix = (horizEdge.r + horizEdge.g + horizEdge.b) /3.0;
// Absolute to get negative values
iy = abs(iy);
ix = abs(ix);
float gradProcduct = ix * iy;
gl_FragColor = vec4(ix,iy,gradProcduct, 0.0);
Not the best looking code - just want it to work for now
4th and 5th: Standard Gaussian Blur
6th: Calculating Harris Response.
If it is a corner i paint that pixel in magenta.
void main() {
vec2 uv = vUV;
float w = 1.0/800.0;
float h = 1.0/600.0;
float threshold = 0.05;
vec4 gradientInfo = texture2D(texture, uv);
/************** Harris Reponse **********************
R is calculated as R = det(M)- K(Trace(M)) which leads to
R = Ix^2*Ix^y - Ixy^2-K(ix^2+iy^2)^2
Ix = X-gradient intesity
Iy = Y-gradient intesity
Ixy = product of the X- and Y-gradient intensities
*********************************************************/
float R = pow(gradientInfo.r,2.0)*pow(gradientInfo.g,2.0)
- pow(gradientInfo.b,2.0)
- threshold * pow((pow(gradientInfo.r,2.0)+pow(gradientInfo.g,2.0)),2.0);
vec4 test;
//if(R > 0.000000000005)
if(R > 0.0000000000750){
// Extremley small values, ugly soloution for now to be able to use R in maxSupress
test = vec4(1.0, 0.0, 1.0, R*1000000000.0);
}
else
test = vec4(vec3(gradientInfo.xyz),0.0);
gl_FragColor = vec4( test);
}
Results
Result on a simple square
Result on a more complex figure with the same R and Threshold
And the result when the response check is mulitplied by a 1000. Doesn't really seem to work.
Below is the code for the maximum supression.
void main() {
vec2 uv = vUV;
float vOffset = 1.0/800.0;
float hOffset = 1.0/600.0;
vec4 neighbourPixels[9];
vec3 result;
int check = 0;
vec3 previous = texture2D(texture2, uv).xyz;
vec4 current = texture2D(texture, uv);
float temp = current.a;
vec4 neighbourArray[25];
if(current.a > 0.0){
for(int i = -2; i<3;i++){
for(int j = -2; j<3;j++){
if(temp < texture2D(texture, vUV.xy+vec2(i,j)*vec2(vOffset,hOffset)).a ){
//result = vec3(1.0,0.0,1.0);
check = 1;
break;
}
}
if(check==1){
break;
}
}
if(check==1){
result = vec3(1.0,0.0,0.0);
}
else{
result = vec3(0.0,1.0,1.0);
}
}
else{
result = previous.xyz;
}
gl_FragColor = vec4( result, 0.0);
}
You need to look for local maxima in the Harris response, rather than just thresholding. Dilate the response with a 3x3 or 5x5 box, then find pixels whether original response and dilated version are equal.
I know to perform this in OpenGL with the code below:
glDisable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
how to simulate that in WebGL?
Here is a blinn-phong shader which emulates the OpenGL fixed function pipeline for per vertex lighting. By default this is equivalent to having glEnable(GL_COLOR_MATERIAL) and glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) enabled. You can emulate glColorMaterial by setting the uniforms to 1.0 which will cause material parameters track the current color instead of those set by glMaterial.
#version 120
////////////////////////////////////////////////////////////////////////////////
// http://www.glprogramming.com/red/chapter05.html //
// //
// color = (matEmission + globalAmbient * matAmbient) + //
// AttenuationFactor( 1.0 / ( Kc + Kl*d + Kq*d^2 ) ) * //
// [ (lightAmbient * matAmbient) + //
// (max(N.L,0) * lightDiffuse * matDiffuse) + //
// (max(N.H,0)^matShininess * lightSpecular * matSpecular) ] //
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Uniforms //
////////////////////////////////////////////////////////////////////////////////
uniform float uColorMaterialAmbient = 1.0;
uniform float uColorMaterialDiffuse = 1.0;
uniform float uColorMaterialEmission = 0.0;
uniform float uColorMaterialSpecular = 0.0;
////////////////////////////////////////////////////////////////////////////////
// Main //
////////////////////////////////////////////////////////////////////////////////
void main(void)
{
vec4 matAmbient = mix(gl_FrontMaterial.ambient, gl_Color, uColorMaterialAmbient);
vec4 matDiffuse = mix(gl_FrontMaterial.diffuse, gl_Color, uColorMaterialDiffuse);
vec4 matEmission = mix(gl_FrontMaterial.emission, gl_Color, uColorMaterialEmission);
vec4 matSpecular = mix(gl_FrontMaterial.specular, gl_Color, uColorMaterialSpecular);
// Transform normal into eye space. gl_NormalMatrix is the transpose of the
// inverse of the upper leftmost 3x3 of gl_ModelViewMatrix.
vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
// Calculate emission and global ambient light
vec4 emissionAmbient = matEmission + (gl_LightModel.ambient * matAmbient);
// Calculate ambient
vec4 lightAmbient = gl_LightSource[0].ambient * matAmbient;
// Transform the vertex into eye space
vec4 eyeVertex = gl_ModelViewMatrix * gl_Vertex;
vec3 eyeLightDir = gl_LightSource[0].position.xyz - eyeVertex.xyz;
float dist = length(eyeLightDir);
eyeLightDir = normalize(eyeLightDir);
// No attenuation for a directional light
float attenuationFactor = 1.0 / (gl_LightSource[0].constantAttenuation
+ gl_LightSource[0].linearAttenuation * dist
+ gl_LightSource[0].quadraticAttenuation * dist * dist);
// Calculate lambert term
float NdotL = max(dot(eyeNormal, eyeLightDir), 0.0);
// Calculate diffuse
vec4 lightDiffuse = NdotL * (gl_LightSource[0].diffuse * matDiffuse);
// Calculate specular
vec4 lightSpecular = vec4(0.0);
if ( NdotL > 0.0 )
{
float NdotHV = max(dot(eyeNormal, gl_LightSource[0].halfVector.xyz), 0.0);
lightSpecular = pow(NdotHV, gl_FrontMaterial.shininess) * (gl_LightSource[0].specular * matSpecular);
}
gl_FrontColor = emissionAmbient + attenuationFactor * (lightAmbient + lightDiffuse + lightSpecular);
gl_Position = ftransform();
}
How do I draw a filled circle with openGl on iPhone ?
I've found many solutions but none of them work. Probably because there are many ways to do it. But what's the method with shortest code ?
For a truly smooth circle, you're going to want a custom fragment shader. For example, the following vertex shader:
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
and fragment shader:
varying highp vec2 textureCoordinate;
const highp vec2 center = vec2(0.5, 0.5);
const highp float radius = 0.5;
void main()
{
highp float distanceFromCenter = distance(center, textureCoordinate);
lowp float checkForPresenceWithinCircle = step(distanceFromCenter, radius);
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * checkForPresenceWithinCircle;
}
will draw a smooth red circle within a square that you draw to the screen. You'll need to supply vertices for your square to the position attribute and coordinates that range from 0.0 to 1.0 in X and Y to the inputTextureCoordinate attribute, but this will draw a circle that's as sharp as your viewport's resolution allows and do so very quickly.
One way would be to use GL_POINTS:
glPointSize(radius);
glBegin(GL_POINTS);
glVertex2f(x,y);
glEnd();
Another alternative would be to use GL_TRIANGLE_FAN:
radius = 1.0;
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x, y);
for(int angle = 1; angle <= 360; angle = angle + 1)
glVertex2f(x + sind(angle) * radius, y + cosd(angle) * radius);
glEnd();
To get the verices of a circle:
float[] verts=MakeCircle2d(1,100,0,0)
public static float[] MakeCircle2d(float rad,int points,float x,float y)//x,y ofsets
{
float[] verts=new float[points*2+2];
boolean first=true;
float fx=0;
float fy=0;
int c=0;
for (int i = 0; i < points; i++)
{
float fi = 2*Trig.PI*i/points;
float xa = rad*Trig.sin(fi + Trig.PI)+x ;
float ya = rad*Trig.cos(fi + Trig.PI)+y ;
if(first)
{
first=false;
fx=xa;
fy=ya;
}
verts[c]=xa;
verts[c+1]=ya;
c+=2;
}
verts[c]=fx;
verts[c+1]=fy;
return verts;
}
Draw it as GL10.GL_LINES if you want a empty circle
gl.glDrawArrays(GL10.GL_LINES, 0, verts.length / 2);
Or draw it as GL10.GL_TRIANGLE_FAN if you want a filled one
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, verts.length / 2);
Its java but it is really easy to convert to c++/objc
Here is a super fast way using shaders... Just make a Quad with a vertex buffer and set the UV's from -1 to 1 for each corner of the quad.
The vertex buffer in floats should look like:
NOTE: this needs a index buffer too.
var verts = new float[20]
{
-1, -1, 0, -1, -1,
-1, 1, 0, -1, 1,
1, 1, 0, 1, 1,
1, -1, 0, 1, -1,
};
#VS
attribute vec3 Position0;
attribute vec2 Texcoord0;
varying vec4 Position_VSPS;
varying vec2 Texcoord_VSPS;
uniform vec2 Location;
void main()
{
vec3 loc = vec3(Position0.xy + Location, Position0.z);
gl_Position = Position_VSPS = vec4(loc, 1);
Texcoord_VSPS = loc.xy;
}
#END
#PS
varying vec4 Position_VSPS;
varying vec2 Texcoord_VSPS;
uniform vec2 Location;
void main()
{
float dis = distance(Location, Texcoord_VSPS);
if (.1 - dis < 0.0) discard;
gl_FragData[0] = vec4(0, 0, 1, 1);
}
#END