bevyengine / bevyengine/bevy

Strange artifact with PBR `perceptual_roughness` set to 0

Open
#16,534 0 comments 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

Commit 2a66bf0909992b280420442ecda42a38d37de326 (latest main at time of writing).

## Relevant system information

AMD Ryzen 9 7950X3D Integrated Graphics (RDNA 2) on latest Arch Linux

```ignore
INFO bevy_render::renderer: AdapterInfo {
name: "AMD Radeon Graphics (RADV RAPHAEL_MENDOCINO)",
vendor: 4098,
device: 5710,
device_type: IntegratedGpu,
driver: "radv",
driver_info: "Mesa 24.2.7-arch1.1",
backend: Vulkan
}
```

## What you did

Created a PBR material with `perceptual_roughness` 0.0. Here is a small example using a mesh I generated to reproduce, with light moving to make it more obvious.

```rs
use bevy::{
asset::RenderAssetUsages,
color::palettes::css::DEEP_PINK,
pbr::wireframe::{WireframeConfig, WireframePlugin},
prelude::*,
render::mesh::{Indices, PrimitiveTopology},
};

fn main() {
App::new()
.add_plugins((DefaultPlugins, WireframePlugin))
.add_systems(Startup, setup)
.add_systems(Update, light_rotate)
.insert_resource(WireframeConfig {
global: true,
..default()
})
.run();
}

fn setup(
mut commands: Commands,
mut meshes: ResMut>,
mut materials: ResMut>,
) {
let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::RENDER_WORLD,
);

mesh.insert_attribute(
Mesh::ATTRIBUTE_POSITION,
vec![
[0.0, 0.24613905, 0.49612403],
[0.24806201, 0.6153476, 0.74418604],
[0.24806201, 0.3076738, 0.49612403],
[0.49612403, 0.4922781, 0.49612403],
[0.0, 0.9845562, 0.99224806],
[0.0, 0.55381286, 0.74418604],
[0.24806201, 0.123069525, 0.24806201],
[0.0, 0.061534762, 0.24806201],
[0.0, 0.0, 0.0],
[0.49612403, 1.2306952, 0.99224806],
[0.74418604, 1.1076257, 0.74418604],
[0.49612403, 0.7999519, 0.74418604],
[0.99224806, 1.9691124, 0.99224806],
[0.74418604, 1.538369, 0.99224806],
[0.24806201, 1.046091, 0.99224806],
[0.99224806, 1.2306952, 0.49612403],
[0.74418604, 0.6153476, 0.24806201],
[0.74418604, 0.7999519, 0.49612403],
[0.99224806, 0.9845562, 0.0],
[0.99224806, 1.046091, 0.24806201],
[0.99224806, 1.538369, 0.74418604],
[0.49612403, 0.24613905, 0.0],
[0.49612403, 0.3076738, 0.24806201],
[0.24806201, 0.061534762, 0.0],
[0.74418604, 0.55381286, 0.0],
],
);

mesh.insert_attribute(
Mesh::ATTRIBUTE_NORMAL,
vec![
[0.0, 1.0, -0.99224806],
[0.49612114, 1.0, -1.4883711],
[0.49612308, 1.0, -0.99224806],
[0.99224806, 1.0, -0.99224806],
[0.0, 1.0, 0.0],
[0.0, 1.0, -1.4883711],
[0.49612355, 1.0, -0.49612355],
[0.0, 1.0, -0.49612427],
[0.0, 1.0, 0.0],
[0.99224997, 1.0, 0.0],
[1.488375, 1.0, -1.488375],
[0.99224615, 1.0, -1.4883711],
[0.0, 1.0, 0.0],
[1.4883673, 1.0, 0.0],
[0.49612498, 1.0, 0.0],
[0.0, 1.0, -0.99224997],
[1.4883711, 1.0, -0.49612114],
[1.4883711, 1.0, -0.99224615],
[0.0, 1.0, 0.0],
[0.0, 1.0, -0.49612498],
[0.0, 1.0, -1.4883673],
[0.99224806, 1.0, 0.0],
[0.99224806, 1.0, -0.49612308],
[0.49612427, 1.0, 0.0],
[1.4883711, 1.0, 0.0],
],
);

mesh.insert_indices(Indices::U32(vec![
0, 1, 2, 1, 3, 2, 4, 1, 5, 1, 0, 5, 0, 6, 7, 6, 8, 7, 3, 6, 2, 6, 0, 2, 9, 10, 11, 10, 3,
11, 12, 10, 13, 10, 9, 13, 9, 1, 14, 1, 4, 14, 3, 1, 11, 1, 9, 11, 15, 16, 17, 16, 3, 17,
18, 16, 19, 16, 15, 19, 15, 10, 20, 10, 12, 20, 3, 10, 17, 10, 15, 17, 21, 6, 22, 6, 3, 22,
8, 6, 23, 6, 21, 23, 21, 16, 24, 16, 18, 24, 3, 16, 22, 16, 21, 22,
]));

let light_angle = -91f32.to_radians();
commands.spawn((
PointLight::default(),
Transform::from_xyz(light_angle.cos(), 2.0, light_angle.sin()),
));

commands.spawn((
Mesh3d(meshes.add(mesh)),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: DEEP_PINK.into(),
perceptual_roughness: 0.0,
..default()
})),
Transform::from_xyz(0.0, 0.0, 0.0)
.with_rotation(Quat::from_rotation_y(90f32.to_radians()))
.with_scale(Vec3::ONE * 2.0),
));

commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 4.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}

fn light_rotate(mut light: Query<&mut Transform, With>, time: Res

## What went wrong

The surface presents black line artifacts. I apologize as this is not made super obvious on this attempt at reproducing minimally, the example below from my project shows it better.

![Image](https://github.com/user-attachments/assets/5effa840-b68e-4087-a79c-6d5aeb4691f6)

This is a more obvious example from my project, same style of artifact but more pronounced somehow:

![Image](https://github.com/user-attachments/assets/0e73ae2d-e45e-498c-80d1-1991198c00f3)

Notice that it seems to follow shadows in some way:

![Image](https://github.com/user-attachments/assets/983501f2-c01b-491f-bd3c-23f8116ad2c5)

And it does not appear to follow triangles:

![Image](https://github.com/user-attachments/assets/7a988d64-4c82-4ec0-89a4-3610f68621a9)

## Additional information

Is this a case of the 0.0 roughness making the color fall into a pole?

Contributor guide

Open the contributing guide

Research direction

Start with the supplied minimal reproduction, especially the setup function's StandardMaterial using perceptual_roughness: 0.0 and the light_rotate system. Reproduce the black line artifacts while moving the light, then determine whether the behavior is caused by zero roughness and identify the rendering change needed to eliminate it.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.