Shader code to show selected part of image - OpenTk - c#

I want to show selected area from second half of an image (This is the range from 0.5 to 1.0) in my glcontrol. For that I have used two variables rightsliderStartval(any value between 0.5 and 1.0)
and rightsliderEndval(any value between 1.0 and 0.5). I want exactly the selected area between this rightsliderStartval and rightsliderEndval. When trying like below selected area is getting but it get stretched.
decimal RateOfResolution = (decimal)videoSource.VideoResolution.FrameSize.Width / (decimal)videoSource.VideoResolution.FrameSize.Height;
int openGLwidth = (this._Screenwidth / 3) - 40;
int openGLheight = Convert.ToInt32(screenWidthbyThree / RateOfResolution);
glControl.Width = openGLwidth;
glControl.Height = openGLheight;
GL.Viewport(new Rectangle(0, 0, glControl.Width, glControl.Height));
public void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoordIn;
void main() {
vTexCoordIn=( a_position.xy+1)/2 ;
gl_Position = vec4(a_position,1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
vec2 vTexCoord=vec2(vTexCoordIn.x,vTexCoordIn.y);
float rightsliderStartval=0.6;//0.5 to 1.0
float rightsliderEndval=0.8;//1.0 to 0.5
float rightsliderDelta=rightsliderEndval-rightsliderStartval;
if (vTexCoordIn.x < 0.5)
discard;
float u = mix(rightsliderStartval, rightsliderEndval, (vTexCoordIn.x-0.5) * 2.0);
vec4 color = texture2D(sTexture, vec2(u, vTexCoordIn.y));
gl_FragColor = color;
}");
GL.CompileShader(fragShader);
}
In Screenshot, White line represent center of image. I Want to show area between yellow and orange line.

If you want to skip a some parts of the texture, then you can use the discard keyword. This command causes the fragment's output values to be discarded and the fragments are not drawn at all.
If you've a rectangular area and you want to draw only in the 2nd half of the rectangular area, then you've to discard the fragments in the 1st half:
if (vTexCoordIn.x < 0.5)
discard;
If you want to draw the range from rightsliderStartval to rightsliderEndval in the 2nd half of the rectangular area, then you have to map the rang [0.5, 1.0] incoming texture coordinate vTexCoordIn.x to [rightsliderStartval, rightsliderEndval]:
float w = (vTexCoordIn.x-0.5) * 2.0; // [0.5, 1.0] -> [0.0, 1.0]
float u = mix(rightsliderStartval, rightsliderEndval, w); // [0.0, 1.0] -> [0.7, 0.9]
This leads to the fragment shader:
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
float rightsliderStartval = 0.7;
float rightsliderEndval = 0.9;
if (vTexCoordIn.x < 0.5)
discard;
float u = mix(rightsliderStartval, rightsliderEndval, (vTexCoordIn.x-0.5) * 2.0);
vec4 color = texture2D(sTexture, vec2(u, vTexCoordIn.y));
gl_FragColor = color;
}
If you don't want that the image is stretched then you've 2 possibilities.
Either discard the region from 0.0 to 0.7 and 0.9 to 1.0:
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
float rightsliderStartval = 0.7;
float rightsliderEndval = 0.9;
if (vTexCoordIn.x < 0.7 || vTexCoordIn.x > 0.9)
discard;
vec4 color = texture2D(sTexture, vTexCoordIn.xy));
gl_FragColor = color;
}
Or scale the image in the y direction, too:
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
float rightsliderStartval = 0.7;
float rightsliderEndval = 0.9;
if (vTexCoordIn.x < 0.5)
discard;
float u = mix(rightsliderStartval, rightsliderEndval, (vTexCoordIn.x-0.5) * 2.0);
float v_scale = (rightsliderEndval - rightsliderStartval) / 0.5;
float v = vTexCoordIn.y * v_scale + (1.0 - v_scale) / 2.0;;
vec4 color = texture2D(sTexture, vec2(u, v));
gl_FragColor = color;
}

Related

How to hide/remove particular area from top and bottom of image - GLControl

