Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 24 Jul 2013
Offline Last Active Yesterday, 01:30 PM

Topics I've Started

Shallow Water

16 January 2015 - 11:04 AM



I've been experimenting with the shallow water equations but I can't seem to get my implementation correct. I'm following this except I'm doing everything on the GPU. I'm not sure where I keep going wrong: see here. From my experimentations with the full Navier-Stokes equations, this makes sense: I remember getting visually similar results (in 2D) where the circle forms into a square-like corner (plotted a circle with velocity (1,1) at every pixel). But this only happened when I stopped the simulation after the advection step ("skipped" projection). Not sure what is happening here. I've tried changing the signs when sampling data as well as switching the order of operations around but nothing seems to work. At one point I ended up with this, which is obviously not correct.


Here are my simulation kernels (I won't post my advection kernel as it is the same one I used for my full NS solver; also note that using a staggered grid whereby a single pixel represents left-bottom pair of velocities for velocity kernels (boundaries are set appropriately to account for the array size differences)):


UpdateHeight kernel

float4 PSMain(PSInput input) : SV_TARGET {
float2 texCoord = input.position.xy * recTexDimensions.xy;
float vL = velocity.Sample(pointSampler, texCoord).x;
float vR = velocity.Sample(pointSampler, texCoord + float2(recTexDimensions.x, 0.0f)).x;
float vT = velocity.Sample(pointSampler, texCoord + float2(0.0f, recTexDimensions.y)).y;
float vB = velocity.Sample(pointSampler, texCoord).y;
float h = height.Sample(pointSampler, texCoord).x;
float newH = h - h * ((vR - vL) * recTexDimensions.x + (vT - vB) * recTexDimensions.y) * dt;
return float4(newH, 0.0f, 0.0f, 0.0f);
float4 PSMain(PSInput input) : SV_TARGET {
float2 texCoord = input.position.xy * recTexDimensions.xy;
float u = velocity.Sample(pointSampler, texCoord).x;
float hL = height.Sample(pointSampler, texCoord - float2(recTexDimensions.x, 0.0f)).x;
float hR = height.Sample(pointSampler, texCoord).x;
float uNew = u + g * (hL - hR) * recTexDimensions.x * dt;
return float4(uNew, 0.0f, 0.0f, 0.0f);
float4 PSMain(PSInput input) : SV_TARGET {
float2 texCoord = input.position.xy * recTexDimensions.xy;
float v = velocity.Sample(pointSampler, texCoord).y;
float hB = height.Sample(pointSampler, texCoord - float2(0.0f, recTexDimensions.y)).x;
float hT = height.Sample(pointSampler, texCoord).x;
float vNew = v + g * (hB - hT) * recTexDimensions.y * dt;
return float4(0.0f, vNew, 0.0f, 0.0f);


I've literally spent the entire day debugging this and I've got no idea why nothing seems to work... Hopefully some of you guys have implemented this before and can help me out.


Thanks in advance!

Renormalizing bilinear interpolation weights

03 January 2015 - 12:24 PM



I need to change the default bilinear interpolation functionality to only use known values for interpolation by biasing the weights based on the contents of the 4 pixels, e.g. if one of the four pixels is (0.0, 0.0, 0.0, 0.0) then bias the lerp() function towards the nonzero neighbouring pixel. At least that's what I've understood I need to do for extrapolating velocities (stored in textures) for my fluid simulation, direct quote here:



We then go through the levels from finest to coarsest and obtain velocities by tri-linear interpolation of the velocities of the previous level using only known velocities and renormalizing the interpolation weights accordingly.



I've written a bilinear interpolation function based on what I've found on the web:

static const float2 recTexDim = float2(1.0f / 48.0f, 1.0f / 48.0f); // as a test case, the source image is 48x48
float4 bilerp(float2 texCoord) {
float2 t = frac(texCoord / recTexDim);
float4 tl = source.Sample(pointSampler, texCoord);
float4 tr = source.Sample(pointSampler, texCoord + float2(recTexDim.x, 0.0f));
float4 bl = source.Sample(pointSampler, texCoord + float2(0.0f, recTexDim.y));
float4 br = source.Sample(pointSampler, texCoord + float2(recTexDim.x, recTexDim.y));
return lerp(lerp(tl, tr, t.x), lerp(bl, br, t.x), t.y);
float4 PSMain(PSInput input) : SV_TARGET {
float4 custom =  bilerp(input.texCoord);
float4 builtIn = source.Sample(linearSampler, input.texCoord);
return abs(custom - builtIn);

If my code were correct, the resulting image should be all black (i.e. no difference between the interpolation functions). However I get the following result: http://postimg.org/image/3walbutj1/


I'm not sure where I'm going wrong here. Also, have I even understood the "renormalizing interpolation weights" bit correctly?


Thanks in advance!

Level sets and loss of volume

04 October 2014 - 01:50 PM



I've been trying to convert my simple 2D fluid solver to a liquid solver with a free surface. For that I've introduced the level set method into the application. However, I seem to be losing mass/volume at a ridiculous speed. Here are two videos showing exactly what I mean: I switch between rendering the advected color vector and the the level set where phi < 0 (i.e. the inside of the liquid, rendered as black).





From what I've read from the papers, the problem is that after advection, phi doesn't hold the signed distance anymore and needs to be reinitialized. However, I've got no idea how one would do it. Some papers have mentioned fast marching method but from what I can understand, it doesn't suit well for GPUs (my solver is completely GPU based). Some other papers mentioned Eikonal solvers in their references but I literally have no idea what/how to proceed.


Any help would be greatly appreciated: bonus points if anyone can link to a tutorial/instructional text that isn't a high-level implementation paper glancing over details.


Here's how I've defined the signed distance initially:

float2 p = input.position.xy - pointCenter;
float s = length(p) - radius;
return float4(s, s, s, 1.0f);
Thanks in advance!

Volume Rendering: Eye Position to Texture Space?

27 September 2014 - 01:36 PM



I've been trying to set up a volume renderer but I'm having trouble getting the ray marching data set up correctly. I use a cube which has extents in positive directions, i.e. the vertex definitions look like (1,0,0), (1,1,0) etc which give me implicitly defined texture coordinates where the v-dir needs to be inverted later. Then what I do:


1) render cube with front face culling, record fragment distance from eye to the fragments position in the alpha channel (GPU Gems 3 article's source code uses the w-component of the vertex after world-view-projection multiplication), i.e. in pixel shader after interpolation of the per-vertex dist return float4(0.0f, 0.0f, 0.0f, dist);

2) turn on subtractive blending, render cube with back face culling, record negative generated texture coordinates in rgb channel and the distance to this fragment in the alpha channel, i.e. return float4(-texCoord, dist) where texCoord is the original vertex input coordinate.


I now have a texture where the rgb channels give the entry point of the ray in texture space and the alpha channel gives the distance through the volume.


However, how would I now get the direction vector? GPU Gems 3 says:


"The ray direction is given by the vector from the eye to the entry point (both in texture space)."


How does one transform the eye position to texture space, so I could put it in a constant buffer for the shader?


Thanks in advance!

Constructing min/max corners of a collision mesh

29 August 2014 - 07:34 AM

I'm having a bit of trouble with constructing the minimum and maximum corners of a collision mesh. I think it's best to explain what steps I'm going through:
1) load 3D mesh, assign a world matrix to it (translation, rotation), assign bounding box half extents
2) when a specific event happens in application, generate a 3D bounding box for the mesh using previously defined half extents. This is mainly for debugging as I'm filling the volume defined by this mesh with smaller cubes later. For rendering I'm  generating a cuboid mesh centered around (0,0,0) with the half extents and assign the same world matrix as the original mesh. Rendering this shows the mesh is in the correct place.
3) Now I need to check for collisions only on the xz-plane. To do this, I "construct" a cuboid from min/max corners and transform that to the position of the mesh. Now here is the problem though: I don't know how/where I'm going wrong but the min/max corners don't seem to be right. For example:
mesh half extents on xz (1.05, 0.5) -> constructed min = (-4, -3.5) and max = (-5, -1.45). How can min.x > max.x?
Here's the relevant code bit (broadCollisionMeshExtents == half extents):
D3DXMATRIX wMat = linkedObj.object->GetWorldMatrix();
D3DXVECTOR2 extents(linkedObj.broadCollisionMeshExtents->x, linkedObj.broadCollisionMeshExtents->z);
D3DXVECTOR3 minimum = D3DXVECTOR3(-extents.x, 0.0f, -extents.y);
D3DXVECTOR3 maximum = D3DXVECTOR3(extents.x, 0.0f, extents.y);
D3DXVec3Transform(&min4, &minimum, &wMat);
D3DXVec3Transform(&max4, &maximum, &wMat);
minimum = D3DXVECTOR3(min4);
maximum = D3DXVECTOR3(max4);
This seems to work as long as the objects don't have any rotation on them. I can sort of force-fix it by doing:
float maxX = maximum.x;
float maxZ = maximum.z;
float minX = minimum.x;
float minZ = minimum.z;
maximum = D3DXVECTOR3(max(maxX, minX), 0.0f, max(maxZ, minZ));
minimum = D3DXVECTOR3(min(maxX, minX), 0.0f, min(maxZ, minZ));
... but that's just silly. I'm not entirely sure as to what is going on, any help would be greatly appreciated.
Thanks in advance!