Как я могу установить повторяющуюся текстуру на объекте в Android ArCore Sceneform API? - PullRequest
0 голосов
/ 22 ноября 2018

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

Мой код:

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

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

current result

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

expected result

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

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

1 Ответ

0 голосов
/ 26 ноября 2018

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

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

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

Пользовательский материал специфичен для 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

Запись нестандартного материала

Справочник нестандартного материала описывает каждый изэлементы в 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 -> repeatatingMaterial = 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)));
  }
...