Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

Tsus

Member Since 25 Oct 2011
Offline Last Active Yesterday, 10:55 AM
*****

#5055508 OIT with weighted average

Posted by Tsus on 21 April 2013 - 08:54 AM

Hi,

 

Your suggestion is already the solution. So, yeah, you got it right. I'll summarize the steps briefly for you:


Your transparent rendering would happen in the rendering loop after the deferred pass:

  1. Fill your deferred buffer (color, depth, …)
  2. Do the deferred lighting
  3. Render the transparent objects

For the last step, do the following:

  1. Disable depth writing (glDepthMask) -> we want no transparent object to be culled by other transparent objects
  2. Enable depth test (glDepthTest) -> compare with your deferred depth buffer (cull by opaque geometry)
  3. Use additive blending (source: GL_ONE, dest: GL_ONE)
  4. Bind two new render targets; let’s call them AccumColors (four (half) float components) and AccumCount (single float component)
  5. Render the transparent objects into those two targets (explained in a moment)
  6. Bind deferred color buffer as render target
  7. Disable depth test (glDepthTest)
  8. Use back-to-front blending (source: GL_ONE_MINUS_SRC_ALPHA, dest: GL_SRC_ALPHA)
  9. Bind AccumColor and AccumCount as textures
  10. Full screen pass: compute the average color/transparency (explained in a moment) and blend with the deferred color buffer

The idea is to compute the average of the colors, weighted by their transparencies. For blending with the background, we additionally need the average opacity. (FYI: I assume that alpha = 1 means opaque, and alpha = 0 means transparent)

 

Step 5 computes the sums. This is what the fragment shader does:

Input: vec3 color, float alpha
Output: 
  AccumColor = vec4(color*alpha, alpha);  // color multiplied (=weighted) with alpha!
  AccumCount = 1;

 

Step 10 compute the average color. Again, the fragment shader:

Input: vec4 AccumColor, float AccumCount

if (AccumCount < 0.00001 || AccumColor.w < 0.00001)
{
  discard;  // nothing here; discard the fragment.
}
else
{
  vec4 avgColor = vec4(
  AccumColor.xyz / AccumColor.w,    // weighted average color
  AccumColor.w / AccumCount);        // average alpha
  // the alpha, used to blend with the background is computed by assuming 
  // that all transparent layers have the average alpha:
  float dstAlpha = 1-pow(max(0,1-avgColor.w), AccumCount);
  // write out the average color and the alpha, used for compositing
  result = vec4 (avgColor.xyz, dstAlpha);
}

Hope that gives some insights. smile.png

Best regards!


 




#5042893 D3D11 - RenderTargetView at slot 0 is not compatable with the DepthStencilView

Posted by Tsus on 13 March 2013 - 05:01 PM

Hi!


Your render target view (that views the texture to render into) and your depth stencil view (the corresponding depth buffer) have different multi-sampling settings.
When using multi-sampling, every pixel needs to store extra data for the sub-samples (their depth and the coverage bits). Each texture resource is prepared for one certain multi-sampling setting and to make them work together, both the color texture and the depth buffer (after all, it’s just another texture) need the same setting. You can have resources with different settings, but you can only bind them together, if their settings coincide.


If you disable multi-sampling, it would be:

sampleDesc.Count = 1;
sampleDesc.Quality = 0;


High-quality 4x MSAA (for instance) is achieved by setting:

sampleDesc.Count = 4;
sampleDesc.Quality = 16.


