bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.12k stars 3.56k forks source link

ImageAddressMode::Repeat "twitchy" texture rendering #15162

Open IvoryDuke opened 1 month ago

IvoryDuke commented 1 month ago

Bevy version

0.14.2

[Optional] Relevant system information

AdapterInfo { name: "NVIDIA GeForce GTX 1060 6GB", vendor: 4318, device: 7171, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "535.183.01", backend: Vulkan } Also occurs with any other computer I have tried (they all happen to be using Vulkan, haven't tested other backends).

What you did

Set ImagePlugin to

ImagePlugin {
    default_sampler: ImageSamplerDescriptor {
        address_mode_u: ImageAddressMode::Repeat,
        address_mode_v: ImageAddressMode::Repeat,
        address_mode_w: ImageAddressMode::Repeat,
        ..Default::default()
    },
}

and mapped a texture to a mesh.

What went wrong

The texture "twitches" depending on the position of the camera and the entity. That is, sometimes the texture is not mapped to the vertices as it should according to the specified UV.

Additional information

Minimal example

use bevy::prelude::*;
use bevy::render::texture::{ImageAddressMode, ImageSamplerDescriptor};
use bevy::render::{
    mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology,
};
use bevy::sprite::MaterialMesh2dBundle;

fn main() {
    App::new()
        .insert_resource(ClearColor(Color::BLACK))
        .add_plugins(DefaultPlugins.set(ImagePlugin {
            default_sampler: ImageSamplerDescriptor {
                address_mode_u: ImageAddressMode::Repeat,
                address_mode_v: ImageAddressMode::Repeat,
                address_mode_w: ImageAddressMode::Repeat,
                ..Default::default()
            },
        }))
        .add_systems(Startup, setup)
        .add_systems(Update, update)
        .run();
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
) {
    const TRANSFORM: Transform = Transform::from_translation(Vec3::ZERO);

    let mut camera = Camera2dBundle::default();
    camera.transform.scale = Vec3::splat(0.125f32);
    commands.spawn(camera);

    let texture = asset_server.load("generic-rpg-tile68.png"); // Can be any non-solid color texture.

    let mesh = Mesh::new(
        PrimitiveTopology::TriangleList,
        RenderAssetUsages::default(),
    )
    .with_inserted_attribute(
        Mesh::ATTRIBUTE_POSITION,
        vec![
            [16.0, 32.0, 0.0],
            [-16.0, 32.0, 0.0],
            [-16.0, -32.0, 0.0],
            [16.0, -32.0, 0.0],
        ],
    )
    .with_inserted_attribute(
        Mesh::ATTRIBUTE_UV_0,
        vec![[1.0, -2.0], [-1.0, -2.0], [-1.0, 2.0], [1.0, 2.0]],
    )
    .with_inserted_attribute(
        Mesh::ATTRIBUTE_NORMAL,
        vec![
            [0.0, 0.0, 1.0],
            [0.0, 0.0, 1.0],
            [0.0, 0.0, 1.0],
            [0.0, 0.0, 1.0],
        ],
    )
    .with_inserted_indices(Indices::U32(vec![0, 1, 2, 0, 2, 3]));

    commands.spawn(MaterialMesh2dBundle {
        mesh: meshes.add(mesh).into(),
        material: materials.add(ColorMaterial {
            color: Color::WHITE,
            texture: texture.into(),
        }),
        global_transform: TRANSFORM.into(),
        transform: TRANSFORM,
        ..Default::default()
    });
}

fn update(mut camera: Query<&mut Transform, With<Camera>>) {
    const DELTA: f32 = 1f32 / 128f32;
    camera.get_single_mut().unwrap().translation.x += DELTA;
}
BenjaminBrienen commented 1 month ago

It would be helpful to test this with other backends

IvoryDuke commented 1 month ago

@BenjaminBrienen I will try to in the next days and will report result. Gonna try OpenGL first.

IvoryDuke commented 1 month ago

I did

export WGPU_BACKEND=gl && cargo run

It did start with the OpenGL backend. It shows the same issue and it looks the same as with Vulkan.