Jump to content

  • Log In with Google      Sign In   
  • Create Account

Husbjörn

Member Since 27 Jan 2014
Offline Last Active Jul 13 2016 10:38 AM

#5294924 SampleLevel not honouring integer texel offset

Posted by Husbjörn on 04 June 2016 - 04:59 AM

This is a curious one.

I recently had to switch out some SampleCmpLevelZero calls on a Texture2DArray for use with shader model 4. The go-to solution seemed to be SampleLevel, called as such:

Tex2DArray.SampleLevel(LegacySampler, coord, 0, texelOffset);

The MSDN article on the function states that the offset argument should indeed be supported: https://msdn.microsoft.com/en-us/library/windows/desktop/bb509699(v=vs.85).aspx

Once compiled it has absolutely no effect however; indeed it doesn't even give off a compilation error if set outside the valid range of (-8 .. +7).

Furthermore, the assembly instruction associated with SampleLevel, sample_l, doesn't seem to have any offset argument at all: https://msdn.microsoft.com/en-us/library/windows/desktop/hh447229(v=vs.85).aspx

It is of course possible that the offset is merged with the input texcoord through separate instructions prior to calling sample_l, but I can't seem to find any indication of this looking at my disassembled shader (granted I'm far from experienced with that though).

 

So I guess my question is whether this function indeed does not support the integer texel offset argument, with the compiler (version 43) essentially just silently removing it, or if something is going particularly wrong on my end? Perhaps this is a known bug in my particular HLSL compiler dll?

 

I know I can just go the extra mile and compute the corresponding texcoord offsets myself and I suppose I will, but I still found this intriguing enough to make a post about it since there doesn't seem to be any information regarding it that I've been able to find.




#5294282 False negative result in bounding frustum test

Posted by Husbjörn on 31 May 2016 - 03:01 AM

