The sample
If you watch the code, I'm interested in refraction.fx, and in void DrawRefractGlacier(GameTime gameTime) function. Here you can notice that the function uses a texture to render water distortion on an image (waterfall.jpg as "distorter image", and glacier.jpg as distorted image).
If you read inside refraction.fx, at the beginning it says:
// Effect uses a scrolling displacement texture to offset the position of the main
// texture. Depending on the contents of the displacement texture, this can give a
// wide range of refraction, rippling, warping, and swirling type effects.
It seems that would be easy to achieve another effect by changing the image. I tried that with an image like this:
I want to achieve the effect of distorting everything around as a rotating whirl, or a spiral. How can I do that?
Some simple sequential screen of how it looks with my texture:
Refraction shader:
// Effect uses a scrolling displacement texture to offset the position of the main
// texture. Depending on the contents of the displacement texture, this can give a
// wide range of refraction, rippling, warping, and swirling type effects.
float2 DisplacementScroll;
float2 angle;
sampler TextureSampler : register(s0);
sampler DisplacementSampler : register(s1);
float2x2 RotationMatrix(float rotation)
{
float c = cos(rotation);
float s = sin(rotation);
return float2x2(c, -s, s ,c);
}
float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float2 rotated_texcoord = texCoord;
rotated_texcoord -= float2(0.25, 0.25);
rotated_texcoord = mul(rotated_texcoord, RotationMatrix(angle));
rotated_texcoord += float2(0.25, 0.25);
float2 DispScroll = DisplacementScroll;
// Look up the displacement amount.
float2 displacement = tex2D(DisplacementSampler, DispScroll+ texCoord / 3);
// Offset the main texture coordinates.
texCoord += displacement * 0.2 - 0.15;
// Look up into the main texture.
return tex2D(TextureSampler, texCoord) * color;
}
technique Refraction
{
pass Pass1
{
PixelShader = compile ps_2_0 main();
}
}
Its draw call:
void DrawRefractGlacier(GameTime gameTime)
{
// Set an effect parameter to make the
// displacement texture scroll in a giant circle.
refractionEffect.Parameters["DisplacementScroll"].SetValue(
MoveInCircle(gameTime, 0.2f));
// Set the displacement texture.
graphics.GraphicsDevice.Textures[1] = waterfallTexture;
// Begin the sprite batch.
spriteBatch.Begin(0, null, null, null, null, refractionEffect);
// Because the effect will displace the texture coordinates before
// sampling the main texture, the coordinates could sometimes go right
// off the edges of the texture, which looks ugly. To prevent this, we
// adjust our sprite source region to leave a little border around the
// edge of the texture. The displacement effect will then just move the
// texture coordinates into this border region, without ever hitting
// the edge of the texture.
Rectangle croppedGlacier = new Rectangle(32, 32,
glacierTexture.Width - 64,
glacierTexture.Height - 64);
spriteBatch.Draw(glacierTexture,
GraphicsDevice.Viewport.Bounds,
croppedGlacier,
Color.White);
// End the sprite batch.
spriteBatch.End();
}
Related
I'm working on my volume rendering application (C# + OpenTK).
The volume is being rendered using raycasting, i found a lot of inspiration on this site:
http://graphicsrunner.blogspot.sk/2009/01/volume-rendering-101.html, and even though my applications works with OpenGL, the main idea of using 3D texture and other stuff is the same.
Application works fine, but after I "flow into the volume" (means inside the bounding box), everything dissapears, and I want to prevent this. So is there some easy way to do this? --> I will be able to flow through the volume or move in the volume.
Here is the code of fragment shader:
#version 330
in vec3 EntryPoint;
in vec4 ExitPointCoord;
uniform sampler2D ExitPoints;
uniform sampler3D VolumeTex;
uniform sampler1D TransferFunc;
uniform float StepSize;
uniform float AlphaReduce;
uniform vec2 ScreenSize;
layout (location = 0) out vec4 FragColor;
void main()
{
//gl_FragCoord --> http://www.txutxi.com/?p=182
vec3 exitPoint = texture(ExitPoints, gl_FragCoord.st/ScreenSize).xyz;
//background need no raycasting
if (EntryPoint == exitPoint)
discard;
vec3 rayDirection = normalize(exitPoint - EntryPoint);
vec4 currentPosition = vec4(EntryPoint, 0.0f);
vec4 colorSum = vec4(.0f,.0f,.0f,.0f);
vec4 color = vec4(0.0f,0.0f,0.0f,0.0f);
vec4 value = vec4(0.0f);
vec3 Step = rayDirection * StepSize;
float stepLength= length(Step);
float LengthSum = 0.0f;
float Length = length(exitPoint - EntryPoint);
for(int i=0; i < 16000; i++)
{
currentPosition.w = 0.0f;
value = texture(VolumeTex, currentPosition.xyz);
color = texture(TransferFunc, value.a);
//reduce the alpha to have a more transparent result
color.a *= AlphaReduce;
//Front to back blending
color.rgb *= color.a;
colorSum = (1.0f - colorSum.a) * color + colorSum;
//accumulate length
LengthSum += stepLength;
//break from the loop when alpha gets high enough
if(colorSum.a >= .95f)
break;
//advance the current position
currentPosition.xyz += Step;
//break if the ray is outside of the bounding box
if(LengthSum >= Length)
break;
}
FragColor = colorSum;
}
The code below is based on https://github.com/toolchainX/Volume_Rendering_Using_GLSL
Display() function:
public void Display()
{
// the color of the vertex in the back face is also the location
// of the vertex
// save the back face to the user defined framebuffer bound
// with a 2D texture named `g_bfTexObj`
// draw the front face of the box
// in the rendering process, i.e. the ray marching process
// loading the volume `g_volTexObj` as well as the `g_bfTexObj`
// after vertex shader processing we got the color as well as the location of
// the vertex (in the object coordinates, before transformation).
// and the vertex assemblied into primitives before entering
// fragment shader processing stage.
// in fragment shader processing stage. we got `g_bfTexObj`
// (correspond to 'VolumeTex' in glsl)and `g_volTexObj`(correspond to 'ExitPoints')
// as well as the location of primitives.
// draw the back face of the box
GL.Enable(EnableCap.DepthTest);
//"vykreslim" front || back face objemu do framebuffru --> teda do 2D textury s ID bfTexID
//(pomocou backface.frag &.vert)
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
GL.Viewport(0, 0, width, height);
LinkShader(spMain.GetProgramHandle(), bfVertShader.GetShaderHandle(), bfFragShader.GetShaderHandle());
spMain.UseProgram();
//cull front face
Render(CullFaceMode.Front);
spMain.UseProgram(0);
//klasicky framebuffer --> "obrazovka"
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
GL.Viewport(0, 0, width, height);
LinkShader(spMain.GetProgramHandle(), rcVertShader.GetShaderHandle(), rcFragShader.GetShaderHandle());
spMain.UseProgram();
SetUniforms();
Render(CullFaceMode.Back);
spMain.UseProgram(0);
GL.Disable(EnableCap.DepthTest);
}
private void DrawBox(CullFaceMode mode)
{
// --> Face culling allows non-visible triangles of closed surfaces to be culled before expensive Rasterization and Fragment Shader operations.
GL.Enable(EnableCap.CullFace);
GL.CullFace(mode);
GL.BindVertexArray(VAO);
GL.DrawElements(PrimitiveType.Triangles, 36, DrawElementsType.UnsignedInt, 0);
GL.BindVertexArray(0);
GL.Disable(EnableCap.CullFace);
spMain.UseProgram(0);//zapnuty bol v Render() ktora DrawBox zavolala
}
private void Render(CullFaceMode mode)
{
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
spMain.UseProgram();
spMain.SetUniform("modelViewMatrix", Current);
spMain.SetUniform("projectionMatrix", projectionMatrix);
DrawBox(mode);
}
The problem is (I think) that as I'm moving towards the volume (I don't move the camera, just scaling the volume), if the scale factor > 2.7something, I'm in the volume, it means "after the plane on which is the final picture being rendered", so a can't see anything.
The solution (maybe) that I can think of, is something like that:
If I reach the scale factor = 2.7something:
1.) -> don't scale the volume
2.) -> somehow told to fragment shader to move EntryPoint towards the
RayDirection for some length (probably based on the scale factor).
Now, I tried this "method" and it seems that it can work:
vec3 entryPoint = EntryPoint + some_value * rayDirection;
The some_value have to be clamped between [0,1[ interval (or [0,1]?)
, but maybe it doesn't matter thank's to that:
if (EntryPoint == exitPoint)
discard;
So now, maybe (if my solution isn't so bad), I can change my answer to this:
How to compute the some_value (based on scale factor which I send to fragment shader)?
if(scale_factor < 2.7something)
work like before;
else
{
compute some_value; //(I need help with this part)
change entry point;
work like before;
}
(I'm not native english speeker, so If there are some big mistakes in the text and you don't understand something, just let me know and I'll try to fix these bugs)
Thank's.
I solved my problem. It doesn't make "being surrounded by the volume" illusion, but now, I can flow through the volume and nothing disappears.
This is the code of my solution added to fragment shader:
vec3 entryPoint = vec3(0.0f);
if(scaleCoeff >= 2.7f)
{
float tmp = min((scaleCoeff - 2.7f) * 0.1f, 1.0f);
entryPoint = EntryPoint + tmp * (exitPoint - EntryPoint);
}
else
{
entryPoint = EntryPoint;
}
//
But if you know or can think about better solution that makes the "being surrounded by the volume" effect, I'll be glad if you let me know.
Thank you.
If understand correctly, I think you should use Plane Clipping to go through the volume. (I could give you a simple example based on your code if you attach this solution. Translate the whole C++ project to C# is too time-consuming.)
I want to draw a simple line. So I have this code as shown below. But when I run the code I can't see anything on the form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
drawLine();
}
private void drawLine() {
GL.glClear(GL.GL_COLOR_BUFFER_BIT);
GL.glBegin(GL.GL_LINES);
GL.glVertex3f(100.0f, 100.0f, 0.0f); // origin of the line
GL.glVertex3f(200.0f, 140.0f, 5.0f); // ending point of the line
GL.glEnd();
}
}
What should I do?
The default state of OpenGL assumes a viewport size that's equal to the size of the window the context was first attached to. All matrices are identity. So you're effectively drawing in so called normalized device coordinates (NDC) space. In that space the visible viewport has a coordinate range of [-1; 1] in either direction.
Your naive code assumes vertex positions to be in units of pixels. However everything outside the range [-1; 1] lies outside the screen and your "pixel coordinates" are way outside the visible viewport. What you must do is set viewport and projection so that they match your window size, if you want to use pixels as coordinate units.
private void drawLine() {
GL.glViewport(0, 0, window_width, window_height);
GL.glMatrixMode(GL_PROJECTION);
GL.glLoadIdentity();
GL.glOrtho(0, window_width, 0, window_height, -1, 1);
GL.glMatrixMode(GL_MODELVIEW);
GL.glLoadIdentity();
GL.glClear(GL.GL_COLOR_BUFFER_BIT);
GL.glBegin(GL.GL_LINES);
GL.glVertex3f(100.0f, 100.0f, 0.0f); // origin of the line
GL.glVertex3f(200.0f, 140.0f, 5.0f); // ending point of the line
GL.glEnd();
GL.glFlush();
this.SwapBuffer(); // if the form doesn't automatically swap
}
i got 2 dynamic texture ,and want add second texture color to first texture color But just where first texture color alpha is not 0
something like inverse transparncey
i add two pic link to show what is my mean:
TO
just collisions part must add two texture pixel color
ty for your help
Maybe using BlendState.Additive wil be enough for you.
or maybe it can be achieved with a custom BlendState.. but I have not experience with this...
or you can make a shader, you should note that you have to quads:
Quad with a rag doll. (Qrd)
Quad with a circle. (Qc)
you draw Qc over Qrd...
so you have to traduce the texture coordinates that you get in the pixel shader that owns to Qc to texture cordinates at Qrd space...
then you sample the color from Qrd texture,
and if alpha is near zero you clip the pixel...
else you return the sample from Qrc texture
just did it , works great
sampler circleSampler : register(s1);
sampler playerSampler : register(s0);
float4 main(float4 color : COLOR0 ,float2 texCoord : TEXCOORD0):COLOR0
{
float4 output = float4(1,1,1,1);
float4 CircColor = tex2D(circleSampler,texCoord);
float4 playerColor = tex2D(playerSampler,texCoord);
if (CircColor.a ==0)
{
output = playerColor;
}
else
{
output = CircColor* playerColor;
}
output.a = playerColor.a;
return output;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 main();
}
}
anyway ty for ur time
Hello everyone I'm currently trying to create a deferred renderer for my graphics engine using c# and SlimDX. As a resource I use this tutorial which is very helpful eventhough it's intended for XNA.
But right now I'm stuck...
I have my renderer set up to draw all geometry's color, normals and depth to seperate render target textures. This works. I can draw the resulting textures to the restored backbuffer as sprites and I can see that they contain just what they are supposed to. But when I try to pass those Textures to another shader, in this case to create a light map, weirds things happen. Here's how I draw one frame:
public bool RenderFrame(FrameInfo fInfo){
if(!BeginRender()) //checks Device, resizes buffers, calls BeginScene(), etc.
return false;
foreach(RenderQueue queue in fInfo.GetRenderQueues()){
RenderQueue(queue);
}
EndRender(); //currently only calls EndScene, used to do more
ResolveGBuffer();
DrawDirectionalLight(
new Vector3(1f, -1f, 0),
new Color4(1f,1f,1f,1f),
fi.CameraPosition,
SlimMath.Matrix.Invert(fi.ViewProjectionMatrix));
}
private void ResolveGBuffer() {
if(DeviceContext9 == null || DeviceContext9.Device == null)
return;
DeviceContext9.Device.SetRenderTarget(0, _backbuffer);
DeviceContext9.Device.SetRenderTarget(1, null);
DeviceContext9.Device.SetRenderTarget(2, null);
}
private void DrawDirectionalLight(Vector3 lightDirection, Color4 color, SlimMath.Vector3 cameraPosition, SlimMath.Matrix invertedViewProjection) {
if(DeviceContext9 == null || DeviceContext9.Device == null)
return;
DeviceContext9.Device.BeginScene();
_directionalLightShader.Shader.SetTexture(
_directionalLightShader.Parameters["ColorMap"],
_colorTexture);
_directionalLightShader.Shader.SetTexture(
_directionalLightShader.Parameters["NormalMap"],
_normalTexture);
_directionalLightShader.Shader.SetTexture(
_directionalLightShader.Parameters["DepthMap"],
_depthTexture);
_directionalLightShader.Shader.SetValue<Vector3>(
_directionalLightShader.Parameters["lightDirection"],
lightDirection);
_directionalLightShader.Shader.SetValue<Color4>(
_directionalLightShader.Parameters["Color"],
color);
_directionalLightShader.Shader.SetValue<SlimMath.Vector3>(
_directionalLightShader.Parameters["cameraPosition"],
cameraPosition);
_directionalLightShader.Shader.SetValue<SlimMath.Matrix>(
_directionalLightShader.Parameters["InvertViewProjection"],
invertedViewProjection);
_directionalLightShader.Shader.SetValue<Vector2>(
_directionalLightShader.Parameters["halfPixel"],
_halfPixel);
_directionalLightShader.Shader.Technique =
_directionalLightShader.Technique("Technique0");
_directionalLightShader.Shader.Begin();
_directionalLightShader.Shader.BeginPass(0);
RenderQuad(SlimMath.Vector2.One * -1, SlimMath.Vector2.One);
_directionalLightShader.Shader.EndPass();
_directionalLightShader.Shader.End();
DeviceContext9.Device.EndScene();
}
Now when I replace the call to DrawDirectionalLight with some code to draw _colorTexture, _normalTexture and _depthTexture to the screen everything looks ok, but when I use the DrawDirectionalLight function instead I see wild flickering. From the output of PIX it looks like my textures do not get passed to the shader correctly:
Following the tutorial the texture parameters and samplers are defined as follows:
float3 lightDirection;
float3 Color;
float3 cameraPosition;
float4x4 InvertViewProjection;
texture ColorMap;
texture NormalMap;
texture DepthMap;
sampler colorSampler = sampler_state{
Texture = ColorMap;
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter= LINEAR;
MinFilter= LINEAR;
MipFilter= LINEAR;
};
sampler depthSampler = sampler_state{
Texture = DepthMap;
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter= POINT;
MinFilter= POINT;
MipFilter= POINT;
};
sampler normalSampler = sampler_state{
Texture = NormalMap;
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter= POINT;
MinFilter= POINT;
MipFilter= POINT;
};
Now my big question is WHY? There are no error messages printed to debug output.
EDIT:
the rendertargets/textures are created like this:
_colorTexture = new Texture(DeviceContext9.Device,
DeviceContext9.PresentParameters.BackBufferWidth,
DeviceContext9.PresentParameters.BackBufferHeight,
1,
Usage.RenderTarget,
Format.A8R8G8B8,
Pool.Default);
_colorSurface = _colorTexture.GetSurfaceLevel(0);
_normalTexture = new Texture(DeviceContext9.Device,
DeviceContext9.PresentParameters.BackBufferWidth,
DeviceContext9.PresentParameters.BackBufferHeight,
1,
Usage.RenderTarget,
Format.A8R8G8B8,
Pool.Default);
_normalSurface = _normalTexture.GetSurfaceLevel(0);
_depthTexture = new Texture(DeviceContext9.Device,
DeviceContext9.PresentParameters.BackBufferWidth,
DeviceContext9.PresentParameters.BackBufferHeight,
1,
Usage.RenderTarget,
Format.A8R8G8B8,
Pool.Default);
_depthSurface = _depthTexture.GetSurfaceLevel(0);
EDIT 2:
The problems seems to lie in the directionalLightShader itselft since passing other regular textures doesn't work either.
The answer to my problem is as simple as the problem was stupid. The strange behaviour was caused by 2 different errors:
I was just looking at the wrong events in PIX. The textures we passed correctly to the shader but I didn't see it because it was 'hidden' in the BeginPass-event (behind the '+').
The pixel shader which I was trying to execute never got called because vertices of the fullscreen quad I used to render were drawn in clockwise order... my CullMode was also set to clockwise...
Thanks to everyone who read this question!
Trying to make a glow effect in xna but it doesn't show the glow or any change at all. Also my back color is purple instead of black and I can't change that either :
GraphicsDevice.Clear(Color.Black);
GraphicsDevice.SetRenderTarget(bulletRenderTarget);
spriteBatch.Begin();
foreach (Bullet bullet in bulletList)
{
Texture2D bulletTexture = textures[bullet.bulletType];
spriteBatch.Draw(
bulletTexture,
new Rectangle(
(int)bullet.position.X,
(int)bullet.position.Y,
bulletTexture.Width,
bulletTexture.Height
),
null,
Color.White,
MathHelper.ToRadians(bullet.angle),
new Vector2(
bulletTexture.Width / 2,
bulletTexture.Height / 2
),
SpriteEffects.None,
0
);
}
spriteBatch.End();
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.Black);
postProcessEffect.CurrentTechnique = postProcessEffect.Techniques["Blur"];
spriteBatch.Begin();
spriteBatch.Draw(
bulletRenderTarget,
new Vector2(0, 0),
Color.White
);
GraphicsDevice.BlendState = BlendState.Additive;
foreach (EffectPass pass in postProcessEffect.CurrentTechnique.Passes)
{
pass.Apply();
spriteBatch.Draw(
bulletRenderTarget,
new Vector2(0,0),
Color.White
);
}
DrawHud();
foreach (BaseEntity entity in entityList)
{
entity.Draw(gameTime);
}
spriteBatch.End();
I'm only trying to get the bullets to glow.
shader :
float BlurDistance = 0.002f;
sampler ColorMapSampler : register(s1);
float4 PixelShaderFunction(float2 Tex: TEXCOORD0) : COLOR
{
float4 Color;
// Get the texel from ColorMapSampler using a modified texture coordinate. This
// gets the texels at the neighbour texels and adds it to Color.
Color = tex2D( ColorMapSampler, float2(Tex.x+BlurDistance, Tex.y+BlurDistance));
Color += tex2D( ColorMapSampler, float2(Tex.x-BlurDistance, Tex.y-BlurDistance));
Color += tex2D( ColorMapSampler, float2(Tex.x+BlurDistance, Tex.y-BlurDistance));
Color += tex2D( ColorMapSampler, float2(Tex.x-BlurDistance, Tex.y+BlurDistance));
// We need to devide the color with the amount of times we added
// a color to it, in this case 4, to get the avg. color
Color = Color / 4;
// returned the blurred color
return Color;
}
technique Blur
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
The reason it's purple is because you have
GraphicsDevice.Clear(Color.Black);
GraphicsDevice.SetRenderTarget(bulletRenderTarget);
which should be the other way around, so changing that into
GraphicsDevice.SetRenderTarget(bulletRenderTarget);
GraphicsDevice.Clear(Color.Black);
fixes the purple problem, to fix the shader change the following in the fx file
sampler ColorMapSampler : register(s0);
And change your spriteBatch.Begin() into
spriteBatch.Begin(SpriteSortMode.Immediate, null);
Some extra info:
the s0 points to the first texture on the graphics device, which is the one that supplied by spriteBatch.Draw, if you want to use s1 you'd have to set it on the GraphicsDevice first by using:
GraphicsDevice.Textures[1] = bulletRenderTarget;
the SpriteSortMode.Immediate just forces the spriteBatch.Draw to draw the sprite immediately, if you don't set it it'll create a batch and draw them all at once, but this will be to late because it needs to be drawn when the EffectPass is being applied.
As for the blur you could lower the value of BlurDistance, but you'd have to try, you can also look up how to do a bloom shader, usually gives a nice effect too.