Keep in mind that MSAA comes at a cost. If you don’t need it, try to avoid it. Also, combining multi-sampled with single-sampled textures requires you to convert one into the other. (I'd advise you to first familarize yourself with the rendering to textures, before working with multi-sampling)

 

Okay, so try to set in your default texture (system class):

texd.SampleDesc.Count = 1; 

and make sure that your view dimensions are set to the single-sampled types, e.g.,

for the depth stencil view: D3D11_DSV_DIMENSION_TEXTURE2D  (not: D3D11_DSV_DIMENSION_TEXTURE2DMS).
 

Cheers!




#5013374 Efficient Rendering of Hundreds of Billboards

Posted by Tsus on 22 December 2012 - 04:26 AM

Hi!

You’re using XNA, right?
A common trick to render many billboards (if you don’t have geometry shaders available) is to send four vertices with identical position to the vertex shader and to expand the quad in view space, by offsetting each of the vertices using their texture coordinates. (The texture coordinate identifies in which corner to move the vertex.) This way, you don't need to calculate rotation matrices on the CPU (or the GPU). Thus you don't have to set additional effect constants and therefore you don't need to call Apply for every single billboard, but only if the texture changes. (So, batching, i.e. sorting per material, would be a good idea.)

Even better, you can render all billboards that share the same texture with a single draw call, by throwing all billboards into a single vertex buffer.
See here, for an example (Section 1.2).

Best regards!
 

PS: You do not necessarily need a quad. You could also use a single right triangle that covers the whole quad. (Of course, some area would be unused.) If you go down this road, you trade input assembler load against rasterizer load. You would need to profile to see what's better in your situation. For starters I would suggest to use quads, since they are more intuitive.




#5005264 Linestrip with GeometryShader

Posted by Tsus on 29 November 2012 - 05:19 AM

Hi Helgon,

The primitive topology that is specified at the input assembler defines the primitives fed into the pipeline (D3D11_PRIMITIVE_TOPOLOGY_X). The topology needs to match the type you specified at the input struct of the geometry shader:
void GS(point VertexOut gin[1],
			inout LineStream<GeoOut> stream)
This would require a D3D11_PRIMITIVE_TOPOLOGY_POINTLIST.

void GS(line VertexOut gin[2],
			inout LineStream<GeoOut> stream)
This would require a D3D11_PRIMITIVE_TOPOLOGY_LINE{LIST|STRIP}. Note that you now have two vertices coming in (gin[2]).
The output topology is defined by the geometry shader’s output stream, i.e. LineStream. Input and output topologies don’t necessarily have to coincide.

Jason suggested to use a line strip as input, as it allows you to fake the connections between your lines. (See the attachment for a small example.)

Best regards!

Attached Files




#5004170 Geometry shader, but why ?

Posted by Tsus on 26 November 2012 - 04:31 AM

Ok, since we’re on the geometry shader's right to exist... Posted Image

Also the geometry shader allows you to dynamically insert new primitives into an existing vertex stream. Consider a particle system in which a few “launch particles” are emitted that explode after a certain time, creating multiple new “secondary particles”. By using Stream Output (steered by the geometry shader stage) you can feed the vertex data back into a vertex buffer and use it in the next frame. (See DirectXSDK, "GSParticles".)

A second -- very important -- thing about stream output is that a geometry shader always “inserts” primitives into the stream (not just appends at the end). Imagine you have a line, consisting of multiple particles. (Now comes a flow visualization example. Posted Image) If you transport (aka advect) the particles in some sort of vector field (like a fluid or turbulent air), you can use the geometry shader to refine the line segments, if two adjacent vertices (A and B) are transported too far apart. (Which is basically just inserting a new vertex between A and B.) The important thing is: the topology is preserved. You still have a point list that can be rendered as a line strip, because the order still fits since the new vertex sits between A and B in the output stream. Doing this with compute shaders is rather cumbersome. Therefore, I often use the Geometry Shader in GPGPU applications (whenever I need to “insert” data into a stream).

Alright, and to talk about spheres... You could as well generate a viewport-aligned quad in your geometry shader that covers the sphere and do an analytic ray cast onto the sphere in the pixel shader to calculate the position and normal, discarding everything outside of the sphere. If you have many spheres with varying level of detail that should be rendered in a single draw call, this approach might not be so demanding for the tessellator.


#5003917 Counting the depth complexity / Get the stencilRef

Posted by Tsus on 25 November 2012 - 04:17 AM

Hi Helgon,

What do you want to count? Both back and front faces? Probably just front faces, right? If so, try to set:
colorDepth.DepthEnable = true;
colorDepth.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; // disable writes
colorDepth.DepthFunc = D3D11_COMPARISON_ALWAYS;
colorDepth.StencilEnable = true;
colorDepth.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; // enable
colorDepth.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; // enable
colorDepth.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
colorDepth.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
colorDepth.FrontFace.StencilPassOp = D3D11_STENCIL_OP_INCR; // also count fragments that didn't pass the depth test
colorDepth.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
colorDepth.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;  // set to INCR, if you want to count both, back and front faces
colorDepth.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; // set to INCR, if you want to count both, back and front faces. (counts fragments that didn't pass the depth test)
colorDepth.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
colorDepth.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

StencilFailOp is executed if the stencil test fails (it will never, since we set StencilFunc to always). StencilDepthFailOp happens if the stencil test passes and the depth test fails. The StencilPassOp operation is used when both tests pass. On frontfaces we increment, on backfaces we do nothing.

If you want to read the stencil value in the shader, then you need three depth stencil views, all viewing the same texture.
The first is used for rendering into it. Therefore, use the format DXGI_FORMAT_D24_UNORM_S8_UINT. Bind it to the OM, when you render the scene (OMSetRenderTargets).
The second SRV is bound to the OM, when you want to read the stencil buffer. Again, use the format DXGI_FORMAT_D24_UNORM_S8_UINT, but additionally set the flag D3D11_DSV_READ_ONLY_STENCIL. (Additionally, set a depthStencilState that disables stencil write operations, i.e., StencilWriteMask = 0)
The third SRV is bound to the PS (PSSetShaderResources). Now, use the format DXGI_FORMAT_X24_TYPELESS_G8_UINT.
In the shader code it is used like this:
Texture2D<uint> txStencil : register (t0); // set the corresponding register
float4 PSStencil(float4 pos: SV_Position) : SV_Target
{
  uint stencil = txStencil.Load(int3(pos.xy, 0));

  // debug output
  if (stencil == 1) return float4(0,1,0,1);
  else return float4(0,0,0,0);
}

Hope that helps! Posted Image
Best regards!


#4998140 XNA

Posted by Tsus on 06 November 2012 - 12:25 PM

Hi!

The standard sample site is: xbox.create.msdn.com/en-US/education/catalog/
I would also recommend to look around here: www.riemers.net/
A selection of books can be found here on gamedev (including some on XNA): www.gamedev.net/page/books/index.html/_/technical/directx-8/

Best regards!


#4998005 Program exits at Direct3D initialization (D3D11CreateDevice)

Posted by Tsus on 06 November 2012 - 06:47 AM

Hi Nick,

Using a default adapter doesn't work for me either. Perhaps just try to iterate the adapters. (In case you have multiple graphics cards, try to build a device on each and see which one has the best feature level.)

bool D3D::CreateDevice()
{
	// Get the factory, so we can iterate the adapters and later build a swap chain.
	if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory) ,(void**)&_Factory)))
		_Factory = NULL;
	HRESULT hr = S_OK;
	UINT createDeviceFlags = 0;
