Skip to content

CAD DTM Rendering #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 131 commits into
base: master
Choose a base branch
from
Open

CAD DTM Rendering #186

wants to merge 131 commits into from

Conversation

Erfan-Ahmadi
Copy link
Contributor

@Erfan-Ahmadi Erfan-Ahmadi commented Mar 25, 2025

CAD DTM Rendering Example
Devsh-Graphics-Programming/Nabla#858


// calculate screen space coordinates of vertices of t
// he current tiranlge within the grid
float3 v[3];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of general variable names, use more specific. like currentTriangleVertices or something better
unconventional idea: give this code (this code is open source) to chat gpt and tell it to suggest better variable names based on it's understanding

cellCoords.y = uint32_t(gridSpacePosDivGridCellWidth.y);
}

float2 insideCellCoord = gridSpacePos - float2(cellWidth, cellWidth) * cellCoords; // TODO: use fmod instead?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devshgraphicsprogramming what do you think about adding OpFMod to our builtins?


float2 insideCellCoord = gridSpacePos - float2(cellWidth, cellWidth) * cellCoords; // TODO: use fmod instead?

const float InvalidHeightValue = asfloat(0x7FC00000);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this a global variable in globals.hlsl with an accompanying isInvalidHeightValue we might do a comparison check against a very low value instead of using NaN

if (textureId != InvalidTextureIndex)
{
const float2 maxCellCoords = float2(round(gridExtents.x / cellWidth), round(gridExtents.y / cellWidth));
const float2 location = (cellCoords + float2(0.5f, 0.5f)) / maxCellCoords;
Copy link
Contributor Author

@Erfan-Ahmadi Erfan-Ahmadi Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why force sampling the middle of the texel when you can just use the uv value?
you're getting the cell coordinates based on uv and then you're gathering from exactly the middle.
I don't think it's going to affect the result of your gather, because gather will act very similar to your code getting the cell coordinates to gather the pixels from.
Please let me know if I'm missing something

INVALID
};

E_CELL_DIAGONAL resolveGridDTMCellDiagonal(in float4 cellHeights)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move these to dtm header

static const E_CELL_DIAGONAL DefaultDiagonal = TOP_LEFT_TO_BOTTOM_RIGHT;

