FINAL EDIT:
Resolved... just needed to learn how alpha blending works in-depth. I should have had:
oBlendStateDesc.RenderTarget[a].DestBlendAlpha = D3D11_BLEND_ZERO;
...set to D3D11_BLEND_ONE to preserve the alpha.
When rendering to the backbuffer once the problem would not be noticed as the colours blend normal and that is the final output. When rendering to the texture the same thing applies, just then rendering the texture to the backbuffer the incorrect alpha plays a role in incorrectly blending the texture into the backbuffer.
I then ran into another issue where the alpha seemed to be decreasing. This is because the colour is blended twice, for example...
Source.RBGA = 1.0f, 0.0f, 0.0f, 0.5f
Dest.RGBA = 0.0f, 0.0f, 0.0f, 0.0f
Render into texture...
Result.RGB = Source.RBG * Source.A + Dest.RGB * (1 - Source.A) = 0.5f, 0.0f, 0.0f
Result.A = Source.A * 1 + Dest.A * 1 = 0.5f
Now...
Source.RBGA = 0.5f, 0.0f, 0.0f, 0.5f
Dest.RGBA = 0.0f, 0.0f, 0.0f, 0.0f
Render into backbuffer...
Result.RGB = Source.RBG * Source.A + Dest.RGB * (1 - Source.A) = 0.25f, 0.0f, 0.0f
Result.A = Source.A * 1 + Dest.A * 1 = 0.5f
To resolve this, when rendering the texture into the backbuffer I use the same blendstate but change the SrcBlend to D3D11_BLEND_ONE so the colour is not blended twice.
Hopefully this helps anyone else having a similar problem....
EDITEND
To increase performance I'm attempting to render a string of text that never changes into a texture to save rendering each individual character every time.
Since I'm rendering strictly in 2D, I've disabled the depth & stencil testing while enabling alpha blending.
Problem is there doesn't seem to be any alpha blending happening, whatever is drawn last overwrites the current pixel with its own data... no blending.
I use a single blend state which I do not change. When rendering to the backbuffer the blending works fine. When rendering the final texture to the backbuffer the blending also works fine. It's just when I render to the texture that blending seems to fail.
Here's how I set up my single blend state:
D3D11_BLEND_DESC oBlendStateDesc;
oBlendStateDesc.AlphaToCoverageEnable = 0;
oBlendStateDesc.IndependentBlendEnable = 0; //set to false, dont need loop below... but just incase
for (unsigned int a = 0; a < 8; ++a)
{
oBlendStateDesc.RenderTarget[a].BlendEnable = 1;
oBlendStateDesc.RenderTarget[a].SrcBlend = D3D11_BLEND_SRC_ALPHA;
oBlendStateDesc.RenderTarget[a].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
oBlendStateDesc.RenderTarget[a].BlendOp = D3D11_BLEND_OP_ADD;
oBlendStateDesc.RenderTarget[a].SrcBlendAlpha = D3D11_BLEND_ONE;
oBlendStateDesc.RenderTarget[a].DestBlendAlpha = D3D11_BLEND_ZERO;
oBlendStateDesc.RenderTarget[a].BlendOpAlpha = D3D11_BLEND_OP_ADD;
oBlendStateDesc.RenderTarget[a].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
}
// Create the blend state from the description
HResult = m_poDevice->CreateBlendState(&oBlendStateDesc, &m_poBlendState_Default);
m_poDeviceContext->OMSetBlendState(m_poBlendState_Default, nullptr, 0xffffff);
Are there any extra steps I am missing to enable blending when rendering to a texture?
EDIT: If I set AlphaToCoverageEnable to true it blends, but looks terrible. That at least confirms it is using the same blend state... just works differently depending on when rendering to backbuffer or a texture : / Here's my texture desc...
m_oTexureDesc.Width = a_oDesc.m_uiWidth;
m_oTexureDesc.Height = a_oDesc.m_uiHeight;
m_oTexureDesc.MipLevels = 1;
m_oTexureDesc.ArraySize = 1;
m_oTexureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
m_oTexureDesc.SampleDesc.Count = 1; //No sampling
m_oTexureDesc.SampleDesc.Quality = 0;
m_oTexureDesc.Usage = D3D11_USAGE_DEFAULT; //GPU writes & reads
m_oTexureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
m_oTexureDesc.CPUAccessFlags = 0;
m_oTexureDesc.MiscFlags = 0;
EDIT:
Here's some visualization...
Rendering to backbuffer - AlphaBlending enabled.
Rendering to texture - AlphaBlending enabled.
Rendering to backbuffer - AlphaBlending disabled.
Letter T taken from the font file
*When rendering with AB disabled, the letters match exactly (compare 4 & 3)
*When rendering to the backbuffer with AB enabled, the letters render slightly (hardly noticeable) washed out but still blend (compare 4 & 1)
*When rendering to a texture with AB enabled, the letters render even more noticeably washed out while not blending at all. (compare 4 & 2)
Not sure why the colours are washed out with alpha blending enabled... but maybe its a clue?
EDIT:
If I clear the render target texture to say... 0.0f, 0.0f, 1.0f, 1.0f (RGBA, blue)... this is the result:
Only the pixels with alpha > 0.0f & < 1.0f blend with the colour. Another clue but I have no idea how to resolve this issue...
Related
I'm trying to inverse to viewport of vulkan instead of inversing everything else, but this result in a black screen. The black screen looks like it's coming from one of my shader.
Code to inverse the viewport:
VkRect2D renderArea = {};
renderArea.offset = {0, 0};
renderArea.extent = {
static_cast<uint32_t>(renderStage.GetSize().x),
static_cast<uint32_t>(renderStage.GetSize().y)
};
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = static_cast<float>(renderArea.extent.height);
viewport.width = static_cast<float>(renderArea.extent.width);
viewport.height = -static_cast<float>(renderArea.extent.height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(
*commandBuffers_[swapchain_->GetActiveImageIndex()],
0,
1,
&viewport);
In render doc I see that stuff are drawn to framebuffer, but at one point after a specific shader everything is black (it works just fine if I'm not doing the inversion).
The vertex shader (light pass in deferred rendering)
void main()
{
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
}
Input of the pass
Output of the pass
The black output is probably your clear color, which means your geometry is either discarded or outside of the viewport.
If you flip the viewport in Vulkan 1.0 you also need to enable VK_KHR_maintenance1 (in Vulkan 1.1. this was promoted to the core).
And if you have culling enabled, you either need to flip the culling mode or the front face information of your pipeline's rasterization state. Otherwise your geometry gets discarded because it faces away from the screen after flipping the viewport.
I am playing with OGL's blending. I have a white background. I draw quad on this background. The quad is binded with white and black texture. Colors array is filled with color and alpha values:
for (i = 0; i < IMAGE_WIDTH; i++) {
for (j = 0; j < MAGE_HEIGHT; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
Image[i][j][0] = (GLubyte) c;
Image[i][j][1] = (GLubyte) c;
Image[i][j][2] = (GLubyte) c;
Image[i][j][3] = (GLubyte) 255;
};
Display textured quad:
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);
glDisable (GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texCheck);
glLoadIdentity();
glTranslatef (0.0f, 0.0f, -9.0f);
glBegin (GL_QUADS);
glColor3f (1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0, 0.0); glVertex3f(-5.0f, -5.0f, 0.0f);
glTexCoord2f(0.0, 1.0); glVertex3f( 5.0f, -5.0f, 0.0f);
glTexCoord2f(1.0, 1.0); glVertex3f( 5.0f, 5.0f, 0.0f);
glTexCoord2f(1.0, 0.0); glVertex3f(-5.0f, 5.0f, 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
glEnable (GL_DEPTH_TEST);
glDisable (GL_BLEND);
Black color of the binded texture on the quad is invisible and works fine. What should I do to make white color of binded texture transparent and black color of binded texure not transparent.
Your blend function should be
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Supplying GL_ONE as second parameter means that destination color value is taken without taking source alpha value into account so no proper blending occurs.
You have to solve 2 issues:
If different texels of a texture should be blended in different way, then you have to set different alpha channels. If, as in your case, black colored texels should be opaque and white colored texels should be invisible, then the alpha channel of the black texel has to be set to 255 and the alpha channel of the white texel has to be set to 0. Note, any alpha value between 0 and 255 causes a transparent effect, which is more or less strong.
you have set the blending function to glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
Blending calculates a new target color (the fragment color in the frame buffer), by a function of the original target color and the source color (in your case the color of the texel).
If you set the glBlendFunc
with the functions (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) and you use
glBlendEquation with the equation GL_FUNC_ADD (this is default) then the destination color is
calculated as follows:
C_dest_new = C_src * A_src + C_dest * (1-A_src)
If the alpha channel is equal to 0.0:
C_dest_new = C_src * 0 + C_dest * (1-0) = C_dest
If the alpha channel is equal to 1.0 (255):
C_dest_new = C_src * 1 + C_dest * (1-1) = C_src
Extension to the answer
To set the alpha channel of white texels to 0, the code, which generates the texture, has to be changed somehow like this:
for (i = 0; i < IMAGE_WIDTH; i++) {
for (j = 0; j < MAGE_HEIGHT; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
Image[i][j][0] = (GLubyte) c;
Image[i][j][1] = (GLubyte) c;
Image[i][j][2] = (GLubyte) c;
Image[i][j][3] = (GLubyte) (255 - c);
}
}
I'm trying to put a texture on one surface of a cube (if facing the XY plane the texture would be facing you).
No texture is getting drawn, only the wireframe and I'm wondering what I'm doing wrong. I think it's the vertex coordinates?
Here's some code:
struct paperVertex {
D3DXVECTOR3 pos;
DWORD color; // The vertex color
D3DXVECTOR2 texCoor;
paperVertex(D3DXVECTOR3 p, DWORD c, D3DXVECTOR2 t) {pos = p; color = c; texCoor = t;}
paperVertex() {pos = D3DXVECTOR3(0,0,0); color = 0; texCoor = D3DXVECTOR2(0,0);}
};
D3DCOLOR color1 = D3DCOLOR_XRGB(255, 255, 255);
D3DCOLOR color2 = D3DCOLOR_XRGB(200, 200, 200);
vertices[0] = paperVertex(D3DXVECTOR3(-1.0f, -1.0f, -1.0f), color1, D3DXVECTOR2(1,0)); // bottom left corner of tex
vertices[1] = paperVertex(D3DXVECTOR3(-1.0f, 1.0f, -1.0f), color1, D3DXVECTOR2(0,0)); // top left corner of tex
vertices[2] = paperVertex(D3DXVECTOR3( 1.0f, 1.0f, -1.0f), color1, D3DXVECTOR2(0,1)); // top right corner of tex
vertices[3] = paperVertex(D3DXVECTOR3(1.0f, -1.0f, -1.0f), color1, D3DXVECTOR2(1,1)); // bottom right corner of tex
vertices[4] = paperVertex(D3DXVECTOR3(-1.0f, -1.0f, 1.0f), color1, D3DXVECTOR2(0,0));
vertices[5] = paperVertex(D3DXVECTOR3(-1.0f, 1.0f, 1.0f), color2, D3DXVECTOR2(0,0));
vertices[6] = paperVertex(D3DXVECTOR3(1.0f, 1.0f, 1.0f), color2, D3DXVECTOR2(0,0));
vertices[7] = paperVertex(D3DXVECTOR3(1.0f, -1.0f, 1.0f), color1, D3DXVECTOR2(0,0));
D3DXCreateTextureFromFile( md3dDev, "texture.bmp", &gTexture);
md3dDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
md3dDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
md3dDev->SetTexture(0, gTexture);
md3dDev->SetStreamSource(0, mVtxBuf, 0, sizeof(paperVertex));
md3dDev->SetVertexDeclaration(paperDecl);
md3dDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
md3dDev->SetIndices(mIndBuf);
md3dDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, VTX_NUM, 0, NUM_TRIANGLES);
disclaimer: I have no Direct3D experience, but solid OpenGL and general computer graphics experience. And since the underlying concepts don't really differ, I attempt an answer, of whose correctness I'm 99% sure.
You call md3dDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME) immediately before rendering and wonder why only the wireframe is drawn?
Keep in mind that using a texture doesn't magically turn a wireframe model into a solid model. It is still a wireframe model with the texture only applied to the wireframe. You can only draw the whole primitve as wireframe or not.
Likewise does using texture coordinates of (0,0) not magically disable texturing for individual faces. You can only draw the whole primitive textured or not, though you might play with the texture coordinates and the texture's wrapping mode (and maybe the texture border) to make the "non-textured" faces use a uniform color from the texture and thus look like not textured.
But in general to achieve such deviating render styles (like textured/non-textured, but especially wireframe/solid) in a single primitive, you won't get around splitting the primitive into multiple ones and drawing each one with its dedicated render style.
EDIT: According to your comment: If you don't need wireframe, why enable it then? Besides disabling wireframe, with your current texture coordinates the other faces won't just have a single color from the texture but some strange distorted version of the texture. This is because your vertices (and their texture coordinates) are shared between different faces, but the texture coordinates at the moment are created only for the front face to look reasonable.
In such a situation, you won't get around duplicating vertices, so that each face uses a set of 4 unique vertices. In the case of a cube you won't actually need an index array anymore, because each face needs its own vertices. This is due to the fact, that a vertex conceptually represents all of the vertex' attributes (position, color, texCoord, ...) and you cannot have a two vertices sharing a position but having different texture coordinates (you can but you need two distinct vertices). Once you've duplicated the vertices accordingly, you can give each of the corner vertices their respective texture coordinates (which would be the usual [0,1]-quad if you want them textured normally, or all 0s if you want them to have a single color, in this case the color of the bottom left (or top left in D3D?) corner of the texture).
The same problem arises if you want to light the cube and need normals per-face, istead of interpolated per-vertex normals. In this case you also have to introduce duplicate vertices only deviating in their normal attribute. Always keep in mind that a vertex conceptually consists of all the vertex attributes and if two vertices have the same position but a different color/normal/texCoord/... they are conceptually (and practically) different vertices.
I'm trying to draw a subregion of a texture in OpenGL by specifying the coordinates I want. What's happening though is that, depending on the size of the image, it seems there's a slight offset in the origin of where it selects the texture coordinates. The offset amount seems to be less than the size of a pixel & the output is is blurred combination of neighboring pixels.
Here's an idea of what I'm describing. In this case I'd want to select the 6x5 green/white region but what OpenGL is rendering includes a slight pink tint to the top & left pixels.
What the output would look like:
I can fix it by adding an offset to the texture coordinates before passing them to glTexCoordPointer but the problem is that I have no way to calculate what the offset is and it seems different for different textures.
Pseudocode:
float uFactor = regionWidth / textureWidth; // For the example: 0.6f
float vFactor = regionHeight / textureHeight; // For the example: 0.5f
data[0].t[0] = 0.0f * uFactor;
data[0].t[1] = 0.0f * vFactor;
data[1].t[0] = 1.0f * uFactor;
data[1].t[1] = 0.0f * vFactor;
data[2].t[0] = 0.0f * uFactor;
data[2].t[1] = 1.0f * vFactor;
data[3].t[0] = 1.0f * uFactor;
data[3].t[1] = 1.0f * vFactor;
glPushMatrix();
// translate/scale/bind operations
glTexCoordPointer(2, GL_FLOAT, 0, data[0].t);
Keep in mind, that OpenGL samples textures at the texel centers. So when using linear filtering (like GL_LINEAR or GL_LINEAR_MIPMAP_LINEAR) the exact texel color is only returned if sampled at the texel center. Thus, when you only want to use a sub-region of a texture, you need to indent your texture coordinates by half a texel (or 0.5/width and 0.5/height). Otherwise the filtering will blend the border of the texture with neigbouting texels outside of your intended region. This causes your slightly pinkish border. If you use up the whole texture this effect is compensated by the GL_CLAMP_TO_EDGE wrapping mode, but when using a subregion, GL does not know where it's edge is and that filtering should not cross it.
So when you got a subregion of the texture in the range [s1,s2]x[t1,t2] (0 <= s,t <= 1), the real valid texCoord interval should be [s1+x,s2-x]x[t1+y,t2-y] with x being 0.5/width and y being 0.5/height (the width and height of the whole texture corresponding to [0,1]x[0,1]).
Therefore try
data[0].t[0] = 0.0f * uFactor + 0.5/textureWidth;
data[0].t[1] = 0.0f * vFactor + 0.5/textureHeight;
data[1].t[0] = 1.0f * uFactor - 0.5/textureWidth;
data[1].t[1] = 0.0f * vFactor + 0.5/textureHeight;
data[2].t[0] = 0.0f * uFactor + 0.5/textureWidth;
data[2].t[1] = 1.0f * vFactor - 0.5/textureHeight;
data[3].t[0] = 1.0f * uFactor - 0.5/textureWidth;
data[3].t[1] = 1.0f * vFactor - 0.5/textureHeight;
Propably this has to do with the wrap around. Try this when you create the source image:
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP )
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP )
Making a 2D OpenGL game. When rendering a frame I need to first draw some computed quads geometry and then draw some textured sprites. When the body of my render method only draws the sprites, everything works fine. However, when I try to draw my geometric quads prior to the sprites the texture of the sprite changes to be the color of the last GL.Color3 used previously. How do I tell OpenGL (well, OpenTK) "Ok, we are done drawing geometry and its time to move on to sprites?"
Here is what the render code looks like:
// Let's do some geometry
GL.Begin(BeginMode.Quads);
GL.Color3(_dashboardBGColor); // commenting this out makes my sprites look right
int shakeBuffer = 100;
GL.Vertex2(0 - shakeBuffer, _view.DashboardHeightPixels);
GL.Vertex2(_view.WidthPixelsCount + shakeBuffer, _view.DashboardHeightPixels);
GL.Vertex2(_view.WidthPixelsCount + shakeBuffer, 0 - shakeBuffer);
GL.Vertex2(0 - shakeBuffer, 0 - shakeBuffer);
GL.End();
// lets do some sprites
GL.Begin(BeginMode.Quads);
GL.BindTexture(TextureTarget.Texture2D, _rockTextureId);
float baseX = 200;
float baseY = 200;
GL.TexCoord2(0, 0); GL.Vertex2(baseX, baseY);
GL.TexCoord2(1, 0); GL.Vertex2(baseX + _rockTextureWidth, baseY);
GL.TexCoord2(1, 1); GL.Vertex2(baseX + _rockTextureWidth, baseY - _rockTextureHeight);
GL.TexCoord2(0, 1); GL.Vertex2(baseX, baseY - _rockTextureHeight);
GL.End();
GL.Flush();
SwapBuffers();
The default texture environment mode is GL_MODULATE, which does that, it multiplies the texture color with the vertex color.
A easy solution is to set the vertex color before drawing a textured primitive to 1,1,1,1 with:
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
Another solution is to change the texture environment mode to GL_REPLACE, which makes the texture color replace the vertex color and doesn't have the issue:
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);