Maybe you cna share your algorithm for frustum culling? Maybe I am missing something here (some space translations or something else?

Certainly, though it is quite old and could probably do with a revision.

I'm using axis aligned bounding boxes by the way, storing the min and max extents along the X/Y/Z axes in object space:

void BoundingBox::Transform(const XMMATRIX& mat, XMFLOAT3& vecMin, XMFLOAT3& vecMax) const {
	XMFLOAT3 coord[8];
	// Front Vertices
	XMStoreFloat3(&coord[0], XMVector3TransformCoord(XMVectorSet(vecBaseMin.x, vecBaseMin.y, vecBaseMin.z, 1.0f), mat));
	XMStoreFloat3(&coord[1], XMVector3TransformCoord(XMVectorSet(vecBaseMin.x, vecBaseMax.y, vecBaseMin.z, 1.0f), mat));
	XMStoreFloat3(&coord[2], XMVector3TransformCoord(XMVectorSet(vecBaseMax.x, vecBaseMax.y, vecBaseMin.z, 1.0f), mat));
	XMStoreFloat3(&coord[3], XMVector3TransformCoord(XMVectorSet(vecBaseMax.x, vecBaseMin.y, vecBaseMin.z, 1.0f), mat));
	// Back Vertices
	XMStoreFloat3(&coord[4], XMVector3TransformCoord(XMVectorSet(vecBaseMin.x, vecBaseMin.y, vecBaseMax.z, 1.0f), mat));
	XMStoreFloat3(&coord[5], XMVector3TransformCoord(XMVectorSet(vecBaseMax.x, vecBaseMin.y, vecBaseMax.z, 1.0f), mat));
	XMStoreFloat3(&coord[6], XMVector3TransformCoord(XMVectorSet(vecBaseMax.x, vecBaseMax.y, vecBaseMax.z, 1.0f), mat));
	XMStoreFloat3(&coord[7], XMVector3TransformCoord(XMVectorSet(vecBaseMin.x, vecBaseMax.y, vecBaseMax.z, 1.0f), mat));
}
void Camera::ReconstructFrustumPlanes() {
	// Left Frustum Plane
        // Add first column of the matrix to the fourth column
	frustumPlane[0].a = viewProj._14 + viewProj._11; 
	frustumPlane[0].b = viewProj._24 + viewProj._21;
	frustumPlane[0].c = viewProj._34 + viewProj._31;
	frustumPlane[0].d = viewProj._44 + viewProj._41;

	// Right frustum Plane
        // Subtract first column of matrix from the fourth column
	frustumPlane[1].a = viewProj._14 - viewProj._11; 
	frustumPlane[1].b = viewProj._24 - viewProj._21;
	frustumPlane[1].c = viewProj._34 - viewProj._31;
	frustumPlane[1].d = viewProj._44 - viewProj._41;

	// Top frustum Plane
        // Subtract second column of matrix from the fourth column
	frustumPlane[2].a = viewProj._14 - viewProj._12; 
	frustumPlane[2].b = viewProj._24 - viewProj._22;
	frustumPlane[2].c = viewProj._34 - viewProj._32;
	frustumPlane[2].d = viewProj._44 - viewProj._42;

	// Bottom frustum Plane
        // Add second column of the matrix to the fourth column
	frustumPlane[3].a = viewProj._14 + viewProj._12;
	frustumPlane[3].b = viewProj._24 + viewProj._22;
	frustumPlane[3].c = viewProj._34 + viewProj._32;
	frustumPlane[3].d = viewProj._44 + viewProj._42;

	// Near frustum Plane
        // We could add the third column to the fourth column to get the near plane,
        // but we don't have to do this because the third column IS the near plane
	frustumPlane[4].a = viewProj._13;
	frustumPlane[4].b = viewProj._23;
	frustumPlane[4].c = viewProj._33;
	frustumPlane[4].d = viewProj._43;

	// Far frustum Plane
        // Subtract third column of matrix from the fourth column
	frustumPlane[5].a = viewProj._14 - viewProj._13; 
	frustumPlane[5].b = viewProj._24 - viewProj._23;
	frustumPlane[5].c = viewProj._34 - viewProj._33;
	frustumPlane[5].d = viewProj._44 - viewProj._43;


	// Normalize planes
	for(unsigned int p = 0; p < 6; p++) {
		float length = sqrt(
                    (frustumPlane[p].a * frustumPlane[p].a) + 
                    (frustumPlane[p].b * frustumPlane[p].b) + 
                    (frustumPlane[p].c * frustumPlane[p].c)
                );
		frustumPlane[p].a /= length;
		frustumPlane[p].b /= length;
		frustumPlane[p].c /= length;
		frustumPlane[p].d /= length;
	}
}
bool Camera::FrustumCullBoundingBox(const XMFLOAT3 &vecMin, const XMFLOAT3& vecMax) {
	for(unsigned int p = 0; p < 6; p++) {
		if(XMlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMin.x, vecMin.y, vecMin.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMax.x, vecMin.y, vecMin.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMin.x, vecMax.y, vecMin.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMin.x, vecMin.y, vecMax.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMax.x, vecMax.y, vecMin.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMax.x, vecMin.y, vecMax.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMin.x, vecMax.y, vecMax.z, 1)) >= 0.0f)
			continue;
		if(XMPlaneDotCoord(&frustumPlane[p], &XMVectorSet(vecMax.x, vecMax.y, vecMax.z, 1)) >= 0.0f)
			continue;
		return false;
	}
	return true;
}



#5293359 DX9 Doubling Memory Usage in x64

Posted by Husbjörn on 25 May 2016 - 08:33 AM

Adding to what vstrakh suggested, your VERTEX structure could be responsible if it uses some datatype that expands, such as 32-bit floats on x86 to 64-bit floats on x64. If you have big vertex buffers that would potentially double their total size then.




#5290530 Is SetPrivateData only supposed to be called once?

Posted by Husbjörn on 07 May 2016 - 04:38 AM

OK, rubber ducking in all its glory, I found out that if you call SetPrivateData(<guid>, 0, null) prior to "overwriting" it this apparently releases the previous data and circumvents the warning.

I still believe this is what it must be doing behind the scenes unless the new data fits in the previous allocation though...? So the warning still seems a bit superfluous.




#5272735 Rendering Multiple cubes

Posted by Husbjörn on 26 January 2016 - 11:02 AM

If the smaller cube depth tests against the values already written to the depth-stencil buffer by the larger, its pixels will be found to be covered and discarded.

Try to set the DepthEnable member of your depth-stencil description to false to disable this and see if that makes it draw as intended, since it appears that you specify the desired drawing order yourself.




#5271390 Shimmering / offset issues with shadow mapping

Posted by Husbjörn on 16 January 2016 - 05:47 AM

