So, I'm trying to render my gameplay to a RenderTarget2D in XNA so I can apply shaders to the scene. It's working, to some extent, but anything that has was drawn with an alpha level other than 255 seems to be tinted purple. The alpha effect is working, but there is also a purple tint to it. I've tried looking around for a solution, and the only ones I can seem to find are either the full screen being rendered purple, or the alpha being replaced with purple.
My issue is not quite either of those...
This is a scene I threw up to show you what's going on. As you can see, the alpha effect is working, but the object is tinted purple.
Here's the part where I post my render code:
gameTarget = new RenderTarget2D(GraphicsDevice, (int)screenSize.X, (int)screenSize.Y, 1, SurfaceFormat.Color, RenderTargetUsage.PreserveContents);
gameDepthBuffer = new DepthStencilBuffer(GraphicsDevice, (int)screenSize.X, (int)screenSize.Y, GraphicsDevice.DepthStencilBuffer.Format);
This is the initialisation I'm using.
GraphicsDevice g = GraphicsDevice;
DepthStencilBuffer d = g.DepthStencilBuffer;
g.SetRenderTarget(0, gameTarget);
g.DepthStencilBuffer = gameDepthBuffer;
g.Clear(Color.Black);
GameBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
level.Draw(GameBatch);
GameBatch.End();
g.SetRenderTarget(0, null);
g.DepthStencilBuffer = d;
GameBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
if (renderEffect != null)
{
renderEffect.Begin();
renderEffect.CurrentTechnique.Passes[0].Begin();
}
Sprite.Draw(GameBatch, gameTarget.GetTexture(), new Rectangle(0, 0, (int)assumedSize.X, (int)assumedSize.Y), Color.White);
if (renderEffect != null)
{
renderEffect.CurrentTechnique.Passes[0].End();
renderEffect.End();
}
GameBatch.End();
renderEffect is the effect file, Sprite is class that deal with drawing relative to an assumed screen size (to cope with varying resolutions).
I'm working in XNA 3.1. I know I should be using 4.0 by now, but I'm not because I have book on 3.1, which is helpful in certain circumstances.
Anyway, some help here would be greatly appreciated...
Generally purple is the default color to which RenderTarget are cleared.
With that in mind, I see that you are not clearing the Back Buffer, after setting the render target to null. So your code should look like:
g.SetRenderTarget(0, null);
g.Clear(Color.Transparent);//or black
Fixed! I needed to set some alpha parameters:
GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = true;
GraphicsDevice.RenderState.AlphaDestinationBlend = Blend.One;
GraphicsDevice.RenderState.AlphaSourceBlend = Blend.SourceAlpha;
GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
Related
I've managed to save a 3D object's position, rotation, scale, color, and shape. However, when I try to load the object, the color doesn't display; but everything else is working fine. I tried using "newObject.GetComponent().material.color = colorOfObject" via a peer's suggestion, but the compiler doesn't like the syntax. Am I on the right track?
Note: I just included my code for the cube option to provide a shorter block of code, but I do have other shape options that the user can choose.
// Saving
if (GUI.Button(new Rect(700, 330, 50, 30), "Save"))
{
// Saving the object's color and resetting it to white
Color colorOfObject = rend.material.GetColor("_Color");
PlayerPrefs.SetFloat("rValue", colorOfObject.r);
PlayerPrefs.SetFloat("gValue", colorOfObject.g);
PlayerPrefs.SetFloat("bValue", colorOfObject.b);
rend.material.SetColor("_Color", Color.white);
}
// Loading
if (GUI.Button(new Rect(770, 330, 50, 30), "Load"))
{
GameObject newObject;
if (PlayerPrefs.GetString("Shape") == "cube")
{
newObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
newObject.AddComponent<cubeControls>();
newObject.transform.position = new Vector3(PlayerPrefs.GetFloat("xCoord"), PlayerPrefs.GetFloat("yCoord"), PlayerPrefs.GetFloat("zCoord"));
newObject.transform.rotation = Quaternion.Euler(PlayerPrefs.GetFloat("xRot"), PlayerPrefs.GetFloat("yRot"), PlayerPrefs.GetFloat("zRot"));
newObject.transform.localScale = new Vector3(PlayerPrefs.GetFloat("xScale"), PlayerPrefs.GetFloat("yScale"), PlayerPrefs.GetFloat("zScale"));
Color defaultColor = Color.white;
Color colorOfObject = new Color(PlayerPrefs.GetFloat("rValue", defaultColor.r), PlayerPrefs.GetFloat("gValue", defaultColor.g), PlayerPrefs.GetFloat("bValue", defaultColor.b));
//rend.material.SetColor("_Color", colorOfObject);
newObject.GetComponent().material.color = colorOfObject;
Destroy(gameObject);
}
If the material of the object is using a shader who doesn't have the "_Color" property then it will be ignored. Some included shaders in Unity use "_TintColor", other just don't support any coloring.
nb: your method is going to generate a new material instance, and thus a new drawcall for each object. Have a look at MaterialPropertyBlocks and use a GPU instancing enabled shader/material setup.
Ah, I found some other examples and I realized that it should be:
newObject.GetComponent<Renderer>().material.color = colorOfObject;
But thanks to everyone who helped!
I am playing around with the Microsoft Vision API and learning C# as I go, and one of the properties of a Vision object is an "Accent Color" of the image.
From a series of images analysed, I want to show those colors ordered in a Linear Gradient -- because that will be able to show the user that most pictures are (for example) blue, because Blue colors take up half of the gradient etc.
I have this working, in that I am ordering the Colors by Hue, and able to produce a Linear Gradient I am filling into a Bitmap.
BUT, the gradient by default is Horizontal, and I need Vertical -- so I've used LinearGradientBrush.RotateTransform(90) which rotates that actual gradient fine, but doesn't seem to fill the entire Rectangle, and it repeats. This is what I'm getting as a result:
How do I create a Vertical LinearGradient that fills up the entire Height of the Rectangle object for my Bitmap?
Here is my code:
private Bitmap CreateColorGradient(System.Drawing.Rectangle rect, System.Drawing.Color[] colors)
{
Bitmap gradient = new Bitmap(rect.Width, rect.Height);
LinearGradientBrush br = new LinearGradientBrush(rect, System.Drawing.Color.White, System.Drawing.Color.White, 0, false);
ColorBlend cb = new ColorBlend();
// Positions
List<float> positions = new List<float>();
for (int i = 0; i < colors.Length; i++) positions.Add((float)i / (colors.Length - 1));
cb.Positions = positions.ToArray();
cb.Colors = colors;
br.InterpolationColors = cb;
br.RotateTransform(90);
using (Graphics g = Graphics.FromImage(gradient))
g.FillRectangle(br, rect);
return gradient;
}
Thanks for reading and any help -- also if you see something in my code that could be done better please point it out it helps me learn :)
You are ignoring the angle parameter in the constructor. And as you instead do a rotation on the Grahics object your brush rectangle is no longer correctly fits the target bitmap and the gradient can't fill it; so it repeats.
To correct
simply set the angle to 90 and
remove the br.RotateTransform(90); call.
Here this changes the result from the left to the middle version:
While we're looking at it, do take note of the WrapMode property of LinearGradientBrush. What you see in the first image is the default WrapMode.Clamp. Often a changing to one of the Flip mode helps.. So lets have a look at the impact of it one the first version at the right position.
It looks like WrapMode.TileFlipY but since I have brought back the rotation it actually takes a value WrapMode.TileFlipX or WrapMode.TileFlipXY:
br.WrapMode = WrapMode.TileFlipX;
I am creating a XNA game and added the option to use the game in fullscreen or windowed.
// full screen on
if (optionsMenu.buttonWithIndexPressed(7) && !game.graphics.IsFullScreen)
{
game.settings.fullScreen = true;
game.graphics.ToggleFullScreen();
}
//fullscreen off
if (optionsMenu.buttonWithIndexPressed(8) && game.graphics.IsFullScreen)
{
game.settings.fullScreen = false;
game.graphics.ToggleFullScreen();
}
When I change this option, everything works fine except for the lag causing all the screen to go black for a few seconds. This lag is really bothering me. Is it possible one way or another, to reduce the time for the lag?
You could try doing a borderless window approach (even through such a thing is not truly supported in XNA) with the following (untested):
IntPtr hWnd = this.Window.Handle;
var control = System.Windows.Forms.Control.FromHandle( hWnd );
var form = control.FindForm();
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
form.WindowState = System.Windows.Forms.FormWindowState.Maximized;
However, your game is going to stutter for a moment whenever you resize, as the backbuffers will need to be re-initialized. There are hacky ways to avoid any hiccups on resizing, but not for going actually fullscreen, hence the borderless window reccommendation.
Also, keep your LoadContent() implementation as short as possible, and only load in what you need at the time. LoadContent() will be called every time your D3D (XNA) window changes context and will halt your game until it finishes reloading all resources, so consider loading your resources more dynamically.
Additional Info
Consider making a texture to which your game renders all passes. Then draw that final game texture (which is at your lower, desired resoloution) onto your actual backbuffer (which is your higher, screen resolution) with a very simple point sample shader.
//yourxnarenderclass.cs
graphicsDevice.SetRenderTarget(null); //targets your backbuffer, which should be your full screen resolution
yourEffect.Parameters["InputTexture"].SetValue(finalGameTexture);
yourEffect.CurrentTechnique = yourEffect.Techniques["Simple"];
foreach (EffectPass pass in yourEffect.CurrentTechnique.Passes)
{
pass.Apply();
quadRender.Render(Vector2.One * -1, Vector2.One);
}
To read more about rendering with quads, see Using a Basic Effect with Texturing (MSDN)
Your input sampler is standard:
//HLSL effect.fx
texture InputTexture;
sampler inputSampler = sampler_state
{
Texture = <InputTexture>;
MipFilter = Point;
MinFilter = Point;
MagFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
And your pixel shader:
VS_OUTPUT FullScreenVS( float3 InPos : POSITION,
float2 InTex : TEXCOORD0)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
// Offset the position by half a pixel to correctly align texels to pixels
Out.Position = float4(InPos,1) + 0.5f* float4(-1.0f/renderTargetSize.x, 1.0f/renderTargetSize.y, 0, 0);
Out.TexCoords = InTex;
return Out;
}
This is tried and tested. There's more code involved, but it's too complex to go into detail here. I suggest reading up on how to implement your own Effects in XNA so the code above will make more sense in context.
In my project, I need to get the brightness of the screen that is being displayed. to do that, I get a snapshot of the screen and make it as a Texture2D
To get the snapshot and convert it I use this:
public void GetScreen(ref Texture2D screenShot){
RenderTexture rt = new RenderTexture(Screen.Width, Screen.Height, 24);
camera.targetTexture = rt;
screenShot = new Texture2D(Screen.Width, Screen.Height, TextureFormat.RGB24, false);
camera.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, Sreen.Width, Screen.Height), 0, 0);
camera.targetTexture = null;
RenderTexture.active = null;
Destroy(rt);
}
but I still need to get the brightness.
Any suggestions will be accepted (about the brightness and/or about the conversion).
Thanks in advance.
Once you have the pixels, the next step is to use get pixels on the image to sample some of them and build the brightness from them:
http://docs.unity3d.com/Documentation/ScriptReference/Texture2D.GetPixel.html
Determining brightness is a bit of a complex issue, so it really depends on your application. Formula to determine brightness of RGB color has methods to determine the brightness of a single pixel. You could sample several pixels towards the center of your image, and then take the average of those.
If you need a more complex solution, you could build a histogram of all the pixels brightness, and then find the peak. http://en.wikipedia.org/wiki/Image_histogram .
I'm currently working my way through "Beginning C# Programming", and have hit a problem in chapter 7 when drawing textures.
I have used the same code as on the demo CD, and although I had to change the path of the texture to be absolute, when rendered it is appearing grey.
I have debugged the program to write to file the loaded texture, and this is fine - no problems there. So something after that point is going wrong.
Here are some snippets of code:
public void InitializeGraphics()
{
// set up the parameters
Direct3D.PresentParameters p = new Direct3D.PresentParameters();
p.SwapEffect = Direct3D.SwapEffect.Discard;
...
graphics = new Direct3D.Device( 0, Direct3D.DeviceType.Hardware, this,
Direct3D.CreateFlags.SoftwareVertexProcessing, p );
...
// set up various drawing options
graphics.RenderState.CullMode = Direct3D.Cull.None;
graphics.RenderState.AlphaBlendEnable = true;
graphics.RenderState.AlphaBlendOperation = Direct3D.BlendOperation.Add;
graphics.RenderState.DestinationBlend = Direct3D.Blend.InvSourceAlpha;
graphics.RenderState.SourceBlend = Direct3D.Blend.SourceAlpha;
...
}
public void InitializeGeometry()
{
...
texture = Direct3D.TextureLoader.FromFile(
graphics, "E:\\Programming\\SharpDevelop_Projects\\AdvancedFrameworkv2\\texture.jpg", 0, 0, 0, 0, Direct3D.Format.Unknown,
Direct3D.Pool.Managed, Direct3D.Filter.Linear,
Direct3D.Filter.Linear, 0 );
...
}
protected virtual void Render()
{
graphics.Clear( Direct3D.ClearFlags.Target, Color.White , 1.0f, 0 );
graphics.BeginScene();
// set the texture
graphics.SetTexture( 0, texture );
// set the vertex format
graphics.VertexFormat = Direct3D.CustomVertex.TransformedTextured.Format;
// draw the triangles
graphics.DrawUserPrimitives( Direct3D.PrimitiveType.TriangleStrip, 2, vertexes );
graphics.EndScene();
graphics.Present();
...
}
I can't figure out what is going wrong here. Obviously if I load up the texture in windows it displays fine - so there's something not right in the code examples given in the book. It doesn't actually work, and there must be something wrong with my environment presumably.
You're using a REALLY old technology there... I'm guessing you're trying to make a game (as we all did when we started out!), try using XNA. My best guess is that it's your graphics driver. I know that sounds like a cop out, but seriously, I've seen this before and once I swapped out my old graphics card for a new one it worked! I'm not saying it's broken, or that it's impossible to get it to work. But my best two suggestions would be to:
1) Start using XNA and use the tutorials on http://www.xnadevelopment.com/tutorials.shtml
2) Replace your graphics card (if you want to carry on with what you are doing now).