I'm using OpenTK and C#, I have defined a plane in 3D space as follows:
GL.Begin(BeginMode.Quads);
GL.Color3(Color.Magenta);
GL.Vertex3(-100.0f, -25.0f, -150.0f);
GL.Vertex3(-100.0f, -25.0f, 150.0f);
GL.Vertex3( 200.0f, -25.0f, 100.0f);
GL.Vertex3( 200.0f, -25.0f, -100.0f);
GL.End();
Can anyone please help me to make the plane transparent?
So you want something like this?
There are a lot of things to take care of to get there.
It all starts with a Color object that contains an alpha value<255. For example Color.FromArgb(85, Color.Turquoise) for the sphere below.
The main render class, sets up the camera view and renders all the lights, and then renders all the objects in the scene:
public void RenderOnView(GLControl control)
{
control.MakeCurrent();
var camera=views[control];
GL.Clear(ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);
GL.Disable(EnableCap.CullFace);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
camera.LookThrough();
if (EnableLights)
{
GL.LightModel(LightModelParameter.LightModelAmbient, new[] { 0.2f, 0.2f, 0.2f, 1f });
GL.LightModel(LightModelParameter.LightModelLocalViewer, 1);
GL.Enable(EnableCap.Lighting);
foreach (var light in lights)
{
light.Render();
}
}
else
{
GL.Disable(EnableCap.Lighting);
GL.ShadeModel(ShadingModel.Flat);
}
GL.Enable(EnableCap.LineSmooth); // This is Optional
GL.Enable(EnableCap.Normalize); // These is critical to have
GL.Enable(EnableCap.RescaleNormal);
for (int i=0; i<objects.Count; i++)
{
GL.PushMatrix();
objects[i].Render();
GL.PopMatrix();
}
control.SwapBuffers();
}
Then each object has a base rendering code Render(), which calls more specialized code Draw()
public void Render()
{
if (Shading==ShadingModel.Smooth)
{
GL.Enable(EnableCap.ColorMaterial);
GL.ColorMaterial(MaterialFace.FrontAndBack, ColorMaterialParameter.AmbientAndDiffuse);
GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Specular, SpecularColor);
GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, EmissionColor);
GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Shininess, Shinyness);
GL.Enable(EnableCap.Lighting);
}
else
{
GL.Disable(EnableCap.ColorMaterial);
GL.Disable(EnableCap.Lighting);
}
GL.ShadeModel(Shading);
GL.Translate(Position);
GL.Scale(Scale, Scale, Scale);
Draw(); // Draws triangles and quads to make up a shape
}
and for example to draw a quad surface you have
protected void DrawQuad(Color color, params Vector3[] nodes)
{
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.Enable(EnableCap.PolygonOffsetFill);
// special code when translucent
if (color.A<255)
{
GL.Enable(EnableCap.Blend);
GL.DepthMask(false);
}
GL.Begin(PrimitiveType.Quads);
GL.Color4(color); //this is where the color with alpha is used
for (int i=0; i<nodes.Length; i++)
{
GL.Vertex3(nodes[i]);
}
GL.End();
// special code when translucent
if (color.A<255)
{
GL.Disable(EnableCap.Blend);
GL.DepthMask(true);
}
}
also the code to draw the outline of a quad to be called after DrawQaud()
protected void DrawLineLoop(Color color, params Vector3[] nodes)
{
GL.Disable(EnableCap.PolygonOffsetFill);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
if (color.A<255)
{
GL.Enable(EnableCap.Blend);
GL.DepthMask(false);
}
GL.Begin(PrimitiveType.LineLoop);
GL.Color4(color);
for (int i=0; i<nodes.Length; i++)
{
GL.Vertex3(nodes[i]);
}
GL.End();
if (color.A<255)
{
GL.Disable(EnableCap.Blend);
GL.DepthMask(true);
}
}
Finally I found solution of my question:
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One);
GL.Enable(EnableCap.Blend);
//Definition of Plane
GL.Begin(BeginMode.Quads);
GL.Color4(0, 0.2, 1, 0.5);
GL.Vertex3(-100.0f, -25.0f, -150.0f);
GL.Vertex3(-100.0f, -25.0f, 150.0f);
GL.Vertex3( 200.0f, -25.0f, 100.0f);
GL.Vertex3( 200.0f, -25.0f, -100.0f);
GL.End();
GL.Disable(EnableCap.Blend);
In computing, Transparency effects are fained using color blending.For The special case of transprency, we talk about Àlpha Blending`
For transparency the blending factor is usualy stored in the 4th component of the colour (the A in RGBA) which stands for alpha. So you have to set all your colors with it.
example for half transparent blue (like glass):
GL.Color4(0,0,1,0.5f);
In OpenGL, blending have to be activated with the following command, which enable a supplementary stage on the rendering pipeline.
GL.Enable( EnableCap.Blend );
Then, because blending could be used to mix colors for other purpose than transparency, you have to specify the blending function to use. Here is the common function for transparency:
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
http://www.opentk.com/doc/chapter/2/opengl/fragment-ops/blending
Simply use GL.Color4 instead of GL.Color3. The 4th value will be the alpha
Related
I'm learning about OpenGL and I use C# for it.
I want to have a red cone and an opportunity to change its transparency.
This is what I do:
Gl.glColor4f(255, 0, 0, alpha);
Glut.glutSolidCone(cone.Radius, cone.Height, cone.Slices, cone.Stacks);
As a result I get something like this:
So it really is a cone but the color is just white (alpha = 1 when ran).
How to achieve the red color with an ability to make it transparent?
Thank you for your replies!
Finally, got a solution:
Gl.glEnable(Gl.GL_BLEND);
Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
Gl.glEnable(Gl.GL_COLOR_MATERIAL);
Gl.glColor4f(1.0f, 0, 0, alpha);
Glut.glutSolidCone(cone.Radius, cone.Height, cone.Slices, cone.Stacks);
So I have a Scroll Bar to change alpha parameter and the cone does change its transparency.
I hope this answer helps also.
The main render class, sets up the camera view and renders all the lights, and then renders all the objects in the scene:
public void RenderOnView(GLControl control)
{
control.MakeCurrent();
var camera = views[control];
GL.Clear(ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);
GL.Disable(EnableCap.CullFace);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
camera.LookThrough();
if (EnableLights)
{
GL.LightModel(LightModelParameter.LightModelAmbient, new[] { 0.2f, 0.2f, 0.2f, 1f });
GL.LightModel(LightModelParameter.LightModelLocalViewer, 1);
GL.Enable(EnableCap.Lighting);
foreach (var light in lights)
{
light.Render();
}
}
else
{
GL.Disable(EnableCap.Lighting);
GL.ShadeModel(ShadingModel.Flat);
}
GL.Enable(EnableCap.LineSmooth); // This is Optional
GL.Enable(EnableCap.Normalize); // These is critical to have
GL.Enable(EnableCap.RescaleNormal);
for (int i = 0; i<objects.Count; i++)
{
GL.PushMatrix();
objects[i].Render();
GL.PopMatrix();
}
control.SwapBuffers();
}
I want to render a 3D scene whit some transparent objects in it,
This is an example of my output (I am using opentk in c#)
But the transparency is not working as i desired, I need something like this:
Here is my settings in code:
// before draw transparent object
GL.Enable(EnableCap.Blend);
// after draw transparent object
GL.Disable(EnableCap.Blend);
// # GLInit
GL.ClearColor(0.5f, 0.5f, 1f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
GL.ClearDepth(1);
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Lequal);
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
//GL.Enable(EnableCap.PolygonOffsetFill);
GL.PolygonOffset(0.01f, 0.01f);
GL.Enable(EnableCap.StencilTest);
GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Replace);
try
{
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.DstAlpha);
GL.BlendEquation(BlendEquationMode.FuncAdd);
//Gl.BlendEquation(BlendEquationMode.FuncAddExt);
}
catch { }
GL.Enable(EnableCap.LineSmooth);
GL.Enable(EnableCap.PointSmooth);
GL.Enable(EnableCap.PolygonSmooth);
GL.Disable(EnableCap.Dither);
GL.ShadeModel(ShadingModel.Smooth);
GL.Disable(EnableCap.Multisample);
GL.LineWidth(0.5f);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.FragmentShaderDerivativeHint, HintMode.Nicest);
I removed these two lines in GlInit() method
//GL.Enable(EnableCap.PointSmooth);
//GL.Enable(EnableCap.PolygonSmooth);
and now I have this
I have been trying my hand at making a simple 2D game in Monogame. I found a tutorial online for a Camera class to be used with scrolling the screen towards where my character is moving.
This is the camera class:
public class Camera
{
Vector2 position;
Matrix viewMatrix;
public Matrix ViewMatrix
{
get { return viewMatrix; }
}
public int ScreenWidth
{
get { return GraphicsDeviceManager.DefaultBackBufferWidth; }
}
public int ScreenHeight
{
get { return GraphicsDeviceManager.DefaultBackBufferHeight; }
}
public void Update(Vector2 playerPosition)
{
position.X = playerPosition.X - (ScreenWidth / 2);
position.Y = playerPosition.Y - (ScreenHeight / 2);
if(position.X <0)
{
position.X = 0;
}
if(position.Y <0)
{
position.Y = 0;
}
viewMatrix = Matrix.CreateTranslation(new Vector3(-position, 0));
}
And in the Game1.cs I use the following Draw method:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend,
null, null, null, null, Camera.ViewMatrix);
ScreenManager.Instance.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
When I use spriteBatch.Begin() without any arguments, the Titlescreen and mainmenu load just fine followed by the tilemap and the player.
However when I add the Camera.Viewmatrix argument the screen stays Black. It does not seem to draw anything past the Graphicsdevice.Clear(Color.Black).
I would appreciate any and all input. And please let me know if you need to see more of my code.
UPDATE: The camera and matrix are fine I believe. The problem has to do with the fact that I have many classes, for example Screenmanager, Image, Tile, Layer, TitleScreen,... that are all using an Update and most of them a Draw method.
The actual drawing is being handled as shown above in the game1.cs by a singleton instance of the ScreenManager class using its draw method.
I suspect that it is trying to apply the matrix to the fadescreen/titlescreen in the start and that is causing errors such as not progressing past the black background. Perhaps because the camera position has no player position?
I have tried using a separate spritebatch.Begin() for the Camera and Player draw methods but this of course results in the error that I'm calling a new spriteBatch.Begin before the other one has ended.
I feel like this is solvable but I might have been staring at it too long to see the solution now.
I don't want to turn this into a 'look at my entire project and fix it for me' but if anyone recognizes this situation and has input, or even has run into the same thing and fixed it, I would very much appreciate your feedback.
Also, should anyone require more code to look at, again. feel free to let me know.
Try feeding it an Identity matrix. That should work and it would confirm that something must be wrong with your matrix. It's been a while since I did this, but it think this worked.
public void Update(Vector2 playerPosition)
{
if(position.X <0)
{
position.X = 0;
}
if(position.Y <0)
{
position.Y = 0;
}
viewMatrix = Matrix.CreateTranslation(new Vector3(-playerPosition.X, -playerPosition.Y, 0.0f));
}
I am working on a 2D menu for a game using OpenTK in C#.
At the moment, the menu is separated in 3 different texture quads, or 'layers', which looks like this.
Layer 1: The base appearance of the buttons.
Layer 2: The appearance of the 'continue' button when the mouse hovers over it.
Layer 3: A 'gear' which holds the buttons, as well as their text/name.
Each of these layers consists of a semi-transparent (32-bit .png) texture bound to a Quad.
When drawing only layers 1 & 3, the textures seem to work properly, but when I want to show Layer 2 as well, layer 3 disappears from my screen, as seen here. In this image, only my base buttons (layer 1) and highlighted 'continue' button (layer 2) are drawn.
I believe this is an issue with my blend function, and the fact that I am drawing more than 2 sprites. I am relatively new to OpenTK/OpenGL, and I was hoping someone here could help me fix this problem. I will add some of my code below:
When the game starts, I set up some GL properties:
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
GL.Enable(EnableCap.Texture2D);
GL.Enable(EnableCap.Blend); //I migh t be missing something here, like textEnv?
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
This part of the code draws my 2D elements. I took it from a tutorial on OpenTK.
public void DrawHUD()
{
// Clear only the depth buffer, so that everything
// we draw for the HUD will appear in front of the
// world objects.
GL.Clear(ClearBufferMask.DepthBufferBit);
// Reset the ModelView matrix so the following
// objects are not affected by the camera position
GL.LoadIdentity();
////draw 3d hud elements (weapon in the main game)
// Disable lighting for the HUD graphics
// GL.Disable(EnableCap.Lighting);
// Save the current perspective projection
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
// Switch to orthogonal view
GL.LoadIdentity();
GL.Ortho(0, Width, 0, Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
// Go back to working with the ModelView
GL.MatrixMode(MatrixMode.Modelview);
//// Draw the HUD elements
GameEngine.Draw2D();
// Switch back to perspective view
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
// Turn lighting back on
// GL.Enable(EnableCap.Lighting);
}
I add the menu 'layers' to an arraylist, which I then use to draw using Graphic, a class which holds the position/texture info of my 'layer'
public virtual void Draw2D()
{
Vector2 pos;
int Z = 0; //to fight z-fighting? this fixed an issue where drawing a 2nd sprite would also make the 1st one dissapear partially
foreach (Graphic G in _2DList)
{
if (G.visible())
{
pos = G.position();
Renderer.DrawHUDSprite(pos.X, pos.Y, Z, G.W(), G.H(), G.Texture());
Z++;
}
}
}
Finally, my draw function for hudsprites looks like this:
public static void DrawHUDSprite(float x, float y, float z, float width, float height, int textID)
{
// Save the ModelView matrix
GL.PushMatrix();
// Move to the correct location on screen
GL.Translate(x, y, z);
GL.BindTexture(TextureTarget.Texture2D, textID);
// Setup for drawing the texture
GL.Color3(Color.White);
// Draw a flat rectangle
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0, 0, 0);
GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(width, 0, 0);
GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(width, height, 0);
GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0, height, 0);
GL.End();
// Restore the ModelView matrix
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.PopMatrix();
}
If this has anything to do with the way I load my textures, I will add the code for this as well.
I managed to solve my issue on my own: The problem lies with my draw2D() function, where I use a Z coordinate to prevent clipping issues. The Z-coordinate when drawing in 2D could only be in the range of [0..1].
My earlier solution which increments Z by 1 (Z++) would cause issues with more than 2 textures/Graphics (Z>1, meaning the quad is not displayed). The fixed version looks like this:
public virtual void Draw2D()
{
if (_2DList.Count > 0) { //pervents dividing by 0, and skips memory allocation if we have no Graphics
Vector2 pos;
float Z = 0; //to fight z-fighting, the sprites ar drawn in the order they were added.
float step = 1.0f / _2DList.Count; //limiting the Z between [0..1]
foreach (Graphic G in _2DList)
{
if (G.visible())
{
pos = G.position();
Renderer.DrawHUDSprite(pos.X, pos.Y, Z, G.W(), G.H(), G.Texture());
Z += step; //with z starting at 0, it will never be 1.
}
}
}
}
I'm attempting my first 2D updown scroller really, and i can't seem to get the background size to fully work. for whatever reason it stays small and it is of no help.
I think in the beginning of the parallax scrolling class i was told to initialize variables and I know which one I have to change.
public Texture2D picture;
public Vector2 position = Vector2.Zero;
public Vector2 offset = Vector2.Zero;
public float depth = 0.0f;
public float moveRate = 0.0f;
public Vector2 pictureSize = Vector2.Zero;
public Color color = Color.White;
I believe i must change pictureSize in order to make it bigger as the current sizing i get this!
The final question i have is, How can I remove the whitespace from the ship image?
Thanks!
If any more code is needed please tell me, the reason I did not put it there, is due to the length.
EDIT*:
Here is the code for the rendering of the actual ship
public void Render(SpriteBatch batch)
{
batch.Begin();
batch.Draw(shipSprite, position, null, Color.White, 0.0f, spriteOrigin, 1.0f,
SpriteEffects.None, 0.0f);
batch.End();
}
The whitespace seems to be provided by XNA as I've cleared it several times using photoshop.
Because i can't directly upload to the site I have put it here: http://www.justbeamit.com/nk95n
And for the background rendering its
public void Draw()
{
layerList.Sort(CompareDepth);
batch.Begin();
for (int i = 0; i < layerList.Count; i++)
{
if (!moveLeftRight)
{
if (layerList[i].position.Y < windowSize.Y)
{
batch.Draw(layerList[i].picture, new Vector2(0.0f,
layerList[i].position.Y), layerList[i].color);
}
if (layerList[i].position.Y > 0.0f)
batch.Draw(layerList[i].picture, new Vector2(0.0f,
layerList[i].position.Y - layerList[i].pictureSize.Y),
layerList[i].color);
else
batch.Draw(layerList[i].picture, new Vector2(0.0f,
layerList[i].position.Y + layerList[i].pictureSize.Y),
layerList[i].color);
}
else
{
if (layerList[i].position.X < windowSize.X)
{
batch.Draw(layerList[i].picture, new Vector2(layerList[i].position.X,
0.0f), layerList[i].color);
}
if (layerList[i].position.X > 0.0f)
batch.Draw(layerList[i].picture, new Vector2(layerList[i].position.X -
layerList[i].pictureSize.X, 0.0f), layerList[i].color);
else
batch.Draw(layerList[i].picture, new Vector2(layerList[i].position.X +
layerList[i].pictureSize.X, 0.0f), layerList[i].color);
}
}
batch.End();
}
^
This is not my code but rather from a book I'm reading on how to do XNA(first attempt at C# to :/)
Without all the relevant code and details it is a bit hard to tell the problem, But I assume your scrolling code has a spriteBatch.Draw() call simlar to this:
spriteBatch.Draw(Texture, Destination, Source, Color.White);
TheDestination is probably equal too new Rectangle(0,0,pictureSize.X,pictureSize.Y), I'm assume with no code shown that the pictureSize is the size of the picture (No really!), with the spritebatch Destination parameter, you can "stretch" your image to your viewport.
With this your PictureSize should be the size of your viewport
pictureSize = new Vector2(graphics.PreferredBackBufferWidth,graphics.PreferredBackBufferHeight);
You can also use the Scale parameter of the SpiteBatch to enlarge it (However it will get blurred) or just create a bigger image for your needs.
Now for the spaceship having a white background, is XNA doing this or is the image white? I assume the latter, you will need a photo editing tool such as GIMP to remove the white background of the image.
How can I remove the whitespace from the ship image?
You could try making white transparent, using the Bitmap.MakeTransparent method. Something like this might work:
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
Bitmap test = new Bitmap("C:\Myimage.jpg");
test.MakeTransparent(Color.White);