Yes, they should be; I only used those to try to correspond as much as possible to the original code which I assumed would work.

Changing to using the XM functions instead actually makes the discrepancies when moving the camera forward / backward slightly smaller (no noticeable change when moving left-to-right), however it's still a far cry from being at acceptable levels, and the camera rotation is just as severe with either method so there must be something else at play.

Thanks for the suggestion though, I guess the XM transform versions are somehow a bit more accurate.

 

Update: I have noticed that the shimmering only occurs while changing the orientation / translation of the rendering camera. Moving the light source causes some edge shimmering but much less so than when the camera moves.

Now the thing about these camera movements is that as soon as the camera stops moving / rotating, the shadows stabilize on the next frame. In other words, if the shadow project in a certain way in frame 1, then the camera is moved over frames 2 - 10 and is again still at frame 11, the shadows will project to the same texels in frames 1 and 11, while flickering over frames 2 - 10. I'm starting to wonder if this could somehow be related to double buffering in that the shadow map is rendered with the "latest" view-projection matrix, but the shader lags one frame behind in using the matrix from the previous frame?
But it doesn't seem to make much sense if this would happen automatically; shouldn't the shader use the latest cbuffer values as well as the depth map resource rather than some old buffered copy of these? Or could something else cause this kind of behaviour?




#5271339 Communication between shaders

Posted by Husbjörn on 15 January 2016 - 03:06 PM

You can (and probably have to) tell your geometry shader the vertex layout struct of your output stream; going by your example it would look like so:

void GS(triangle VS_OUT input[3], inout TriangleStream<GS_OUT> Tristream);

As for getting the system value, since this is an input to the shader stage itself rather than coming from the input vertices, I believe it should be declared as its own input to the geometry shader function:

void GS(triangle VS_OUT input[3], uint gsId : SV_GSInstanceId, inout TriangleStream<GS_OUT> Tristream);

This works for other types of shader / system-values as well:

hs_out HS(InputPatch<vs_out, 6> p, uint i : SV_OutputControlPointID, uint patchId : SV_PrimitiveID);

For a shader type that takes its input as the direct output of the previous stage, for example vertex to pixel shaders, you should be able to declare the system value semantic as part of the output from your vertex shader and simply not set it from your vertex shader. The above approach of adding it as another input argument should also work however, and probably looks cleaner.




#5271276 Shimmering / offset issues with shadow mapping

Posted by Husbjörn on 15 January 2016 - 08:08 AM

I am in the somewhat early stages of adding shadow mapping for directional light sources to my engine and after having some issues with this I decided to follow the step-by-step implementation offered by Alex Tardif here: http://alextardif.com/ShadowMapping.html

Still so I'm getting about the same shimmering edges, as well as seeming frame-to-frame offsets in the whole depth map when moving the viewing camera.

Here's a short video to show the issues in action: https://youtu.be/_XBx6UmUZdI

 

What strikes me as particularly odd is the fact that there are significantly less artifacts when moving the camera left-to-right, as opposed to forward / backwards. As is more understandable the most severe artifacts occur when changing the orientation of the camera.

 

Here's my relevant code if anybody can spot any obvious issues or things I've missed that may be considered universally as "obvious".

The code is intentionally as close a match to the one presented in Tardif's article as possible, even if this makes it a bit messier with the changes between XMFLOATX and XMVECTOR etc. I have also left out the second part of his article (or rather not gotten to it yet) which deals with downsampling and blurring, but I cannot see how this would have any relevance besides making the shadows appear smoother.

I am also only using a single cascade split for now, which arbitrarily spans the 1..400 depth range of the rendering camera (which roughly correponds to the size of my testing scene):

