如何在 Android ArCore Sceneform API 中的对象上设置重复纹理? [英] How I can set repeated texture on an object in Android ArCore Sceneform API?

查看:16
本文介绍了如何在 Android ArCore Sceneform API 中的对象上设置重复纹理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经成功地在 AR 场景中的两个向量之间画了一条线.

I have successfully made a line between two vectors in the AR Scene.

我的代码:

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:(线条的一半是透明的,另一半是橙色的.)

It works perfectly, but I have a mistake texture. In the file "textures/aim_line.png" contains PNG: (the line's half is transparent the other half is orange.)

我目前的结果:

但我期待下一个结果:

所以,我使用了写有WrapMode.REPEAT"的采样器,但纹理不重复,只是拉伸.

So, I have use the Sampler where was wrote "WrapMode.REPEAT" but the texture does not repeat, only stretched.

如何在 Android ArCore Sceneform API 中的对象上设置重复纹理?

How I can set repeated texture on an object in Android ArCore Sceneform API?

推荐答案

查看圆柱模型,它有一个 0 到 1 的 UV 贴图.这是用来将纹理映射到网格上的.0,0 是纹理的左下角,1,1 是右上角.采样器上的环绕配置仅在模型上的 UV 坐标 > 1.0 时使用.在这种情况下,它会根据设置进行钳制或重复.由于圆柱体已经被约束为 0,1,所以纹理总是被拉伸.

Looking at the cylinder model, it has a UV map of 0 to 1. This is used to map the texture onto the mesh. 0,0 is the bottom left of the texture and 1,1 is the top right. The wrapping configuration on the sampler is only used when the UV coordinates on the model are > 1.0. In that case it clamps or repeats based on the setting. Since the cylinder is already constrained to 0,1, the texture is always stretched.

解决此问题的替代方法是对自己的圆柱体进行建模并根据需要设置 UV 坐标,或者使用自定义材质在采样前操纵 UV 坐标.

Your alternatives to fix this are either to model your own cylinder and set the UV coordinates as you need, or to use a custom material to manipulate the UV coordinates before sampling.

您可以使用 Blender 或 Maya 或其他 3D 建模工具制作模型.

You can use Blender or Maya or another 3D modeling tool make the model.

自定义材质特定于 Sceneform,因此步骤如下:

The custom material is specific to Sceneform, so here's the steps:

  1. 创建一个虚拟模型以在加载自定义材料时使用
  2. 编写重复纹理的自定义材质
  3. 在运行时加载虚拟模型并获取材质
  4. 在自定义材料上设置参数.

创建虚拟模型

我使用了我身边的飞机 OBJ 模型.模型是什么并不重要,我们只需要它来加载材料.在 app/sampledata/materials 中创建一个名为 dummy.obj

Create a dummy model

I used a plane OBJ model I had around. It does not matter what the model is, we just need it to load the material. Create a file in app/sampledata/materials named 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 中:

Write the custom material

The custom material reference describes each of the elements in the 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 添加:

Add the model and material to the build

This adds the step to compile the model and material into a .sfb file. In app/build.gradle add:

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 添加到顶级 build.gradle 中的 buildscript 类路径:

You will also need to add Sceneform to the buildscript class path in the top level 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());

ModelRenderable.builder().setSource(this, R.raw.material_holder) .build().thenAccept( modelRenderable -> repeatingMaterial = modelRenderable.getMaterial());

这将材料存储在成员字段 repeatingMaterial 中.

This stores the material in the member field repeatingMaterial.

将您的原始代码修改为:

Modifying your original code to be:

  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)));
  }

这篇关于如何在 Android ArCore Sceneform API 中的对象上设置重复纹理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