I can display below image using opengl in my glControl. Is there any way to cut or hide particular area (say 50px from top and bottom) equally from both bottom and top of glControl? Below is the code I have used to calculate the size of glControl. Can I achieve it by changing values on view port?
private void OpenGL_Size(GLControl glControl, VideoCaptureDevice videoSource)//always in portrait mode
{
decimal RateOfResolution = (decimal)videoSource.VideoResolution.FrameSize.Width / (decimal)videoSource.VideoResolution.FrameSize.Height;
decimal screenHeightbyTwo = this._Screenheight / 2;
RateOfResolution = 1 / RateOfResolution;// portrait
openGLheight = Convert.ToInt32(screenHeightbyTwo); // height is fixed; calculate the width
openGLwidth = (Convert.ToInt32(RateOfResolution * screenHeightbyTwo));
glControl.Width = openGLwidth;
glControl.Height = openGLheight;
}
GL.Viewport(new Rectangle(0, 0, glControl.Width, glControl.Height));
Shader code
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
vec4 color = texture2D(sTexture,vTexCoordIn);
gl_FragColor = color;
}
If you want to skip a some parts of the texture, then you can use the discard keyword. This command causes the fragment's output values to be discarded and the fragments are not drawn at all.
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
if (vTexCoordIn.y < 0.1 || vTexCoordIn.y > 0.9)
discard;
vec4 color = texture2D(sTexture, vTexCoordIn);
gl_FragColor = color;
}
If the height of the image and the height of the area which has to be discarded is given, then the condition is:
float img_h_px = 432.0; // height of the image in pixel
float area_h_px = 50.0; // area height in pixel
float w = area_h_px/img_h_px;
if (vTexCoordIn.y < w || vTexCoordIn.y > (1.0-w))
discard;

Apply Projection on half of texture

I'm using three glcontrols say GlControl1, GlControl2, GlControl3.
And I have two textures stexture1 and stexture2. Where stexture1 is displaying in glcontrol2. And right half portion of stexture2 is displaying on glcontrol1 and left half is dispalying on glcontrol3.
Now I want to apply projection on these three glcontrols. Using this link I can apply it successfully on glcontrol2 since it is displaying the texture fully.
But when applying on glcontrol1 and glcontrol3 it is not working well.
Please see the shader code I'm trying with.
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture_1;
uniform sampler2D sTexture_2;
uniform float sSelectedRangeLeft;
uniform float sSelectedRangeRight;
uniform float sSelectedRangeLeftEnd;
uniform float sSelectedRangeRightEnd;
uniform int sCurrentGLControl;
varying vec2 vTexCoordIn;
void main ()
{
vec2 vTexCoord=vec2(vTexCoordIn.x,vTexCoordIn.y);
float rightsliderStartval=sSelectedRangeRight;//0.5(value between 0.5 and 1.0)
float rightsliderEndval=sSelectedRangeRightEnd;//1.0(value between 0.5 and 1.0)
float rightsliderDelta=rightsliderEndval-rightsliderStartval;
float leftsliderStartval=sSelectedRangeLeftEnd;//0.0(value between 0 and 0.5)
float leftsliderEndval=sSelectedRangeLeft;//0.5(value between 0 and 0.5)
float leftsliderDelta=leftsliderEndval-leftsliderStartval;
if(sCurrentGLControl==1)
{
if ( vTexCoord.x <=1.0 && vTexCoord.x > 1.0 -rightsliderDelta)
{
vec4 colorLeft=texture2D (sTexture_2, vec2(vTexCoord.x -(1.0-rightsliderEndval), vTexCoord.y));
//i want to show this result in a projected view like glcontrol2
gl_FragColor = colorLeft;
}
}
else if(sCurrentGLControl==3)
{
if ( vTexCoord.x <=leftsliderDelta )
{
vec4 colorRight=texture2D (sTexture_2, vec2((vTexCoord.x)+leftsliderStartval, vTexCoord.y+sSelectedRightEndVerticalShift));
//i want to show this result in a projected view like glcontrol2
gl_FragColor = colorRight;
}
}
else if(sCurrentGLControl==2)
{ //Projection works fine
vec2 pos = vTexCoord.xy * 2.0 - 1.0;
float b = 0.3;
float v_scale = (1.0 + b) / (1.0 + b * sqrt(1.0 - pos.x*pos.x));
float u = asin( pos.x ) / 3.1415 + 0.5;
float v = (pos.y * v_scale) * 0.5 + 0.5;
if ( v < 0.0 || v > 1.0 )
discard;
vec3 texColor = texture2D( sTexture_1, vec2(u, v) ).rgb;
gl_FragColor = vec4( texColor.rgb, 1.0 );
}
}");
==================================================================
if (glControl.Name == "glControl1")
{
GL.Viewport(new Rectangle(-glControl.Width, 0, glControl.Width*2.0, glControl.Height));
}
else if (glControl.Name == "glControl2")
{
GL.Viewport(new Rectangle(0, 0, glControl.Width , glControl.Height));
}
else
{
GL.Viewport(new Rectangle(0, 0, glControl.Width*2.0, glControl.Height));
}
If you don't want to distort the "discarded" area, the just keep the original texture coordinate:
precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoordIn;
void main ()
{
vec2 uv = vTexCoordIn.xy
if (vTexCoordIn.x >= 0.7 && vTexCoordIn.x <= 0.9)
{
vec2 pos = vTexCoordIn.xy * 2.0 - 1.0;
float b = 0.3;
float v_scale = (1.0 + b) / (1.0 + b * sqrt(1.0 - pos.x*pos.x));
float u = asin( pos.x ) / 3.1415 + 0.5;
float v = (pos.y * v_scale) * 0.5 + 0.5;
if (v >= 0.0 && v <= 1.0)
uv = vec2(u, v);
}
vec3 texColor = texture2D(sTexture, uv).rgb;
gl_FragColor = vec4(texColor.rgb, 1.0);
}
Edit according to the changes of the question:
If you just want to show a part of the texture, then you've to map the texture coordinate from the range [0, 1] to the range [left, right], when the texture is looked up:
u = u * rightsliderDelta + rightsliderStartval;
vec3 texColor = texture2D( sTexture_2, vec2(u, v) ).rgb;
Apply this to your code as follows:
e.g.:
void main ()
{
vec2 vTexCoord=vec2(vTexCoordIn.x,vTexCoordIn.y);
float rightsliderStartval=sSelectedRangeRight;//0.5(value between 0.5 and 1.0)
float rightsliderEndval=sSelectedRangeRightEnd;//1.0(value between 0.5 and 1.0)
float rightsliderDelta=rightsliderEndval-rightsliderStartval;
// [...]
if(sCurrentGLControl==1) {
vec2 pos = vTexCoord.xy * 2.0 - 1.0;
float b = 0.3;
float v_scale = (1.0 + b) / (1.0 + b * sqrt(1.0 - pos.x*pos.x));
float u = asin( pos.x ) / 3.1415 + 0.5;
float v = (pos.y * v_scale) * 0.5 + 0.5;
if ( v < 0.0 || v > 1.0 )
discard;
u = u * rightsliderDelta + rightsliderStartval;
vec3 colorLeft = texture2D( sTexture_2, vec2(u, v) ).rgb;
gl_FragColor = vec4( colorLeft .rgb, 1.0 );
}
// [...]
}