// Create a new projection matrix for the rendering camera (which is assumed to use perspective projection here) that 
// only stretches over the current cascade
XMMATRIX matCascadeProjection = XMMatrixPerspectiveFovLH(pRenderingCamera->GetFOV(), pRenderingCamera->GetAspect(), 1.0f, 300.0f);
XMVECTOR frustumCorners[8] = {
	XMVectorSet(-1.0f, 1.0f,  0.0f, 0.0f), 
	XMVectorSet(1.0f,  1.0f,  0.0f, 0.0f), 
	XMVectorSet(1.0f,  -1.0f, 0.0f, 0.0f), 
	XMVectorSet(-1.0f, -1.0f, 0.0f, 0.0f), 
	XMVectorSet(-1.0f, 1.0f,  1.0f, 0.0f), 
	XMVectorSet(1.0f,  1.0f,  1.0f, 0.0f), 
	XMVectorSet(1.0f,  -1.0f, 1.0f, 0.0f), 
	XMVectorSet(-1.0f, -1.0f, 1.0f, 0.0f)
};
// NOTE: The transpose part here seems rather useless; the tutorial mentions it is for being sent to the GPU, but this
//       particular matrix never is. Nevertheless, I'll do it like this to achieve the highest possible correspondence to the
//       article's code snippets. Furthermore, not using a transposed matrix (and obviously not using the TransformTransposed 
//       function) seems to give identical results. Try to remove the transpose part once everything seems to work as intended.
XMMATRIX matCamViewProj		= XMMatrixTranspose(pRenderingCamera->GetViewMatrix() * matCascadeProjection);
XMMATRIX matInvCamViewProj	= XMMatrixInverse(nullptr, matCamViewProj);
// Unproject frustum corners into world space
for(size_t n = 0; n < 8; n++) {
	XMFLOAT3 tmp;
	XMStoreFloat3(&tmp, frustumCorners[n]);
	tmp = util::TransformTransposedFloat3(tmp, matInvCamViewProj);
	frustumCorners[n] = XMLoadFloat3(&tmp);
}

// Find frustum center
XMFLOAT3 frustumCenter(0.0f, 0.0f, 0.0f);
{
	XMVECTOR v = XMLoadFloat3(&frustumCenter);
	for(size_t n = 0; n < 8; n++)
		v += frustumCorners[n];
	v *= (1.0f / 8.0f);
	XMStoreFloat3(&frustumCenter, v);
}

// Retrieve normalized light direction
XMVECTOR lightDirection = XMVector3Normalize(light->GetTransform().GetForwardVector());

// Determine the radius of the to-be orthographic projection as the distance between the farthest frustum corner points divided by two
float radius = XMVectorGetX(XMVector3Length((frustumCorners[0] - frustumCorners[6]))) / 2.0f;	// The length is copied into each element

// Figure out how many texels per world-unit will fit if we project a cube with the given "radius" (side length / 2)
float texelsPerUnit = (float)shadowMapWidth / (radius * 2);	// NOTE: The shadow map *must* be square!

// Build a scaling matrix to scale evenly in all directions to the number of texels per unit
XMMATRIX matScaling = XMMatrixScaling(texelsPerUnit, texelsPerUnit, texelsPerUnit);

// Create look-at vector and matrix by accounting for scaling (and later snapping) to the number of texels per unit
const XMVECTOR UpVector		= XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
const XMVECTOR ZeroVector	= XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR vecBaseLookat		= XMVectorSet(-XMVectorGetX(lightDirection), - XMVectorGetY(lightDirection), -XMVectorGetZ(lightDirection), 0.0f);
XMMATRIX matLookat		= XMMatrixMultiply(XMMatrixLookAtLH(ZeroVector, vecBaseLookat, UpVector), matScaling);
XMMATRIX matInvLookat		= XMMatrixInverse(nullptr, matLookat);	// Take note that this will also undo the scaling effect imposed on «matLookat»!

// Now the above can be used to move the frustum center in texel-sized increments (when transformed by matLookat, and the 
// result can then be brought back into world-space by the inverse lookat matrix).
frustumCenter	= util::TransformFloat3(frustumCenter, matLookat);
frustumCenter.x	= (float)floor(frustumCenter.x);	// Clamp to texel increment (by rounding down)
frustumCenter.y = (float)floor(frustumCenter.y);	// Clamp to texel increment (by rounding down)
frustumCenter	= util::TransformFloat3(frustumCenter, matInvLookat);

// Calculate eye position by backtracking in the opposite light direction, ie. towards the light, by the cascade radius * 2
XMVECTOR eye = XMLoadFloat3(&frustumCenter) - (lightDirection * radius * 2.0f);

// Build the final light view matrix
XMMATRIX matLightView = XMMatrixLookAtLH(eye, XMLoadFloat3(&frustumCenter), UpVector);

