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

cephalo

Member Since 04 Mar 2011
Offline Last Active May 15 2013 02:04 PM
*****

#5057122 How to Use Perlin Simplex Noise?

Posted by cephalo on 26 April 2013 - 07:51 PM

You can use Perlin noise for literally EVERYTHING. There is no natural phenomena that you can simulate that won't benefit from this kind of noise input. Terrain maps, mold growth, pimple production, creature mannerisms, river networks, galaxy formation, you name it. Perlin noise simulates nature on many, many levels.

 

EDIT: I forgot to mention social aggression in bonobos, and many other things.




#5057119 How much to tessellate?

Posted by cephalo on 26 April 2013 - 07:26 PM

 

Nice job sticking to it - so where is the obligatory screen shot showing us the low and high res triangles all at once???

 

Alrighty then. I'm actually still futzing with the LOD settings, but I do have an interesting discovery. Here is the new code, I tried to do some culling of the backward triangle patches, but in this case the surface can protrude too much and the gaps are visible. I also tried to greatly reduce the tessellation in that case, but the popping was very noticeable.

PatchConstants PatchHS(InputPatch<VertexOutput,10> cp, uint patchID : SV_PrimitiveID)
{
	PatchConstants pt;

	float4 corner0 = mul(float4(cp[0].PositionWorld,1.0f),ViewProjection);
	float4 corner1 = mul(float4(cp[1].PositionWorld,1.0f),ViewProjection);
	float4 corner2 = mul(float4(cp[2].PositionWorld,1.0f),ViewProjection);

	corner0 = corner0/(corner0.w + 0.00001f);
	corner1 = corner1/(corner1.w + 0.00001f);
	corner2 = corner2/(corner2.w + 0.00001f);

	static const float dMax = 1.5f;
	static const float dMin = 0.04f;

	float dist0 = distance(corner1.xy,corner2.xy);
	float dist1 = distance(corner2.xy,corner0.xy);
	float dist2 = distance(corner0.xy,corner1.xy);

	pt.EdgeTess[0] = 64.0f * saturate((dist0 + dMin)/(dMax + dMin));

	pt.EdgeTess[1] = 64.0f * saturate((dist1 + dMin)/(dMax + dMin));

	pt.EdgeTess[2] = 64.0f * saturate((dist2 + dMin)/(dMax + dMin));

	pt.InsideTess = min(pt.EdgeTess[0],min(pt.EdgeTess[1],pt.EdgeTess[2]));

	//corner0.z = 0.0f;
	//corner1.z = 0.0f;
	//corner2.z = 0.0f;

	//float3 winding = cross(corner1 - corner0,corner2 - corner0);
	//if(winding.z > 0)
	//{
	//	pt.InsideTess = 1.0f;
	//}

	return pt;
}

Here is the interesting part. I originally chose 'fractional_even' arbitrarily. Switching to 'fractional_odd' can completely change the look of the scene. First is the view from central Taffy Mountain looking west with fractional even partitioning:

CTLookingWestEven.jpg

 

Now the from the same vantage with fractional odd partitioning:

CTLookingWestOdd.jpg

 

At least in this particular case, I would say that fractional odd has far fewer undesireable artifacts! It's an interesting consequence.




#5057041 How much to tessellate?

Posted by cephalo on 26 April 2013 - 12:33 PM

Ok, I have that squared away and I'm back in business! My algorithm works great, I just have to tweak it so that both low detail and high detail aren't so quick to appear. I can handle that.

 

After this I'll need to see some performance info of some kind, so I need to print text. I'll open a new thread for that. My research on that topic has given me some conflicting info.




#5056435 Ugly lines on screen.

Posted by cephalo on 24 April 2013 - 01:52 PM

It looks like discontinuous normals. I can't tell how they are calculated from the picture. Is this object made of multiple patches stitched together? If so, continuous normals are not easy to achieve. Perhaps the content maker decided they were good enough.




#5055019 Calculating Surface Normal on a Bezier Triangle

Posted by cephalo on 19 April 2013 - 03:11 PM

Well, I tried something similar to PN-Triangles, in that I am interpolating normals from the edge, and here is the result. It's sort of continuous across triangles, but not very well defined like the above example. I may get better results if I increase the order of control points to interpolate, but then we are getting into slow territory. It's a tough problem!

Bad Normals5.jpg

 

Here is my new hull shader and domain shader. In the hull shader I am using de Casteljau's on the curve made by the edge in order to get the n110, n011 and n101 normals for interpolation. This is a bit different than with standard PN-Triangles:

 

#define p300 0
#define p030 1
#define p003 2
#define p210 3
#define p201 4
#define p120 5
#define p021 6
#define p012 7
#define p102 8
#define p111 9

