-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Add cone, make cylinder special case of a cone #10298
Conversation
cones.mp4Here are a few examples. Changed material to unlit for visual clarity. The cones in the video are defined as follows: meshes.add(
shape::Cone {
top_radius: 0.0,
bottom_radius: 0.4,
resolution: 32,
..default()
}
.into(),
),
meshes.add(
shape::Cone {
top_radius: 0.9,
bottom_radius: 0.8,
resolution: 16,
..default()
}
.into(),
),
meshes.add(
shape::Cone {
top_radius: 0.9,
bottom_radius: 0.3,
resolution: 16,
segments: 10,
..default()
}
.into(),
),
meshes.add(
shape::Cone {
top_radius: 1.0,
bottom_radius: 0.0,
resolution: 32,
height: 0.5,
..default()
}
.into(),
), |
use crate::mesh::{Indices, Mesh}; | ||
use wgpu::PrimitiveTopology; | ||
|
||
/// A cone which stands on the XZ plane |
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.
It would be nice to comment on the tip and face geometry (especially the UVs).
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.
Assuming this is resolved via your commit, let me know if not.
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.
Nope, I'd like much more detail, ala what HackerFoo was requesting below.
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've been thinking a bit about how I would go about making some diagrams or similar, but I feel making it in an ASCII editor will be messy.
I see there is some precedent for having images in docs: https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png
But that is only linked to and not shown directly via rustdoc
.
Should I just create an image?
Also I noted other programs (Godot, Blender) have other features and optimizations such as choosing if caps should be generated, making top/bottom a single point (when zero radius) and more, but I thought this might be a good start. |
Yep, we can merge it without those, but making good-first-issues for follow-up work like that would be much appreciated. |
Could you please add an image of the cone tip with smooth shading and a 0.0 tip radius, and no intermediate rings? I've only found one way to get this to work properly: #5891 (comment) (TL;DR use a single vertex for the tip with the normal set to zero, and normalize interpolated vertex normals in the fragment shader.) Also, a diagram would be useful, indicating the top & bottom radius, height, resolution, and segments. Note that, with a radius of 0 at the tip, half of the triangles surrounding the tip are degenerate if using quads, since two of the vertices will be at the tip, forming a line to the other vertex. If you omit the degenerate triangles, the normal resolution is cut in half at the tip, resulting in visible creases from the base to the tip. |
Also see this discussion, linked in #5891: https://stackoverflow.com/questions/15283508/low-polygon-cone-smooth-shading-at-the-tip/37187730#37187730 |
Happy to do so when this gets merged. I have a few follow-up tasks I can think of.
Video: https://github.com/bevyengine/bevy/assets/52322338/c3a96842-5113-4fcd-8fa4-8fc77309f266 I guess these are the creases you mentioned @HackerFoo? At first I tried doing a single-vertex optimization when a radius is zero, but the barrel body UV mapping got very ugly so I assumed I had to keep all the vertices in order to preserve the mapping. Should this be resolved in this PR or later? EDIT: After reading #5891 and #5666 a bit more it seems there might not be a solution right now that isn't at odds with:
Perhaps @superdump could provide some insight? EDIT 2: Hm, I think my PR is lacking adding a EDIT 3: I think the normal Y should get a |
Yes, that's what I expected. I don't think there is a solution other than normalizing in the fragment shader, or something similar e.g. weighted vertices. |
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
60709c5
to
3f1ef3f
Compare
I was also curious as to how Godot did theirs and I found this: Both have similar heights and radii, but: Default (behind) cone:
Less geometry (front) cone:
So it seems the effect is present there but masked by having more geometry in the defaults. I adopted those defaults now, looks like so: cone_3d_shapes.mp4Putting into draft since I'm unsure how to diagram it properly yet. |
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Added an illustration done in draw.io as well as the .xml source for it such that it can be further edited in the future. Also added some more docs. |
The effect should still be visible when zoomed in on the tip of the cone. A cone with a zero normal tip vertex doesn't have this problem. In my case 20x-1 vertices (4x radial segments, 4x rings, another ring instead of a single vertex at the tip) would affect performance, but I'm not using Bevy's shapes. |
I would definitely like to fix this problem directly, rather than mask it with more geometry :) Defaults should be both correct and free of odd performance footguns. |
I'd need to delve a bit deeper to understand the implications of
and I want to work on other things right now, so putting this PR up for adoption. |
FYI, I'm implementing this as a part of adding mesh creation support for the new primitive shapes (see #10569). I have a working implementation of the cone with a single vertex for the tip and a zero normal: Note: Unlike this PR, my implementation's default UVs map to polar coordinates (which Blender also uses). For example, a traffic cone with a white line going through it would be similar to Target's logo, which feels relatively intuitive to me. However, this requires #10905, because the vertex normals need to be normalized in the fragment shader and not in the vertex shader. Otherwise, the NaN values will produce a black mesh. Also, if we're going to be mathematically correct, the cone in this PR isn't actually a real cone because it doesn't always taper to a single point:
Instead, it's a conical frustum, a truncated cone where the truncation plane is parallel to the base. Coincidentally, there is a TLDR: I'm working on this, and the code here is very useful for the conical frustum implementation. PR(s) should be ready soon after #10905 hopefully gets merged! |
@Jondolf Very cool! Glad to hear you found something that will work well in all cases. |
# Objective Fixes #5891. For mikktspace normal maps, normals must be renormalized in vertex shaders to match the way mikktspace bakes vertex tangents and normal maps so that the exact inverse process is applied when shading. However, for invalid normals like `vec3<f32>(0.0, 0.0, 0.0)`, this normalization causes NaN values, and because it's in the vertex shader, it affects the entire triangle and causes it to be shaded as black: ![incorrectly shaded cone](https://github.com/bevyengine/bevy/assets/57632562/3334b3a9-f72a-4a08-853e-8077a346f5c9) *A cone with a tip that has a vertex normal of [0, 0, 0], causing the mesh to be shaded as black.* In some cases, normals of zero are actually *useful*. For example, a smoothly shaded cone without creases requires the apex vertex normal to be zero, because there is no singular normal that works correctly, so the apex shouldn't contribute to the overall shading. Duplicate vertices for the apex fix some shading issues, but it causes visible creases and is more expensive. See #5891 and #10298 for more details. For correctly shaded cones and other similar low-density shapes with sharp tips, vertex normals of zero can not be normalized in the vertex shader. ## Solution Only normalize the vertex normals and tangents in the vertex shader if the normal isn't [0, 0, 0]. This way, mikktspace normal maps should still work for everything except the zero normals, and the zero normals will only be normalized in the fragment shader. This allows us to render cones correctly: ![smooth cone with some banding](https://github.com/bevyengine/bevy/assets/57632562/6b36e264-22c6-453b-a6de-c404b314ca1a) Notice how there is still a weird shadow banding effect in one area. I noticed that it can be fixed by normalizing [here](https://github.com/bevyengine/bevy/blob/d2614f2d802d0fb8000821a81553b600cc85f734/crates/bevy_pbr/src/render/pbr_functions.wgsl#L51), which produces a perfectly smooth cone without duplicate vertices: ![smooth cone](https://github.com/bevyengine/bevy/assets/57632562/64f9ad5d-b249-4eae-880b-a1e61e07ae73) I didn't add this change yet, because it seems a bit arbitrary. I can add it here if that'd be useful or make another PR though.
# Objective The `Cone` primitive should support meshing. ## Solution Implement meshing for the `Cone` primitive. The default cone has a height of 1 and a base radius of 0.5, and is centered at the origin. An issue with cone meshes is that the tip does not really have a normal that works, even with duplicated vertices. This PR uses only a single vertex for the tip, with a normal of zero; this results in an "invalid" normal that gets ignored by the fragment shader. This seems to be the only approach we have for perfectly smooth cones. For discussion on the topic, see #10298 and #5891. Another thing to note is that the cone uses polar coordinates for the UVs: <img src="https://github.com/bevyengine/bevy/assets/57632562/e101ded9-110a-4ac4-a98d-f1e4d740a24a" alt="cone" width="400" /> This way, textures are applied as if looking at the cone from above: <img src="https://github.com/bevyengine/bevy/assets/57632562/8dea00f1-a283-4bc4-9676-91e8d4adb07a" alt="texture" width="200" /> <img src="https://github.com/bevyengine/bevy/assets/57632562/d9d1b5e6-a8ba-4690-b599-904dd85777a1" alt="cone" width="200" />
Objective
Bevy is lacking a cone mesh type.
Solution
Copy the cylinder implementation into a
Cone
type and split the single radius into top- and bottom radii.Step this radius when iterating over the cone/cylinder rings.
Make cylinders a special case of a cone where the radii are equal.
Changelog
Added