// Build the light's projection matrix. This is intended to keep a consistent size and should therefore minimize
// shimmering edges due to per-frame matrix recalculations.
// The near- and far value multiplications are arbitrary and meant to catch shadow casters outside of the frustum, 
// whose shadows may extend into it. These should probably be better tweaked later on, but lets see if it at all works first.
const float zMod = 6.0f;
XMMATRIX matLightProj = XMMatrixOrthographicOffCenterLH(-radius, radius, -radius, radius, -radius * zMod, radius * zMod);


// Associate the current matrices with the light source (the shader side will need to know the "light matrix" to properly sample the shadow map(s))
light->SetCascadeViewProjectionMatrix(split, matLightView * matLightProj);

// Bind the corresponding shadow map for rendering by the special, global shadow mapping camera
gGlob.pShadowCamera->SetDepthStencilBuffer(shadowMap, (UINT)light->GetShadowMapIndex() + split);
// Set the shadow camera's matrices to those of the light source
gGlob.pShadowCamera->SetViewMatrix(matLightView);
gGlob.pShadowCamera->SetProjectionMatrix(matLightProj);

// Render the depth (shadow) map (note that this automatically clears the associated depth-stencil view)
gGlob.pShadowCamera->RenderDepthOnly(true);

The implementations of util::TransformFloat3 and util::TransformTransposedFloat3 are direct copies, with the change that they use the XMFLOAT3 struct instead of Vector3, of the implementations given by Tardif here: http://alextardif.com/code/transformvector3.txt

For completedness, here's my code for those as well:

inline XMFLOAT3 TransformFloat3(const XMFLOAT3& point, const XMMATRIX& matrix) {
	XMFLOAT3 result;
	XMFLOAT4 temp(point.x, point.y, point.z, 1);	// Need a 4-part vector in order to multiply by a 4x4 matrix
	XMFLOAT4 temp2;

	temp2.x = temp.x * matrix._11 + temp.y * matrix._21 + temp.z * matrix._31 + temp.w * matrix._41;
	temp2.y = temp.x * matrix._12 + temp.y * matrix._22 + temp.z * matrix._32 + temp.w * matrix._42;
	temp2.z = temp.x * matrix._13 + temp.y * matrix._23 + temp.z * matrix._33 + temp.w * matrix._43;
	temp2.w = temp.x * matrix._14 + temp.y * matrix._24 + temp.z * matrix._34 + temp.w * matrix._44;

	result.x = temp2.x / temp2.w;			// View projection matrices make use of the W component
	result.y = temp2.y / temp2.w;
	result.z = temp2.z / temp2.w;

	return result;
}

inline XMFLOAT3 TransformTransposedFloat3(const XMFLOAT3& point, const XMMATRIX& matrix) {
	XMFLOAT3 result;
	XMFLOAT4 temp(point.x, point.y, point.z, 1);	// Need a 4-part vector in order to multiply by a 4x4 matrix
	XMFLOAT4 temp2;

	temp2.x = temp.x * matrix._11 + temp.y * matrix._12 + temp.z * matrix._13 + temp.w * matrix._14;
	temp2.y = temp.x * matrix._21 + temp.y * matrix._22 + temp.z * matrix._23 + temp.w * matrix._24;
	temp2.z = temp.x * matrix._31 + temp.y * matrix._32 + temp.z * matrix._33 + temp.w * matrix._34;
	temp2.w = temp.x * matrix._41 + temp.y * matrix._42 + temp.z * matrix._43 + temp.w * matrix._44;

	result.x = temp2.x / temp2.w;			// View projection matrices make use of the W component
	result.y = temp2.y / temp2.w;
	result.z = temp2.z / temp2.w;

	return result;
}

Any light-shedding on what may be at fault here would be most welcome.

I can also provide my HLSL code if requested but I don't see how that can really be at fault since it doesn't do any offsetting or such and the shadow are after all projected where they should, were it not for the jumping around between frames. So I believe the fault should be with the depth (shadow) map rendering as outlined above.

The depth map is a slice in a Texture2DArray, 2048x2048 pixels in size and uses the DXGI_FORMAT_D32_FLOAT format. Naturally it has only a single mip slice.




#5256930 How to create a depth-stencil-only pixel shader?

Posted by Husbjörn on 12 October 2015 - 04:22 PM

Right, it turns out I accidentally had set a normal rendering shader to a billboard instead of this depth one, so that was indeed trying to write to SV_Target. How embarrasing. On the upside, no more warnings now that I have fixed that oversight!