#define n200 0
#define n020 1
#define n002 2
#define n110 3
#define n011 4
#define n101 5

struct VertexOutput
{
	float3 PositionWorld	: POSITION;
	float2 MainTexCoord		: TEXCOORD;
};

struct PatchConstants
{
	float EdgeTess[3]	: SV_TessFactor;
	float InsideTess	: SV_InsideTessFactor;

	float3 NormalCP[6]	: NORMAL;
};

PatchConstants PatchHS(InputPatch<VertexOutput,10> cp, uint patchID : SV_PrimitiveID)
{
	PatchConstants pt;

	pt.EdgeTess[0] = 12;
	pt.EdgeTess[1] = 12;
	pt.EdgeTess[2] = 12;
	pt.InsideTess = 12;

	pt.NormalCP[n200] = float3(0,1,0);
	pt.NormalCP[n020] = float3(0,1,0);
	pt.NormalCP[n002] = float3(0,1,0);

	float t = 0.5f;
	float3 bitangent;

	float3 p1_0 = (1.0f - t) * cp[p300].PositionWorld + t * cp[p210].PositionWorld;
	float3 p1_1 = (1.0f - t) * cp[p210].PositionWorld + t * cp[p120].PositionWorld;
	float3 p1_2 = (1.0f - t) * cp[p120].PositionWorld + t * cp[p030].PositionWorld;

	float3 p2_0 = (1.0f - t) * p1_0 + t * p1_1;
	float3 p2_1 = (1.0f - t) * p1_1 + t * p1_2;
	
	float3 tangent = normalize(p2_1 - p2_0);
	float3 offline = normalize(cp[p030].PositionWorld - cp[p300].PositionWorld);
	if(cp[p030].PositionWorld.y > cp[p300].PositionWorld.y)
	{
		bitangent = normalize(cross(offline,tangent));
	}
	else
	{
		bitangent = normalize(cross(tangent,offline));
	}
	pt.NormalCP[n110] = normalize(cross(bitangent, tangent));

	p1_0 = (1.0f - t) * cp[p030].PositionWorld + t * cp[p021].PositionWorld;
	p1_1 = (1.0f - t) * cp[p021].PositionWorld + t * cp[p012].PositionWorld;
	p1_2 = (1.0f - t) * cp[p012].PositionWorld + t * cp[p003].PositionWorld;

	p2_0 = (1.0f - t) * p1_0 + t * p1_1;
	p2_1 = (1.0f - t) * p1_1 + t * p1_2;
	
	tangent = normalize(p2_1 - p2_0);
	offline = normalize(cp[p003].PositionWorld - cp[p030].PositionWorld);
	if(cp[p003].PositionWorld.y > cp[p030].PositionWorld.y)
	{
		bitangent = normalize(cross(offline,tangent));
	}
	else
	{
		bitangent = normalize(cross(tangent,offline));
	}
	pt.NormalCP[n011] = normalize(cross(bitangent, tangent));

	p1_0 = (1.0f - t) * cp[p003].PositionWorld + t * cp[p102].PositionWorld;
	p1_1 = (1.0f - t) * cp[p102].PositionWorld + t * cp[p201].PositionWorld;
	p1_2 = (1.0f - t) * cp[p201].PositionWorld + t * cp[p300].PositionWorld;

	p2_0 = (1.0f - t) * p1_0 + t * p1_1;
	p2_1 = (1.0f - t) * p1_1 + t * p1_2;
	
	tangent = normalize(p2_1 - p2_0);
	offline = normalize(cp[p300].PositionWorld - cp[p003].PositionWorld);
	if(cp[p300].PositionWorld.y > cp[p003].PositionWorld.y)
	{
		bitangent = normalize(cross(offline,tangent));
	}
	else
	{
		bitangent = normalize(cross(tangent,offline));
	}
	pt.NormalCP[n101] = normalize(cross(bitangent, tangent));

	return pt;
}

struct HullOut
{
	float3 PositionWorld	: POSITION;
	float2 MainTexCoord		: TEXCOORD;
};

[domain("tri")]
[partitioning("fractional_even")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(10)]
[patchconstantfunc("PatchHS")]
HullOut HS(InputPatch<VertexOutput,10> p, uint i : SV_OutputControlPointID, uint patchId : SV_PrimitiveID)
{
	HullOut hout;

	hout = p[i];

	return hout;
}

 

And here is the interpolation in the domain shader:

#define p300 0
#define p030 1
#define p003 2
#define p210 3
#define p201 4
#define p120 5
#define p021 6
#define p012 7
#define p102 8
#define p111 9