#ifdef _DEBUG
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
	D3D_DRIVER_TYPE driverTypes[] =
	{
		D3D_DRIVER_TYPE_UNKNOWN,	  
	};
	UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] );
	D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 };
	unsigned int numFeatureLevels = 3;

	// Iterate the driver types (chose the first one that works. -> possible to use software fallback)
	for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
	{
		_DriverType = driverTypes[driverTypeIndex];
		// Iterate the adapters
		for ( UINT i = 0;
			_Factory->EnumAdapters(i, &_Adapter) != DXGI_ERROR_NOT_FOUND;
		++i )
		{
			// Try to create a device
			hr = D3D11CreateDevice(_Adapter, _DriverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,	  D3D11_SDK_VERSION,  &_Device, &_FeatureLevel, &_ImmediateContext);
			if (SUCCEEDED(hr)) // pick the first that works (this is not necessarily the best one!)
				break;
		}
		if( SUCCEEDED( hr ) )
			break;
	}
	return true;
}

As for the debug info: do you have built the effect framework on debug and release, and link the correct version respectively?

Best regards,
Tsus


#4980605 Parentheses in HLSL cause light attenuation function to not work correctly?

Posted by Tsus on 16 September 2012 - 05:19 AM

Nice! I should put in area lights. It looks so much better. Posted Image
Btw, I’ve used stochastic progressive photon mapping for the image above, implemented on the GPU using stochastic spatial hashing. So, a consistent rendering, too. Posted Image


#4980194 Parentheses in HLSL cause light attenuation function to not work correctly?