Thanks a lot for pointing it out ajmiles and Matias Goldberg :)




#5227275 Inconsistent falloff for light sources

Posted by Husbjörn on 05 May 2015 - 04:30 AM

I've been trying to implement lighting in my project, essentially following the method that is described here: http://www.3dgep.com/texturing-lighting-directx-11

 

While this does seemingly work, I've noticed some discrepancies where it essentially appears that certain meshes receive more light than they should based on their distance from the light source(s).

Here's an image showcasing this issue with a spot light:

SpotLightProblem.png

The light source is situated a small distance above the floor and is aimed straight along the Z axis. As can be seen the light fall off such that it is essentially non-inifluential at the floor where the wall is, yet the wall receives a lot more light than I feel it should at this distance.

 

Still, one may think that this could possibly be related to the fact that the imaginary light rays hit the wall straight on as opposed to the floor and as such would light it up more. However, the same problem is also evident with omnidirectional light sources which in this case should have the same effect on all surfaces it hits (including the floor). As can be seen in the following image this is not the case however.

The dark circle is a semi-transparent sphere indicating the position of the light source and not a shadow of the sphere above it by the way; no shadow mapping has been implemented yet.

 

PointLightProblem.png

 

 

I am wondering what might be the cause of this.

All walls / floor / ceiling are just instances of the same quad mesh repositioned and rotated using world matrices so I don't believe it would relate to one (read: all) of these having incorrect normal data or such.

Also when only rendering the calculated attenuation (see the link above), it does indeed fall off as it "should" from the light source and opposite walls do not get a greater influence so the problem shouldn't be related to the attenuation factor either.

 

From what I can gather, it would in fact seem the problem relates to this function, since only returning C from it also causes proper falloff:

/**
 * Calculates the diffuse contribution of a light source at the given pixel.
 * @param L		- Light direction in world space
 * @param N		- Normal direction of the pixel being rendered in world space
 * @param C		- Light colour
 **/
float4 CalculateDiffuseContrib(float3 L, float3 N, float4 C) {
	float NL = max(0, dot(N, L));
	return C * NL;
}

Since the only real factor here is the fragment normal (the light direction should be correct and is calculated as normalize(lightPos - fragmentPos), where both are in world space) I imagine the problem would have to be somehow related to that.

I am using normal mapping in the above screenshots, but even when using interpolated vertex normals the results are the same.

 

Is this a common occurence, or may it even be that this is how it is supposed to look?

Thanks in advance for any illuminating (wink.png) replies!




#5217969 Simplifying Assimp 3.1-imported FBX scenes

Posted by Husbjörn on 20 March 2015 - 04:29 PM

Ah yes, well there is a single offset / pivot matrix per node. Those outlined up there are in excess to them.

Basically I have built my animation system around this matFinalTransform = (parentNode ? parentNode->matFinalTransform : IdentityMatrix) * matOffset * matScaling * matRotation * matTranslation based on the import structure exposed by the Assimp library. All 3D models imported using Assimp 3.0 adheres to this format so I just have the single conversion of it into my own format. However, the FBX Importer that comes with Assimp 3.1.x+ imports a more complex node hierarchy where all the matrices above are added together by linking them in sub-trees per actual "master node". Because this results in many times more nodes than the actual model has this, while technically working, is inefficient to use. So therefore I want to convert it to the simplified structure mentioned above. I should also point out that these sub-node hierarchies do contain individual offset matrices for not necessarily all but many of the nodes that aren't just set to the identity matrix so it isn't as simple as them just replacing that.

 

An example hierarchy might be:

Root
  - Spine01
    - Spine01_$Complex$_Translation [offset matrix != identity]
      - Spine01_$Complex$_RotationOffset [offset matrix != identity]
        - Spine01_$Complex$_RotationPivot [offset matrix == identity]
          - Spine01_$Complex$_PreRotationOffet [offset matrix == identity]
            - Spine01_$Complex$_Rotation [offset matrix != identity]
              - Spine01_$Complex$_PostRotationOffset [offset matrix != identity, no animation keys]
                - Spine01_$Complex$_RotationPivotInverse [offset matrix != identity, no keys]
                  - Spine01_$Complex$_ScalingOffset [offset matrix == identity, single key]
                    - Spine01_$Complex$_ScalingPivot [offset matrix != identity, no keys]
                      - Spine01_$Complex$_Scaling [offset matrix != identity]
                        - Spine01_$Complex$_ScalingPivotInverse [offset matrix != identity, no keys]
  - Spine02
    - Spine01_$Complex$_Translation
      ... and so on