#define n200 0
#define n020 1
#define n002 2
#define n110 3
#define n011 4
#define n101 5

#define U bary.x
#define V bary.y
#define W bary.z

cbuffer PerFrameBuffer : register(b0)
{
	//float4x4 World; This is just the identity matrix, so not needed
	float4x4 ViewProjection;
	float4 vecEye; 
	float4 LightDirection;
	float4 LightColor; 
};

struct PatchConstants
{
	float EdgeTess[3]	: SV_TessFactor;
	float InsideTess	: SV_InsideTessFactor;

	float3 NormalCP[6]	: NORMAL;
};

struct HullOut
{
	float3 PositionWorld	: POSITION;
	float2 MainTexCoord		: TEXCOORD;
};

struct DomainOut
{
	float4 PositionH		: SV_Position;
	float3 Normal			: NORMAL0;
	float3 Tangent			: TANGENT0;
	float3 Bitangent		: BITANGENT0;
	float3 View				: NORMAL1;
	float2 MainTexCoord		: TEXCOORD0;
};

[domain("tri")]
DomainOut DS(PatchConstants pc, float3 bary : SV_DomainLocation, const OutputPatch<HullOut,10> cp)
{
	DomainOut dout;

	float3 p1_200 = U * cp[p300].PositionWorld + V * cp[p210].PositionWorld + W * cp[p201].PositionWorld;
	float3 p1_110 = U * cp[p210].PositionWorld + V * cp[p120].PositionWorld + W * cp[p111].PositionWorld;
	float3 p1_101 = U * cp[p201].PositionWorld + V * cp[p111].PositionWorld + W * cp[p102].PositionWorld;
	float3 p1_020 = U * cp[p120].PositionWorld + V * cp[p030].PositionWorld + W * cp[p021].PositionWorld;
	float3 p1_011 = U * cp[p111].PositionWorld + V * cp[p021].PositionWorld + W * cp[p012].PositionWorld;
	float3 p1_002 = U * cp[p102].PositionWorld + V * cp[p012].PositionWorld + W * cp[p003].PositionWorld;

	float3 p2_100 = U * p1_200 + V * p1_110 + W * p1_101;
	float3 p2_010 = U * p1_110 + V * p1_020 + W * p1_011;
	float3 p2_001 = U * p1_101 + V * p1_011 + W * p1_002;

	float3 position = U * p2_100 + V * p2_010 + W * p2_001;

	//float3 tangent = p2_010 - p2_100;
	//float3 bitangent = p2_001 - p2_100;

	//tangent = normalize(tangent);
	//bitangent = normalize(bitangent);
	float3 normal = pow(U,2) * pc.NormalCP[n200] +
		pow(V,2) * pc.NormalCP[n020] +
		pow(W,2) * pc.NormalCP[n002] + 
		U * V * pc.NormalCP[n110] + 
		U * W * pc.NormalCP[n101] +
		V * W * pc.NormalCP[n011];

	dout.View = vecEye.xyz - position.xyz;
	dout.PositionH = mul(float4(position,1.0f),ViewProjection);
	dout.Normal = normalize(normal);
	dout.Tangent = float3(0,1,0);
	dout.Bitangent = float3(0,1,0);

	dout.MainTexCoord = cp[p300].MainTexCoord * U + cp[p030].MainTexCoord * V + cp[p003].MainTexCoord * W;

	return dout;
}



#5054307 [solved]My tessellation pipeline that draws nothing.

Posted by cephalo on 17 April 2013 - 02:57 PM

Wow, I turned on my pixel shading, and as you can see, my normal calculations are completely nonsensical. Still, after extending the hex map to 120x120 hexes, without any optimization of the tessellation for distance, the framerate I'm getting makes me giggle with glee! I don't have a working framerate counter yet (not so easy in DX11) but the camera controls feel like buttah!

 

FunkyShading.jpg




#5054303 [solved]My tessellation pipeline that draws nothing.

Posted by cephalo on 17 April 2013 - 02:32 PM

One thing: Disable stencil.


IsStencilEnabled = false,

 

I can see! I was blind and now I can see! You guys are friggen miracle workers. Thanks so much! Ahhhh I feel much better now.

ICanSee.jpg

 

This is cool. The DX9 version was extremely complex and used far too much video memory. DX11 offers features that allow me to use 1/100th of the memory and probably at a higher framerate, maybe even with some displacement mapping! Thanks again everyone.




#5044867 SlimDX future?

Posted by cephalo on 20 March 2013 - 07:17 AM

I can verify that switching from SlimDX to SharpDX is almost trivial, even for a newb like me, if you're concerned about continued development.




PARTNERS