Hello guys can someone help me with the conversion of glsl to c#? i'm new to glsl and i really need alot of help! gladly appreciate all your helps! :)
#version 120
uniform sampler2D tex;
void main()
{
vec4 pixcol = texture2D(tex, gl_TexCoord[0].xy);
vec4 colors[3];
colors[0] = vec4(0.,0.,1.,1.);
colors[1] = vec4(1.,1.,0.,1.);
colors[2] = vec4(1.,0.,0.,1.);
float lum = (pixcol.r+pixcol.g+pixcol.b)/3.;
int ix = (lum < 0.5)? 0:1;
vec4 thermal = mix(colors[ix],colors[ix+1],(lum-float(ix)*0.5)/0.5);
gl_FragColor = thermal;
}
You don't need to convert GLSL to c# to use it, as it is used by OpenGL API directly. There are several OpenGl wrappers for c#, not sure if all support shaders, but openTk supports for sure, example is here:
using (StreamReader sr = new StreamReader("vertex_shader.glsl"))
{
GL.ShaderSource(m_shader_handle, sr.ReadToEnd());
}
You can load shader either from file, either from string directly:
string shader = "void main() { // your shader code }"
GL.ShaderSource(m_shader_handle, shader);
The c# code that would be analogous to your reference code is (pseudo-code)
//Declares the texture/picture i.e. uniform sampler2D tex;
Bitmap x = new Bitmap();
float[] main()
{
// Looks up the color of a pixel for the specified coordinates, the color (as a rule of thumb)
// a normalized value i.e. vec4 pixcol = texture2D(tex, gl_TexCoord[0].xy);
Color pixcolUnnormalized= x.GetPixel();
float[] pixcol = new float[] { pixcolUnnormalized.r / 255.0f, pixcolUnnormalized.g / 255.0f, pixcolUnnormalized.b / 255.0f, pixcolUnnormalized.a / 255.0f);
//Setup coefficients i.e. vec4 colors[3]; colors[0] = vec4(0.,0.,1.,1.); colors[1] = vec4(1.,1.,0.,1.); colors[2] = vec4(1.,0.,0.,1.);
float[] color1[] = new float[] { 0.0,0.0,1.0,1.0 };
float[] color2[] = new float[] { 0.0,0.0,1.0,1.0 };
float[] color3[] = new float[] { 0.0,0.0,1.0,1.0 };
float[ float[] ] colors = new float[] { colors1, colors2, colors3 };
///Obtain luminance value from the pixel.
float lum = (pixcol[0]+pixcol[1] +pixcol[2])/3.;
int ix = (lum < 0.5)? 0:1;
//Interpolate the color values i.e. vec4 thermal = mix(colors[ix],colors[ix+1],(lum-float(ix)*0.5)/0.5);
float[] thermal = new float[] {
colors[ix][0] * ( 1 - (lum-float(ix)*0.5)/0.5) ) + colors[ix + 1][0] * (lum-float(ix)*0.5)/0.5)
colors[ix][1] * ( 1 - (lum-float(ix)*0.5)/0.5) ) + colors[ix + 1][1] * (lum-float(ix)*0.5)/0.5)
colors[ix][2] * ( 1 - (lum-float(ix)*0.5)/0.5) ) + colors[ix + 1][2] * (lum-float(ix)*0.5)/0.5)
colors[ix][3] * ( 1 - (lum-float(ix)*0.5)/0.5) ) + colors[ix + 1][3] * (lum-float(ix)*0.5)/0.5)
};
//return the value
return thermal;
}
Related
I am doing A raytraycer with c# and I am trying to add lights. My scene has one Spherical light in front and one behind the Spheres(I haven't implemented shadows yet). However, it doesn't seem to look right when multiple light sources are turned on. Are there any mistakes in my implementation ?
Scene with two light sources turned on
Scene with one light source
The code for computing the light
protected Color Shading(Vector3 position, List<Lightsource> lightSources, Color
color, Vector3 normal, float albedo)
{
var finalColor = Color.Black;
foreach (var lightSource in lightSources)
{
var posToLightVector = lightSource.Position - position;
var lightDir = Vector3.Normalize(posToLightVector);
var lightDot = Math.Max(Vector3.Dot(lightDir,normal), 0);
var lightReflected = albedo / Math.PI;
var lightPower = lightDot * lightSource.Intensity;
var newColor = calculateColorValue(color, lightPower, lightReflected);
finalColor = AddColors(finalColor, newColor);
}
return finalColor;
}
private Color calculateColorValue(Color colorValue, float lightPower, double lightReflected)
{
var r = ((float)colorValue.R / 255) * lightPower * lightReflected;
var g = ((float)colorValue.G / 255) * lightPower * lightReflected;
var b = ((float)colorValue.B / 255) * lightPower * lightReflected;
return Color.FromArgb(Math.Min((int)(r * 255), 255), Math.Min((int)(g * 255), 255), Math.Min((int)(b * 255), 255));
}
private static Color AddColors(Color color1, Color color2)
{
return Color.FromArgb(Math.Min(255, color1.R + color2.R), Math.Min(255, color1.G + color2.G), Math.Min(255, color1.B + color2.B));
}
I am trying to implement the unsharp masking method on emgucv using c#.
The python code I have now is (ref):
def unsharp_mask(image, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0):
"""Return a sharpened version of the image, using an unsharp mask."""
# For details on unsharp masking, see:
# https://en.wikipedia.org/wiki/Unsharp_masking
# https://homepages.inf.ed.ac.uk/rbf/HIPR2/unsharp.htm
blurred = cv.GaussianBlur(image, kernel_size, sigma)
sharpened = float(amount + 1) * image - float(amount) * blurred
sharpened = np.maximum(sharpened, np.zeros(sharpened.shape))
sharpened = np.minimum(sharpened, 255 * np.ones(sharpened.shape))
sharpened = sharpened.round().astype(np.uint8)
if threshold > 0:
low_contrast_mask = np.absolute(image - blurred) < threshold
np.copyto(sharpened, image, where=low_contrast_mask)
return sharpened
The c# code I have now cannot do the work as the above code does. Does anyone know how to implement it emgu cv using c#?
public static void GetMat(Image<Gray, byte> srcimg, Image<Gray, byte> imgBlurred, ref Mat dst, int nAmount = 200)
{
float amount = nAmount / 100f;
using (Image<Gray, byte> dst_temp = new Image<Gray, byte>(srcimg.Width, srcimg.Height))
{
for (int v = 0; v < srcimg.Height; v++)
{
for (int u = 0; u < srcimg.Width; u++)
{
byte a = srcimg.Data[v, u, 0]; //Get Pixel Color | fast way
byte b = imgBlurred.Data[v, u, 0];
int c = (int)(a * (1 + amount) - (amount * b));
if (c < 0) c = 0;
if (c > 255) c = 255;
dst_temp.Data[v, u, 0] = (byte)c;
}
}
dst = dst_temp.Mat.Clone();
}
}
public static void getSharpenImage(Mat src, ref Mat dst, int nAmount = 200, double sigma = 3, int threshold = 0)
{
float amount = nAmount / 100.0F;
using (Mat imgBlurred = new Mat())
{
CvInvoke.GaussianBlur(src, imgBlurred, new System.Drawing.Size(0, 0), sigma, sigma);
using (Mat mask_temp = new Mat())
{
CvInvoke.AbsDiff(src, imgBlurred, mask_temp);
using (Mat lowcontrastmask = new Mat())
{
CvInvoke.Threshold(mask_temp, lowcontrastmask, threshold, 255, ThresholdType.BinaryInv);
GetMat(src.ToImage<Gray, byte>(), imgBlurred.ToImage<Gray, byte>(), ref dst);
src.CopyTo(dst, lowcontrastmask);
}
}
}
}
https://www.idtools.com.au/unsharp-masking-python-opencv/ has a python solution.
the following works in C#:
Mat blurredImage = new Mat();
Mat lapImage = new Mat();
CvInvoke.MedianBlur(grayImage, blurredImage, 1);
CvInvoke.Laplacian(blurredImage, lapImage, blurredImage.Depth);
blurredImage -= (0.9*lapImage);
I want to draw the mandelbrot-set taken from the Win2D-Example-Gallery and tweak it a little.
At first I had all my code to generate the mandelbrot inside the CreateResources-Method of CanvasAnimatedControl, but due to performance issues I went on to do it using shaders (HLSL or PixelShaderEffect) and CanvasVirtualControl:
public PixelShaderEffect _effectMandel;
CanvasVirtualImageSource _sdrc;
public async Task CreateResources(CanvasVirtualControl sender)
{
_sdrc = new CanvasVirtualImageSource(sender, new Size(_width, _height));
var arr = await FileHelper.ReadAllBytes("Shaders/Mandelbrot.bin");
if (arr != null)
{
_effectMandel = new PixelShaderEffect(arr);
using (CanvasDrawingSession drawingSession = sender.CreateDrawingSession(new Rect(0,0,_width,_height)))
{
drawingSession.DrawImage(_effectMandel);
}
}
}
When I run the application, I get a System.Runtime.InteropServices.COMException right in the using section and the 'App.g.i.cs' file opens up telling me:
The shader code I use is this:
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
// This shader has no input textures.
// It generates a mandelbrot fractal.
#define D2D_INPUT_COUNT 0
#define D2D_REQUIRES_SCENE_POSITION
#include "d2d1effecthelpers.hlsli"
float scale;
float2 translate;
static const float4 tapOffsetsX = float4(-0.25, 0.25, -0.25, 0.25);
static const float4 tapOffsetsY = float4(-0.25, -0.25, 0.25, 0.25);
static const int iterations = 100;
D2D_PS_ENTRY(main)
{
float2 pos = D2DGetScenePosition().xy;
// Improve visual quality by supersampling inside the pixel shader, evaluating four separate
// versions of the fractal in parallel, each at a slightly different position offset.
// The x, y, z, and w components of these float4s contain the four simultaneous computations.
float4 c_r = (pos.x + tapOffsetsX) * scale + translate.x;
float4 c_i = (pos.y + tapOffsetsY) * scale + translate.y;
float4 value_r = 0;
float4 value_i = 0;
// Evalulate the Mandelbrot fractal.
for (int i = 0; i < iterations; i++)
{
float4 new_r = value_r * value_r - value_i * value_i + c_r;
float4 new_i = value_r * value_i * 2 + c_i;
value_r = new_r;
value_i = new_i;
}
// Adjust our four parallel results to range 0:1.
float4 distanceSquared = value_r * value_r + value_i * value_i;
float4 vectorResult = isfinite(distanceSquared) ? saturate(1 - distanceSquared) : 0;
// Resolve the supersampling to produce a single scalar result.
float result = dot(vectorResult, 0.25);
if (result < 1.0 / 256)
return 0;
else
return float4(result, result, result, 1);
}
If you know why this happens, please answer. Thanks!
I needed to setup a Timer to regularly invalidate the canvas and get 60fps.
I had another look into the Microsoft Examples and finally worked it out using this code:
DispatcherTimer timer;
internal void Regions_Invalidated(CanvasVirtualControl sender, CanvasRegionsInvalidatedEventArgs args)
{
// Configure the Mandelbrot effect to position and scale its output.
float baseScale = 0.005f;
float scale = (baseScale * 96 / sender.Dpi) / (helper._modifiers[1] / 1000f);
var controlSize = baseScale * sender.Size.ToVector2() * scale;
Vector2 translate = (baseScale * sender.Size.ToVector2() * new Vector2(-0.5f,-0f));
_effectMandel.Properties["scale"] = scale;
_effectMandel.Properties["translate"] = (Microsoft.Graphics.Canvas.Numerics.Vector2)translate;
#endif
// Draw the effect to whatever regions of the CanvasVirtualControl have been invalidated.
foreach (var region in args.InvalidatedRegions)
{
using (var drawingSession = sender.CreateDrawingSession(region))
{
drawingSession.DrawImage(_effectMandel);
}
}
// start timer for fps
this.timer = new DispatcherTimer();
int fps = 60;
this.timer.Interval = new TimeSpan(0, 0, 0, 0, 100 / fps);
this.timer.Tick += timer_Tick;
this.timer.Start();
}
private void timer_Tick(object sender, object e)
{
this.timer.Stop();
_canvas.Invalidate();
}
Hope this is helpful to someone.
I'm using a simple attenuation algorithm to darken walls based on their distance from light sources.
The end goal is to develop a light-mapping system in which the brightness for each wall is calculated in a pre-pass (including shadowing from other walls), and then that light-map image is blended with the wall texture.
+ =
Besides shadowing, I have the light-maps working, and the result replicate the shader code exactly. The problem is it is slow, and adding raycasted shadow checking is only going to make it worse.
My question is this, how can I perform these calculations on the GPU? Is a third party library/module required, or can it be done natively through OpenGL (OpenTK in my case)?
Alternatively, I'd be happy to switch to deferred rendering/lighting with cube shadow mapping but I'm yet to come across any information I can get my head around.
c# lightmap (run once for each wall)
public void createLightMap()
{
// Determine Light Map dimensions
int LightMapSize = 300;
int w = (int)(this.Width * LightMapSize);
int h = (int)(this.Height * LightMapSize);
// Create Bitmap
Bitmap bitmap = new Bitmap(w, h);
// Fragment testing
Vector3 fragmentPosition = new Vector3(this.x2, this.Height, this.z2);
float xIncement = (1f / LightMapSize) * ((x2 - x) / this.Width);
float zIncement = (1f / LightMapSize) * ((z2 - z) / this.Width);
float yIncement = (1f / LightMapSize);
// Calculate Light value for each pixel
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++)
{
// Update fragment position
fragmentPosition.X = this.x2 - xIncement -(xIncement * x);
fragmentPosition.Z = this.z2 - (zIncement * x);
fragmentPosition.Y = this.Height - (yIncement * y);
Vector3 totalDiffuse = Vector3.Zero;
// Iterate through the lights
for (int n = 0; n < 2; n++)
{
Light light = Game.lights[n];
Vector3 LightPosition = new Vector3(light.Position);
Vector3 Attenuation = new Vector3(light.Attenuation);
Vector3 Colour = new Vector3(light.Colour);
Vector3 toLightVector = LightPosition - fragmentPosition;
// Return early if wall is facing away from light
if (Vector3.Dot(this.normalVector, toLightVector.Normalized()) < 0)
continue;
// Calculate vector length (aka, distance from lightsource)
float distance = (float)Math.Sqrt(toLightVector.X * toLightVector.X + toLightVector.Y * toLightVector.Y + toLightVector.Z * toLightVector.Z);
// Attenuation
float attFactor = Attenuation.X + (Attenuation.Y * distance) + (Attenuation.Z * distance * distance);
Vector3 diffuse = Colour / attFactor;
totalDiffuse += diffuse;
}
// Create bitmap
var r = (int)(totalDiffuse.X * 256);
var g = (int)(totalDiffuse.Y * 256);
var b = (int)(totalDiffuse.Z * 256);
r = Math.Min(r, 255);
g = Math.Min(g, 255);
b = Math.Min(b, 255);
// Set Pixel
bitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
this.LightMapTextureID = Texture.loadImage(bitmap);
}
Fragment shader (an alternative to above light-mapping, creating the same effect)
#version 330
precision highp float;
in vec2 frag_texcoord;
in vec3 toLightVector[8];
uniform sampler2D MyTexture0;
uniform vec3 LightColour[8];
uniform vec3 LightAttenuation[8];
uniform float NumberOfLights;
out vec4 finalColor;
void main(void)
{
vec3 totalDiffuse;
for (int i=0; i<NumberOfLights; i++) {
{
float distance = length(toLightVector[i]);
float attFactor = LightAttenuation[i].x + (LightAttenuation[i].y * distance) + (LightAttenuation[i].z * distance * distance);
vec3 diffuse = (LightColour[i]) / attFactor;
totalDiffuse += diffuse;
}
finalColor = vec4(totalDiffuse, 1.0) * texture(MyTexture0, frag_texcoord)
}
}
I'm writing a Level Editor in C# and OpenTK, and wanted to see if a more complex shader would work fine. So I grabbed this mine craft shader here https://www.shadertoy.com/view/MdlGz4.
But I can't get it to work, I keep getting this error:
Failed to link shader program!
Fragment info
-------------
Internal error: assembly compile error for fragment shader at offset 392911:
-- error message --
line 16405, column 1: error: too many instructions
-- internal assembly text --
!!NVfp5.0
OPTION NV_bindless_texture;
OPTION NV_shader_atomic_float;
# cgc version 3.1.0001, build date Feb 9 2013
# command line args:
#vendor NVIDIA Corporation
#version 3.1.0.1
#profile gp5fp
The shadertoy version runs fine in my browser. So I know my hardware (GTX 680) can handle it. I'm using #version 400 in the fragment shader, in the hope that a higher version allows for more instructions. But that did not help either.
So my question is, how do I have to load/compile such a long fragment shader?
Here's the actual shader that I'm trying to run:
Vertex:
#version 400
uniform mat4 camera;
uniform mat4 model;
in vec3 in_vertex;
in vec4 in_color;
in vec2 in_uv;
out vec2 frag_TexCoord;
out vec4 frag_Color;
void main()
{
gl_Position = camera * model * vec4(in_vertex, 1);
frag_TexCoord = in_uv;
frag_Color = in_color;
}
Fragment:
#version 400
uniform vec2 iResolution;
uniform float iGlobalTime;
in vec4 frag_Color;
in vec2 frag_TexCoord;
out vec4 final_color;
// Created by Reinder Nijhoff 2013
//
// port of javascript minecraft: http://jsfiddle.net/uzMPU/
// original code by Markus Persson: https://twitter.com/notch/status/275331530040160256
float hash( float n ) {
return fract(sin(n)*43758.5453);
}
// port of minecraft
bool getMaterialColor( int i, vec2 coord, out vec3 color ) {
// 16x16 tex
vec2 uv = floor( coord );
float n = uv.x + uv.y*347.0 + 4321.0 * float(i);
float h = hash(n);
float br = 1. - h * (96./255.
);
color = vec3( 150./255., 108./255., 74./255.); // 0x966C4A;
if (i == 4) {
color = vec3( 127./255., 127./255., 127./255.); // 0x7F7F7F;
}
float xm1 = mod((uv.x * uv.x * 3. + uv.x * 81.) / 4., 4.);
if (i == 1) {
if( uv.y < (xm1 + 18.)) {
color = vec3( 106./255., 170./255., 64./255.); // 0x6AAA40;
} else if (uv.y < (xm1 + 19.)) {
br = br * (2. / 3.);
}
}
if (i == 7) {
color = vec3( 103./255., 82./255., 49./255.); // 0x675231;
if (uv.x > 0. && uv.x < 15.
&& ((uv.y > 0. && uv.y < 15.) || (uv.y > 32. && uv.y < 47.))) {
color = vec3( 188./255., 152./255., 98./255.); // 0xBC9862;
float xd = (uv.x - 7.);
float yd = (mod(uv.y, 16.) - 7.);
if (xd < 0.)
xd = 1. - xd;
if (yd < 0.)
yd = 1. - yd;
if (yd > xd)
xd = yd;
br = 1. - (h * (32./255.) + mod(xd, 4.) * (32./255.));
} else if ( h < 0.5 ) {
br = br * (1.5 - mod(uv.x, 2.));
}
}
if (i == 5) {
color = vec3( 181./255., 58./255., 21./255.); // 0xB53A15;
if ( mod(uv.x + (floor(uv.y / 4.) * 5.), 8.) == 0. || mod( uv.y, 4.) == 0.) {
color = vec3( 188./255., 175./255., 165./255.); // 0xBCAFA5;
}
}
if (i == 9) {
color = vec3( 64./255., 64./255., 255./255.); // 0x4040ff;
}
float brr = br;
if (uv.y >= 32.)
brr /= 2.;
if (i == 8) {
color = vec3( 80./255., 217./255., 55./255.); // 0x50D937;
if ( h < 0.5) {
return false;
}
}
color *= brr;
return true;
}
int getMap( vec3 pos ) {
vec3 posf = floor( (pos - vec3(32.)) );
float n = posf.x + posf.y*517.0 + 1313.0*posf.z;
float h = hash(n);
if( h > sqrt( sqrt( dot( posf.yz, posf.yz )*0.16 ) ) - 0.8 ) {
return 0;
}
return int( hash( n * 465.233 ) * 16. );
}
vec3 renderMinecraft( vec2 uv ) {
float xRot = sin( iGlobalTime*0.5 ) * 0.4 + (3.1415 / 2.);
float yRot = cos( iGlobalTime*0.5 ) * 0.4;
float yCos = cos(yRot);
float ySin = sin(yRot);
float xCos = cos(xRot);
float xSin = sin(xRot);
vec3 opos = vec3( 32.5 + iGlobalTime * 6.4, 32.5, 32.5 );
float gggxd = (uv.x - 0.5) * (iResolution.x / iResolution.y );
float ggyd = (1.-uv.y - 0.5);
float ggzd = 1.;
float gggzd = ggzd * yCos + ggyd * ySin;
vec3 _posd = vec3( gggxd * xCos + gggzd * xSin,
ggyd * yCos - ggzd * ySin,
gggzd * xCos - gggxd * xSin );
vec3 col = vec3( 0. );
float br = 1.;
vec3 bdist = vec3( 255. - 100., 255. - 0., 255. - 50. );
float ddist = 0.;
float closest = 32.;
for ( int d = 0; d < 3; d++) {
float dimLength = _posd[d];
float ll = abs( 1. / dimLength );
vec3 posd = _posd * ll;;
float initial = fract( opos[d] );
if (dimLength > 0.) initial = 1. - initial;
float dist = ll * initial;
vec3 pos = opos + posd * initial;
if (dimLength < 0.) {
pos[d] -= 1.;
}
for (int i=0; i<30; i++) {
if( dist > closest )continue;
//int tex = getMap( mod( pos, 64. ) );
int tex = getMap( pos );
if (tex > 0) {
vec2 texcoord;
texcoord.x = mod(((pos.x + pos.z) * 16.), 16.);
texcoord.y = mod((pos.y * 16.), 16.) + 16.;
if (d == 1) {
texcoord.x = mod(pos.x * 16., 16.);
texcoord.y = mod(pos.z * 16., 16.);
if (posd.y < 0.)
texcoord.y += 32.;
}
if ( getMaterialColor( tex, texcoord, col ) ) {
ddist = 1. - (dist / 32.);
br = bdist[d];
closest = dist;
}
}
pos += posd;
dist += ll;
}
}
return col * ddist * (br/255.);
}
void main()
{
vec2 uv = frag_TexCoord.xy / iResolution.xy;
final_color = vec4( renderMinecraft( uv ) ,1.0);
}
Clarification as to where the error happens:
The frist two steps of compiling the vertex and fragment shader work fine. It's the linking (GL.GetProgram()) that returns 0. The call to GL.GetProgramInfo returns the above mentioned error and lists the program in assembly code (# 19337 instructions, 8 R-regs). So it does have so many lines.
_vertexShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(_vertexShader, vertexProgram);
GL.CompileShader(_vertexShader);
GL.GetShader(_vertexShader, ShaderParameter.CompileStatus, out result);
if (result == 0)
{
System.Diagnostics.Debug.WriteLine(GL.GetString(StringName.ShadingLanguageVersion));
System.Diagnostics.Debug.WriteLine(GL.GetShaderInfoLog(_vertexShader));
}
//Create Fragment Shader
_fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(_fragShader, fragmentProgram);
GL.CompileShader(_fragShader);
GL.GetShader(_fragShader, ShaderParameter.CompileStatus, out result);
if (result == 0)
{
System.Diagnostics.Debug.WriteLine(GL.GetString(StringName.ShadingLanguageVersion));
System.Diagnostics.Debug.WriteLine(GL.GetShaderInfoLog(_fragShader));
}
//Link to program
_shader = GL.CreateProgram();
GL.AttachShader(_shader, _vertexShader);
GL.AttachShader(_shader, _fragShader);
GL.LinkProgram(_shader);
GL.GetProgram(_shader, ProgramParameter.LinkStatus, out result);
if (result == 0)
{
System.Diagnostics.Debug.WriteLine("Failed to link shader program!");
System.Diagnostics.Debug.WriteLine(GL.GetProgramInfoLog(_shader));
GL.DeleteProgram(_shader);
}