-
-
Notifications
You must be signed in to change notification settings - Fork 235
refactor: optimize cave sphere shaping #3382
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -58,72 +58,88 @@ pub fn generate(map: *CaveMapFragment, worldSeed: u64) void { | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| fn displaceByHalfExtentBounded(center: f32, extent: f32, max_extent: i32) struct { | ||||||
| min: i32, | ||||||
| max: i32, | ||||||
| } { | ||||||
| return .{ | ||||||
| .min = @max(@as(i32, @trunc(center - extent)) - 1, 0), | ||||||
| .max = @min( | ||||||
| @as(i32, @trunc(center + extent)) + 1, | ||||||
| max_extent, | ||||||
| ), | ||||||
| }; | ||||||
| } | ||||||
|
|
||||||
| fn generateSphere_(seed: *u64, map: *CaveMapFragment, relPos: Vec3f, radius: f32, comptime addTerrain: bool) void { | ||||||
| const lodScale = map.pos.voxelSize; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please stick to the existing naming convention
Suggested change
|
||||||
| const scaledWidth = CaveMapFragment.width*lodScale; | ||||||
| const scaledHeight = CaveMapFragment.height*lodScale; | ||||||
|
|
||||||
| // Makes walls rough by adding a 1-in-roughnessChance chance that blocks | ||||||
| // remain unchanged. | ||||||
| const roughnessChance = 6; | ||||||
| const terrainShaper = if (addTerrain) CaveMapFragment.addRange else CaveMapFragment.removeRange; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think function pointers are generally harder to read and argue about.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do like the idea of this, but I will challenge doing the same comptime-parameter, if it were up to me, I think a signature that looks more or less like this would be more explicit as to what is being done:
If I do go this route, would you want me to make the Also, slight sidenote, this function doesn't even benefit from using the comptime
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, an enum is always better, and I'd prefer to use the same enum in both places.
I'd suggest not to do too many changes in this one PR. Also it is kind of annoying to convert a Vec3i to Vec2i currently due to lack of swizzling in the language.
I think when inlined you'd have trouble turning |
||||||
|
|
||||||
| const relX = relPos[0]; | ||||||
| const relY = relPos[1]; | ||||||
| const relZ = relPos[2]; | ||||||
| var xMin = @as(i32, @trunc(relX - radius)) - 1; | ||||||
| xMin = @max(xMin, 0); | ||||||
| var xMax = @as(i32, @trunc(relX + radius)) + 1; | ||||||
| xMax = @min(xMax, CaveMapFragment.width*map.pos.voxelSize); | ||||||
| var yMin = @as(i32, @trunc(relY - radius)) - 1; | ||||||
| yMin = @max(yMin, 0); | ||||||
| var yMax = @as(i32, @trunc(relY + radius)) + 1; | ||||||
| yMax = @min(yMax, CaveMapFragment.width*map.pos.voxelSize); | ||||||
| if (xMin >= xMax or yMin >= yMax or relZ - radius + 1 >= @as(f32, @floatFromInt(CaveMapFragment.height*map.pos.voxelSize)) or relZ + radius + 1 < 0) { | ||||||
|
|
||||||
| const xDist = displaceByHalfExtentBounded(relX, radius, scaledWidth); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you make
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not exactly a huge fan on doing just
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure |
||||||
| const yDist = displaceByHalfExtentBounded(relY, radius, scaledWidth); | ||||||
| const zDist = displaceByHalfExtentBounded(relZ, radius, scaledHeight); | ||||||
|
|
||||||
| if (xDist.min >= xDist.max or yDist.min >= yDist.max or zDist.min >= zDist.max) { | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| const radiusSq = radius*radius; | ||||||
| const invRadiusSq = 1.0/(radiusSq); | ||||||
| const thresholdXY = 0.9*0.9*radiusSq; | ||||||
|
|
||||||
| // Go through all blocks within range of the sphere center and remove them. | ||||||
| var curX = xMin; | ||||||
| while (curX < xMax) : (curX += map.pos.voxelSize) { | ||||||
| const distToCenterX = (@as(f32, @floatFromInt(curX)) - relX)/radius; | ||||||
| var curY = yMin; | ||||||
| while (curY < yMax) : (curY += map.pos.voxelSize) { | ||||||
| const distToCenterY = (@as(f32, @floatFromInt(curY)) - relY)/radius; | ||||||
| const xyDistanceSquared = distToCenterX*distToCenterX + distToCenterY*distToCenterY; | ||||||
| var curX = xDist.min; | ||||||
| while (curX < xDist.max) : (curX += lodScale) { | ||||||
| const dx = @as(f32, @floatFromInt(curX)) - relX; | ||||||
| const dxSq = dx*dx; | ||||||
|
|
||||||
| var curY = yDist.min; | ||||||
| while (curY < yDist.max) : (curY += lodScale) { | ||||||
| const dy = @as(f32, @floatFromInt(curY)) - relY; | ||||||
| const dySq = dy*dy; | ||||||
| const xySumSq = dxSq + dySq; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be no performance difference to do the squaring here, avoiding the helper constants
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll expand out the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would disagree. I prefer reading arithmetic |
||||||
|
|
||||||
| var zMin: i32 = @trunc(relZ); | ||||||
| var zMax: i32 = @trunc(relZ); | ||||||
| if (xyDistanceSquared < 0.9*0.9) { | ||||||
| const zDistance = radius*@sqrt(0.9*0.9 - xyDistanceSquared); | ||||||
| if (xySumSq < thresholdXY) { | ||||||
| const zDistance = @sqrt(thresholdXY - xySumSq); | ||||||
| zMin = @trunc(relZ - zDistance); | ||||||
| zMax = @trunc(relZ + zDistance); | ||||||
| if (addTerrain) { | ||||||
| map.addRange(curX, curY, zMin, zMax); // Add the center range in a single call. | ||||||
| } else { | ||||||
| map.removeRange(curX, curY, zMin, zMax); // Remove the center range in a single call. | ||||||
| } | ||||||
| terrainShaper(map, curX, curY, zMin, zMax); | ||||||
| } | ||||||
| // Add some roughness at the upper cave walls: | ||||||
|
|
||||||
| // Add some roughness to the upper cave walls: | ||||||
| var curZ: i32 = zMax; | ||||||
| while (curZ <= CaveMapFragment.height*map.pos.voxelSize) : (curZ += map.pos.voxelSize) { | ||||||
| const distToCenterZ = (@as(f32, @floatFromInt(curZ)) - relZ)/radius; | ||||||
| const distToCenter = distToCenterZ*distToCenterZ + xyDistanceSquared; | ||||||
| if (distToCenter < 1) { | ||||||
| // Add a small roughness parameter to make walls look a bit rough by filling only 5/6 of the blocks at the walls with air: | ||||||
| if (random.nextIntBounded(u8, seed, 6) != 0) { | ||||||
| if (addTerrain) { | ||||||
| map.addRange(curX, curY, curZ, curZ + 1); | ||||||
| } else { | ||||||
| map.removeRange(curX, curY, curZ, curZ + 1); | ||||||
| } | ||||||
| } | ||||||
| } else break; | ||||||
| while (curZ <= scaledHeight) : (curZ += lodScale) { | ||||||
| const dz = @as(f32, @floatFromInt(curZ)) - relZ; | ||||||
| const distToCenter = (xySumSq + dz*dz)*invRadiusSq; | ||||||
| if (distToCenter >= 1) break; | ||||||
|
|
||||||
| if (random.nextIntBounded(u8, seed, roughnessChance) != 0) { | ||||||
| terrainShaper(map, curX, curY, curZ, curZ + 1); | ||||||
| } | ||||||
| } | ||||||
| // Add some roughness at the lower cave walls: | ||||||
|
|
||||||
| // Add some roughness to the lower cave walls: | ||||||
| curZ = zMin; | ||||||
| while (curZ >= 0) : (curZ -= map.pos.voxelSize) { | ||||||
| const distToCenterZ = (@as(f32, @floatFromInt(curZ)) - relZ)/radius; | ||||||
| const distToCenter = distToCenterZ*distToCenterZ + xyDistanceSquared; | ||||||
| if (distToCenter < 1) { | ||||||
| // Add a small roughness parameter to make walls look a bit rough by filling only 5/6 of the blocks at the walls with air: | ||||||
| if (random.nextIntBounded(u8, seed, 6) != 0) { | ||||||
| if (addTerrain) { | ||||||
| map.addRange(curX, curY, curZ, curZ + 1); | ||||||
| } else { | ||||||
| map.removeRange(curX, curY, curZ, curZ + 1); | ||||||
| } | ||||||
| } | ||||||
| } else break; | ||||||
| while (curZ >= 0) : (curZ -= lodScale) { | ||||||
| const dz = @as(f32, @floatFromInt(curZ)) - relZ; | ||||||
| const distToCenter = (xySumSq + dz*dz)*invRadiusSq; | ||||||
| if (distToCenter >= 1) break; | ||||||
|
|
||||||
| if (random.nextIntBounded(u8, seed, roughnessChance) != 0) { | ||||||
| terrainShaper(map, curX, curY, curZ, curZ + 1); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the other comment (also name convention is camel case)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rewrote that mostly as follows (completely missed the
max_extentI've been writing too much rust as of late), I do have a question as to whether or not you wantmaxExtentto be aVec3ior aVec2i, it can't be ani32, becausezhas it's own scaling based off of theCaveFragment.height, whereasxandyuse thewidth.Vec3iimplies thatxandycan use differentmaxExtents, whereasVec2icements in place that whateverxis scaled by,ymust be scaled by.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then Vec3i would be better, Vec2i would be rather hard to read in my opinion. There is no reason to cement this property in a helper function that doesn't care about it.