As far as I can tell, all of the special offset ones aren't animated but they either store their offset as a single key, or in the assimp-assigned offset matrix of the node, OR both of those carry different, non-identity data.

 

 

The fact that you can import an FBX file into most modelling software and then export it to another format that uses the offset + SRT transform order bespeaks that it is indeed possible to do this conversion.

Basically I guess the FBX is imported with that data because it might be interesting to preserve for modelling applications but for use in a realtime game it just isn't reasonable to have meshes with 400+ "joints" like that.




#5217877 Simplifying Assimp 3.1-imported FBX scenes

Posted by Husbjörn on 20 March 2015 - 09:47 AM

Well, to further specify the problem at hand I essentially want to turn this:

transform = translation * rotationOffset * rotationPivot * preRotationOffset * rotation * postRotationOffset * rotationPivotInverse * scalingOffset * scalingPivot * scaling * scalingPivotInverse;

into the more simple, traditional three components scaling, rotation, translation such that the following statement would hold true assuming the above assignment of transform:

transform == _scaling * _rotation * _translation;

Now that I see it in front of me... building the first matrix from the input data and then decomposing it into the SRT components would surely not work would it? That seems way too easy mellow.png

(I have put this problem aside for the last couple of weeks so I don't really remember but I can't believe I wouldn't have examined that possibility).




#5191574 Getting around non-connected vertex gaps in hardware tessellation displacemen...

Posted by Husbjörn on 06 November 2014 - 03:43 PM

Off the top of my head each individual face of your cube is tessellated and then displaced.

You need to ensure that the edge vertices are shared in each (subdivided) side-face or else these seams will occur since all vertices on the top face are displaced only along the up axis and all vertices of the front face are displaced only along the depth axis.

A simple solution is to displace along the vertex normals and ensure that whereever you have overlapping vertices (such as at the corners of a cube) you set the normal of all such vertices to the average of all "actual" vertex normals at that position. This will make the edges a bit more bulky but keep the faces connected.

 

My previous post in this thread (just above yours) describes how I solved this in a relatively simple way in more detail.




#5178123 Seemingly incorrect buffer data used with indirect draw calls

Posted by Husbjörn on 04 September 2014 - 01:13 PM


Like any other GPU-executed command, CopyStructureCount has implicit synchronization with any commands issued afterwards. So there shouldn't be any kind of manual waiting or synchronization required, the driver is supposed to handle it.

That's what I thought.

 

After a third rewrite (and a full rendering shader rewrite as well) it turned out I managed to build my quads the wrong way in the geometry shader so that they weren't visible; the appropriate vertex count does indeed seem to be passed to the DrawInstancedIndirect call. However, RenderDoc is still reporting the call as having a zero argument for the vertex count, so I guess there's a quite sneaky bug in there too which threw me off (naturally I expected it to give the correct output).

Thanks for your suggestions though smile.png

 

 

Edit: Didn't see your ninja post baldurk.

 

 

 

To clarify - the number that you see in the DrawInstancedIndirect(<X, Y>) in the event browser in RenderDoc is just retrieved the same way as you described by copying the given buffer to a staging buffer, and mapping that.

That is indeed weird because now I do get the proper count read back if I map it to a staging buffer myself and the correct draw results, yet RenderDoc claims this function is called with the arguments <0, 1>. I guess it clips away the last two offset integers because in reality the buffer should contain 4 values (mine would be x, 1, 0, 0) right?

My byte offset is zero, there is nothing more in the indirect buffer than the 16 bytes representing the argument list.

 

I'll try to add to my currently working minimalistic program to see if it still renders correctly and whether RenderDoc will keep on showing that 0 (or something else that's unreasonable) and get back. Maybe the problems will resurface in a different way once I add some complexity back in, though I hope not.




#5172779 Unordered access view woes with non-structured buffers

Posted by Husbjörn on 11 August 2014 - 08:05 AM

RWBuffer<float3> RWBuf : register(u0);

But it fails at the call to ID3D11Device::CreateUnorderedAccessView so I don't think the shader declaration is of any relevance since they haven't been bound together yet by then.






PARTNERS