const bool4 invalidHeights = bool4(
isnan(cellHeights.x),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use IsInvalid from the new globals.hlsl function I mentioned in https://github.com/Devsh-Graphics-Programming/Nabla-Examples-and-Tests/pull/186/files#r2133674200

Comment on lines +491 to +492
if (cellDiagonal == E_CELL_DIAGONAL::INVALID)
discard;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're going to handle it when doing the dilation emulation (when you iterate over all neighbouring cells)
but I'm going to say it again anyways (sorry): we shouldn't discard

float2 insideCellCoord = gridSpacePos - float2(cellWidth, cellWidth) * cellCoords; // TODO: use fmod instead?

const float InvalidHeightValue = asfloat(0x7FC00000);
float4 cellHeights = float4(InvalidHeightValue, InvalidHeightValue, InvalidHeightValue, InvalidHeightValue);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment the formation: is it (TL, TR, BL, BR) for example?

Comment on lines +499 to +514
float2 gridSpaceCellTopLeftCoords = cellCoords * cellWidth;

//printf("uv = { %f, %f } diagonalTLtoBR = %i triangleA = %i, insiceCellCoords = { %f, %f }", uv.x, uv.y, int(diagonalFromTopLeftToBottomRight), int(triangleA), insideCellCoord.x / cellWidth, insideCellCoord.y / cellWidth);

if (diagonalFromTopLeftToBottomRight)
{
v[0] = float3(gridSpaceCellTopLeftCoords.x, gridSpaceCellTopLeftCoords.y, cellHeights.w);
v[1] = float3(gridSpaceCellTopLeftCoords.x + cellWidth, gridSpaceCellTopLeftCoords.y + cellWidth, cellHeights.y);
v[2] = triangleA ? float3(gridSpaceCellTopLeftCoords.x, gridSpaceCellTopLeftCoords.y + cellWidth, cellHeights.x) : float3(gridSpaceCellTopLeftCoords.x + cellWidth, gridSpaceCellTopLeftCoords.y, cellHeights.z);
}
else
{
v[0] = float3(gridSpaceCellTopLeftCoords.x, gridSpaceCellTopLeftCoords.y + cellWidth, cellHeights.x);
v[1] = float3(gridSpaceCellTopLeftCoords.x + cellWidth, gridSpaceCellTopLeftCoords.y, cellHeights.z);
v[2] = triangleA ? float3(gridSpaceCellTopLeftCoords.x, gridSpaceCellTopLeftCoords.y, cellHeights.w) : float3(gridSpaceCellTopLeftCoords.x + cellWidth, gridSpaceCellTopLeftCoords.y + cellWidth, cellHeights.y);
}
Copy link
Contributor Author

@Erfan-Ahmadi Erfan-Ahmadi Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you see sdf codes in shadertoy there is a nice trick when it comes to the coordinate space you do your SDFs in.

You're trying very hard to convert your triangle points to screensapce by computing and adding gridSpaceCellTopLeftCoords to every triangle vertex. then later on adding topLeft of the grid to everypoint and doing sdf with input.position.xy

Now the simple trick is: instead of converting every point in the cell to screenspace, compute your vertices in local grid cell and convert your point to local grid cell and do sdf with: (`input.position.xy - (gridTopLeft + cellTopLeft))

It will give you the exact same sdf and instead of 3*2 vector additions you just get 1 subtraction to bring your point in question to local grid cell.

your vertices for example can be (0, 0, h0) & (cellWidth, 0, h1) & (cellWidth, cellWidth, h2) and then your screenspace point will be brought into this space by simple translation.

Bonus point for curious minds: since this coordinate transformation is a simple translation it won't affect distances/lengths, so it won't change the sdf value from your previous version, BUT if it also had uniform scaling, it would affect the distances and you'd need to adjust the sdf accordingly. (for example when you decided to use (1, 1) instead of (cellWidth, cellWidth) and scale to some unit space to do your sdf calculations in.

Comment on lines +527 to +536
if (triangleA)
{
outlineLineSegments[0] = nbl::hlsl::shapes::Line<float>::construct(v[2].xy, v[0].xy);
outlineLineSegments[1] = nbl::hlsl::shapes::Line<float>::construct(v[2].xy, v[1].xy);
}
else
{
outlineLineSegments[0] = nbl::hlsl::shapes::Line<float>::construct(v[1].xy, v[2].xy);
outlineLineSegments[1] = nbl::hlsl::shapes::Line<float>::construct(v[0].xy, v[2].xy);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so this is not the way I want you to do outlines at all.

  1. Triangle formation (your v[3]) should only be done for CONTOUR and HEIGHT_SHADING (skip tthe formation calculations if only outlines is requested)
  2. Outline SDF and color calculation should be independant from triangle formation, based on the point you're going to do SDF with (2 lines out of 4)
  3. You'll be doing sdf with the whole larger lines, you don't have to adjust phaseshift anymore (extra unnecessary calculations), we'll handle clipping for all types of objects later on in case it was super zoomed in the sdf might be less accurate, but it's a simple line sdf so no big problem.
  4. Remember that the whole dilation emulation thing (iterating over all neighbouring cells and doing sdf with them) should also be independant from outline rendering
  5. Last but not least I want to be able to draw a grid without a heightmap texture and triangle formation. make sure your code can handle that. Because we're going to abuse this code to draw simple regular grids in n4ce, where there is no height values and heightmaps, formations or triangles; just simple grid
    image

}
if (dtmSettings.drawOutlineEnabled())
dtmColor = dtm::blendUnder(dtmColor, dtm::calculateGridDTMOutlineColor(dtmSettings.outlineLineStyleIdx, outlineLineSegments, input.position.xy, outlinePhaseShift));
if (dtmSettings.drawHeightShadingEnabled() && !outOfBoundsUV)
Copy link
Contributor Author

@Erfan-Ahmadi Erfan-Ahmadi Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& !outOfBoundsUV
Ok I can live with this. just know that you're implicitly discarding height shading for out of bounds UVs. if your grid was rotated you'd get aliasing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants