Как я могу установить повторяющуюся текстуру на объекте в Android ArCore Sceneform API?

Я успешно провел линию между двумя векторами в сцене дополненной реальности.

Мой код:

private void addLineBetweenPoints(Scene scene, Vector3 from, Vector3 to) {
        // prepare an anchor position
        Quaternion camQ = scene.getCamera().getWorldRotation();
        float[] f1 = new float[]{to.x, to.y, to.z};
        float[] f2 = new float[]{camQ.x, camQ.y, camQ.z, camQ.w};
        Pose anchorPose = new Pose(f1, f2);

        // make an ARCore Anchor
        Anchor anchor = mCallback.getSession().createAnchor(anchorPose);
        // Node that is automatically positioned in world space based on the ARCore Anchor.
        AnchorNode anchorNode = new AnchorNode(anchor);
        anchorNode.setParent(scene);

        // Compute a line's length
        float lineLength = Vector3.subtract(from, to).length();

        // Prepare a sampler
        Texture.Sampler sampler = Texture.Sampler.builder()
                .setMinFilter(Texture.Sampler.MinFilter.LINEAR_MIPMAP_LINEAR)
                .setMagFilter(Texture.Sampler.MagFilter.LINEAR)
                .setWrapModeR(Texture.Sampler.WrapMode.REPEAT)
                .setWrapModeS(Texture.Sampler.WrapMode.REPEAT)
                .setWrapModeT(Texture.Sampler.WrapMode.REPEAT)
                .build();

        // 1. Make a texture
        Texture.builder()
                .setSource(() -> getContext().getAssets().open("textures/aim_line.png"))
                .setSampler(sampler)
                .build().thenAccept(texture -> {
                    // 2. make a material by the texture
                    MaterialFactory.makeTransparentWithTexture(getContext(), texture)
                        .thenAccept(material -> {
                            // 3. make a model by the material
                            ModelRenderable model = ShapeFactory.makeCylinder(0.0025f, lineLength,
                                    new Vector3(0f, lineLength / 2, 0f), material);
                            model.setShadowReceiver(false);
                            model.setShadowCaster(false);

                            // make node
                            Node node = new Node();
                            node.setRenderable(model);
                            node.setParent(anchorNode);

                            // set rotation
                            final Vector3 difference = Vector3.subtract(to, from);
                            final Vector3 directionFromTopToBottom = difference.normalized();
                            final Quaternion rotationFromAToB =
                                    Quaternion.lookRotation(directionFromTopToBottom, Vector3.up());
                            node.setWorldRotation(Quaternion.multiply(rotationFromAToB,
                                    Quaternion.axisAngle(new Vector3(1.0f, 0.0f, 0.0f), 90)));
                    });
        });
    }

Работает отлично, но у меня ошибка текстуры. В файле "textures / aim_line.png" содержится PNG: (половина линии прозрачная, другая половина - оранжевая.)

aim_line.png

Мой текущий результат:

текущий результат

Но я ожидал следующего результата:

ожидаемый результат

Итак, я использовал Sampler, в котором было написано «WrapMode.REPEAT», но текстура не повторяется, а только растягивается.

Как я могу установить повторяющуюся текстуру на объекте в Android ArCore Sceneform API?


person Andrew Grow    schedule 22.11.2018    source источник


Ответы (1)


Глядя на модель цилиндра, у нее есть UV-карта от 0 до 1. Она используется для наложения текстуры на сетку. 0,0 - это нижний левый угол текстуры, а 1,1 - верхний правый. Конфигурация обертывания на сэмплере используется только тогда, когда UV-координаты модели> 1.0. В этом случае он фиксируется или повторяется в зависимости от настройки. Поскольку цилиндр уже ограничен 0,1, текстура всегда растягивается.

Ваши альтернативы, чтобы исправить это, - либо смоделировать свой собственный цилиндр и установить нужные UV-координаты, либо использовать специальный материал для управления UV-координатами перед отбором проб.

Вы можете использовать Blender, Maya или другой инструмент 3D-моделирования для создания модели.

Пользовательский материал специфичен для Sceneform, поэтому выполните следующие действия:

  1. Создайте фиктивную модель для использования при загрузке пользовательского материала.
  2. Напишите индивидуальный материал, повторяющий текстуру
  3. Загрузите фиктивную модель во время выполнения и получите материал
  4. Задайте параметры для нестандартного материала.

Создайте фиктивную модель

Я использовал модель самолета OBJ, которая у меня была. Неважно, что это за модель, она нужна нам только для загрузки материала. Создайте в app/sampledata/materials файл с именем dummy.obj.

o Plane
v 0.500000 0.500000 0.000000
v  -0.500000 0.500000 0.000000
v  0.500000 -0.500000 0.000000
v  -0.500000 -0.500000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 1/1/1 2/2/1 4/3/1 3/4/1

Напишите индивидуальный материал

Справочник по настраиваемым материалам описывает каждый из элементов в < strong> repeating_texture.mat:

// Sample material for repeating a texture.
//
// the repeating factor is given as repeat_x,
// repeat_y as a factor multipled by the UV
// coordinate.
material {
    "name" : "RepeatingTexture",
   parameters : [
   {
      type : sampler2d,
      name : texture
   },

    {
        type: float,
        name:"repeat_x"
    },
    {
            type: float,
            name: "repeat_y"
    }
   ],
   requires : [
       "position",
       "uv0"
   ],

}
fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);

        vec2 uv = getUV0();
        uv.x = uv.x * materialParams.repeat_x;
        uv.y = uv.y * materialParams.repeat_y;

        material.baseColor = texture(materialParams_texture, uv).rgba;
    }
}

Добавьте модель и материал в сборку

Это добавляет шаг для компиляции модели и материала в файл .sfb. В app/build.gradle добавить:

apply plugin: 'com.google.ar.sceneform.plugin'

sceneform.asset('sampledata/materials/dummy.obj',
        "sampledata/materials/repeating_texture.mat",
        'sampledata/materials/dummy.sfa',
        'src/main/res/raw/material_holder')

Вам также нужно будет добавить Sceneform в путь класса buildscript на верхнем уровне build.gradle:

    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath 'com.google.ar.sceneform:plugin:1.5.1'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

Загрузите материал во время выполнения

В onCreate() звоните:

ModelRenderable.builder (). SetSource (this, R.raw.material_holder) .build (). ThenAccept (modelRenderable -> RepeatingMaterial = modelRenderable.getMaterial ());

Это сохраняет материал в поле члена repeatingMaterial.

Установите параметры на материале

Изменение исходного кода на:

  private void addLineBetweenPoints(AnchorNode from, Vector3 to) {
    // Compute a line's length
    float lineLength = Vector3.subtract(from.getWorldPosition(), to).length();
    // repeat the pattern every 10cm
    float lengthCM = lineLength * 100;

    repeatingMaterial.setFloat("repeat_x", lengthCM/10);
    repeatingMaterial.setFloat("repeat_y", lengthCM/10);
                // 3. make a model by the material
                ModelRenderable model = ShapeFactory.makeCylinder(0.0025f, lineLength,
                        new Vector3(0f, lineLength / 2, 0f), repeatingMaterial);
                model.setShadowReceiver(false);
                model.setShadowCaster(false);
                // make node
                Node node = new Node();
                node.setRenderable(model);
                node.setParent(from);
                // set rotation
                final Vector3 difference = Vector3.subtract(from.getWorldPosition(), to);
                final Vector3 directionFromTopToBottom = difference.normalized();
                final Quaternion rotationFromAToB =
                        Quaternion.lookRotation(directionFromTopToBottom, Vector3.up());
                node.setWorldRotation(Quaternion.multiply(rotationFromAToB,
                        Quaternion.axisAngle(new Vector3(1.0f, 0.0f, 0.0f), 90)));
  }
person Clayton Wilkinson    schedule 26.11.2018
comment
Большое спасибо, это отличный ответ! Спасибо за решение, сэр. Ваша помощь очень важна для меня. - person Andrew Grow; 28.11.2018
comment
Как мы можем изменить текстуру во время выполнения, например, в каждом кадре, чтобы имитировать бесконечное движение (например, прогресс)? - person Максим Петлюк; 01.03.2019