Creating a custom square shape shader

I'm trying to create a custom shader in unity. Following is the code for my shader.
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
// Default Vertex Shader
v2f vert(appdata_img v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord.xy);
return o;
}
// Parameters
sampler2D _MainTex;
float _FOV;
// Alpha is the ratio of pixel density: width to height
float _Alpha;
uniform float4x4 _UnityDisplayTransform;
// Fragment Shader: Remap the texture coordinates to combine
// barrel distortion and disparity video display
fixed4 frag(v2f i) : COLOR {
float2 uv1, uv2, uv3;
float t1, t2;
float offset;
// uv1 is the remap of left and right screen to a full screen
uv1 = i.uv - 0.5;
uv1.x = uv1.x * 2 - 0.5 + step(i.uv.x, 0.5);
t1 = sqrt(1.0 - uv1.x * uv1.x - uv1.y * uv1.y);
t2 = 1.0 / (t1 * tan(_FOV * 0.5));
// uv2 is the remap of side screen with barrel distortion
uv2 = uv1 * t2 + 0.5;
// black color for out-of-range pixels
if (uv2.x >= 1.5 || uv2.y >= 1.0 || uv2.x <= -0.5 || uv2.y <= 0.0) {
return fixed4(0, 0, 0, 1);
} else {
offset = 0.5 - _Alpha * 0.5;
// uv3 is the remap of image texture
uv3 = uv2;
uv3.x = uv2.x * _Alpha + offset;
return tex2D(_MainTex, uv3);
}
}
ENDCG
}
Im getting the following output with the same. This is the effect that I get when I apply the shader.
However Im desiring to get a two perfect squares instead of the curved edges. How can I be able to sort it out?
This should work:
Shader "Custom/FakeAR"
{
Properties{
_MainTex("", 2D) = "white" {}
_FOV("FOV", Range(1, 2)) = 1.6
_Disparity("Disparity", Range(0, 0.3)) = 0.1
_Alpha("Alpha", Range(0, 2.0)) = 1.0
}
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
// Default Vertex Shader
v2f vert(appdata_img v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord.xy);
return o;
}
// Parameters
sampler2D _MainTex;
float _FOV;
// Alpha is the ratio of pixel density: width to height
float _Alpha;
// Disparity is the portion to separate
// larger disparity cause closer stereovision
float _Disparity;
// Fragment Shader: Remap the texture coordinates to combine
// barrel distortion and disparity video display
fixed4 frag(v2f i) : COLOR
{
float2 uv1, uv2, uv3;
float t1, t2;
float offset;
// uv1 is the remap of left and right screen to a full screen
uv1 = i.uv - 0.5;
uv1.x = uv1.x * 2 - 0.5 + sign(i.uv.x < 0.5);
//t1 = sqrt(1.0 - uv1.x * uv1.x - uv1.y * uv1.y);
t2 = _FOV;// 1.0 / (t1 * tan(_FOV * 0.5));
// uv2 is the remap of side screen with barrel distortion
uv2 = uv1 * t2 + 0.5;
// black color for out-of-range pixels
if (uv2.x >= 1 || uv2.y >= 1 || uv2.x <= 0 || uv2.y <= 0) {
return fixed4(0, 0, 0, 1);
}
else {
offset = 0.5 - _Alpha * 0.5 + _Disparity * 0.5 - _Disparity * sign(i.uv.x < 0.5);
// uv3 is the remap of image texture
uv3 = uv2;
uv3.x = uv2.x * _Alpha + offset;
return tex2D(_MainTex, uv3);
}
//float4 color = tex2D(_MainTex, i.uv);
//return 1 - color;
}
ENDCG
}
}
FallBack "Diffuse"
}

Show half portion of image side by side - OpenGL

I have created two textures for two images. Now I want to show this textures in opengl in an order that left part of image2, full image1, right part of image2. I have done like below. Image1 shows at the center of opengl screen. But left and right part of screen is not correct (which should show left part of image2 and right part of image2 respectively)
Vertex shader:
attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = (a_position.xy + 1) / 2;
gl_Position = vec4(a_position,1);
}
Fragment shader:
precision highp float;
uniform sampler2D sTexture;//texture for image 1
uniform sampler2D sTexture1;//texture for image 2
varying vec2 vTexCoord;
void main () {
if ( vTexCoord.x<=0.25 )
gl_FragColor = texture2D (sTexture1, vec2(vTexCoord.x/2.0, vTexCoord.y));
else if ( vTexCoord.x>0.25 && vTexCoord.x<0.75 )
gl_FragColor = texture2D (sTexture, vec2(vTexCoord.x*2.0, vTexCoord.y));
else if(vTexCoord.x>=0.75 )
gl_FragColor = texture2D (sTexture1, vec2(vTexCoord.x*2.0-1.0, vTexCoord.y));
}
Compiling shaders:
void CreateShaders() {
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, vertexShaderSource);
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, fragmentShaderSource);
GL.CompileShader(fragShader);
}
I want to show this textures in opengl in an order that left part of image2, full image1, right part of image2
If the texture coordinate is less than 0.25 then you want to show the rang [0, 0.5] of image2. You have to map the x component of the texture coordinate from [0.0, 0.25] to [0, 0.5]:
vec2( vTexCoord.x*2.0, vTexCoord.y );
If the texture coordinate is grater then you want to show the rang [0.5, 1] of image2. You have to map the x component of the texture coordinate from [0.75, 1.0] to [0.5, 1.0]:
vec2( (vTexCoord.x-0.75)*2.0 + 0.5, vTexCoord.y );
or
vec2( vTexCoord.x*2.0 - 1.0, vTexCoord.y );
If the texture coordinate is grater than 0.25 and less than 0.75 then you want to show the full range of image1. You have to map the x component of the texture coordinate from [0.25, 0.75] to [0.0, 1.0]:
vec2( vTexCoord.x*2.0 - 0.5, vTexCoord.y );
The shader code my look like this
precision highp float;
uniform sampler2D sTexture;//texture for image 1
uniform sampler2D sTexture1;//texture for image 2
varying vec2 vTexCoord;
void main ()
{
float u = vTexCoord.x*2.0;
float a = 0.0;
if( vTexCoord.x > 0.75 )
{
u -= 1.0;
}
else if ( vTexCoord.x >= 0.25 )
{
u -= 0.5;
a = 1.0;
}
vec4 color1 = texture2D(sTexture1, vec2(u, texCoord.y));
vec4 color2 = texture2D(sTexture, vec2(u, texCoord.y));
gl_FragColor = mix(color2, color1, a);
}
Extension to the answer:
if I want to show only a portion of right image,for example (0.6,0.8).
You want to map [0.75, 1.0] to [0.6, 0.8]:
[0.75, 1.0] to [0, 1]: u' = (u-0.75)/0.25
[0, 1] to [0.6, 0.8]: u'' = u'*0.2+0.6
This leads to:
u = (vTexCoord.x-0.75)*0.2/0.25 + 0.6;
when mapping [0.75, 1.0] to [0.6, 0.8] i wish to display the remain portion of [0.75, 1.0] with black/white color. when using (vTexCoord.x-0.75)*0.2/0.25 + 0.6 image with portion [.6,.8] is filled in [0.75, 1.0]
You have to convert the RGB color to grayscal. I recommend to use the a formula for Relative luminance:
float grayscale = dot(color1, vec3(0.2126, 0.7152, 0.0722));
color1.rgb = vec3(grayscale);