Posted by Tsus on 14 September 2012 - 03:38 PM

There she is. Posted Image
Nice model, thanks again!

Attached Thumbnails

  • CornellKit2.jpg



#4980030 Parentheses in HLSL cause light attenuation function to not work correctly?

Posted by Tsus on 14 September 2012 - 06:34 AM

Hi CryZe!

Alright, let me show you how I got to my equations. I’m still convinced that they are correct. Posted Image

The intensity is the flux per solid angle: ), therefore my Pi in the BRDF doesn’t cancel out.

Best regards!


#4979870 Parentheses in HLSL cause light attenuation function to not work correctly?

Posted by Tsus on 13 September 2012 - 04:43 PM

Hi!

If you write
float attenuation = 1.0f / d*d;
if will evaluate to

By the way, the other attenuation parameters (constant and linear) are just for artistic purposes. Squared attenuation would be most correct, since the irradiance of a point light is:
E = max(0, cosAngle) * vLightIntensity / (squaredDistance);
For a diffuse surface the radiance then becomes:
L = E * vSurfaceColor / Pi;
You got it right, except for the division by Pi. (It is there for the energy conservation.)

Anyway, the reason why things are getting dark is, that your light source is probably too far away. Consider a distance of 10 units in space. Squared and divided gives you 1/100 of your un-attenuated intensity. I think, things should work for you, if you make your light brighter, i.e. your variable “lightColor”. The lightColor actually stores the luminous intensity in candela (cd). A candle has about 1 candela. A 100 watt light bulb has about 130 cd. So, I guess you need rather large values. :-)

By the way, your test model is quite beautiful. Is it available online? I'd like to use it in my thesis.

Cheers!


#4978235 Cube drawn on the first frame only

Posted by Tsus on 09 September 2012 - 04:07 AM

Hi!

It looks like you are using the flip-model for your swap chain. There are a few remarks on it in the MSDN docs.

If you don’t really need the flip-model (i.e. you don’t build an app for the windows store and don’t mix with GDI content), it should be possible to build the swap chain with the DXGI_SWAP_EFFECT_DISCARD flag and all should behave as usual.

That’s pretty much all the help I can give you, since I haven’t ported anything to Dx11.1 yet.
If you figure it out, please let us know the solution. It would interest me as well. Posted Image

Good luck and best regards!


#4977860 pre-pass lightning: gbuffer clears fine, but objects normals and depths wont...

Posted by Tsus on 07 September 2012 - 06:14 PM

Hi a2ps!

Nice to hear that it works! Posted Image
The missing transpose probably comes from the packing order of the matrices. I assume, on the C++ side it is row_major and on the HLSL side it is column_major. A row_major in front of your matrices in the HLSL code should help you avoiding the transpose in the C++ code. Though, I would rather recommend using the compiler flag \Zpr when compiling the shaders with fxc.exe to make row_major the default packing order in HLSL. Always writing the transpose on the C++ side or adding manually the row_major in front of all matrices in the HLSL code is a little error-prone.

Happy coding with the lighting! Posted Image
Best regards


#4977386 pre-pass lightning: gbuffer clears fine, but objects normals and depths wont...

Posted by Tsus on 06 September 2012 - 04:18 PM

Hi a2ps!

Can you directly render the scene to the backbuffer? Perhaps try some simple vertex/pixel shader, e.g. just drawing everything in red. That way you could isolate, whether it is your input assembler setup or the output merger (render target stuff).

I noticed two things that might be a problem. It is hard to tell, whether those apply in your case, since it depends on the way you fill your vertex buffer / compile your shader, but here it goes:

Be careful with the transformation of the normal to world space. Your vertex shader receives the normal in a float4. Make sure that the w-component is a zero, since you only want to apply the rotation/scale part of the world matrix, not the translation. (This is a common pitfall.)

Another thing is the packing order of your matrices. Sometimes the C++ and HLSL side don’t line up. Perhaps try to specify the order explicitly (row_major or column_major), like so:
row_major matrix WorldMatrix;
row_major matrix ViewMatrix;
row_major matrix ProjectionMatrix;
(You can also set this with a compiler flag: \Zpr for row major and \Zpc for column major.)

Let us know if that works for you.
Best regards!




PARTNERS