C# OpenGL - Trying to get the light to move with the camera using shaders

I am currently building a test scene with shaders.
Here is my Vertext Shader code:
public const string VertexShaderText = #"
#version 130
in vec3 vertexPosition;
in vec3 vertexNormal;
in vec3 vertexTangent;
in vec2 vertexUV;
uniform vec3 light_direction;
out vec3 normal;
out vec2 uv;
out vec3 light;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
uniform bool enable_mapping;
void main(void)
{
normal = normalize((model_matrix * vec4(floor(vertexNormal), 0)).xyz);
uv = vertexUV;
mat3 tbnMatrix = mat3(vertexTangent, cross(vertexTangent, normal), normal);
light = (enable_mapping ? light_direction * tbnMatrix : light_direction);
gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
}
";
Here is my Fragment Shader:
public const string FragmentShaderText = #"
#version 130
uniform sampler2D colorTexture;
uniform sampler2D normalTexture;
uniform bool enableToggleLighting;
uniform mat4 model_matrix;
uniform bool enable_mapping;
uniform float alpha;
uniform float ambi;
in vec3 normal;
in vec2 uv;
in vec3 light;
out vec4 fragment;
void main(void)
{
vec3 fragmentNormal = texture2D(normalTexture, uv).xyz * 2 - 1;
vec3 selectedNormal = (enable_mapping ? fragmentNormal : normal);
float diffuse = max(dot(selectedNormal, light), 0);
float ambient = ambi;
float lighting = (enableToggleLighting ? max(diffuse, ambient) : 1);
fragment = vec4(lighting * texture2D(colorTexture, uv).xyz, alpha);
}
";
My Project is initialized like this:
CanvasControlSettings.ShaderProgram.Use();
CanvasControlSettings.ShaderProgram["projection_matrix"].SetValue(mainSceneProj);
CanvasControlSettings.ShaderProgram["light_direction"].SetValue(new Vector3(0f, 0f, 1f));
CanvasControlSettings.ShaderProgram["enableToggleLighting"].SetValue(CanvasControlSettings.ToggleLighting);
CanvasControlSettings.ShaderProgram["normalTexture"].SetValue(1);
CanvasControlSettings.ShaderProgram["enable_mapping"].SetValue(CanvasControlSettings.ToggleNormalMapping);
My rotation moves the camera around the object. I want to move the light position along with the camera so that the shading is always visible.
How can I send the Camera Pos to the shader and implement this ?
From the front:
Rotated:
EDIT:
I Updated the Camera Position after rotate like this:
GL.Light(LightName.Light0, LightParameter.Position, new float[] { CanvasControlSettings.Camera.Position.X, CanvasControlSettings.Camera.Position.Y, CanvasControlSettings.Camera.Position.Z, 0.0f } );
And changed the light line to this
light = gl_LightSource[0].position.xyz;
This almost works perfectly accept that the material light color is now way to bright! I would show pictures but it seems I need more rep.
EDIT:
Ok, after following provided links, I found my way. I changed the Vertex Shader light code to:
vec4 lightPos4 = vec4(gl_LightSource[0].position.xyz, 1.0);
vec4 pos4 = model_matrix * vec4(vertexPosition, 1.0);
light = normalize((lightPos4 - pos4).xyz);
Works perfectly now. Thanks
You don't need to send the camera position to your shader. Just change your lights position to the camera position and send your light to your shader.

Categories

Resources