diff --git a/samples/gltf/app/src/main/java/com/google/ar/sceneform/samples/gltf/GltfActivity.java b/samples/gltf/app/src/main/java/com/google/ar/sceneform/samples/gltf/GltfActivity.java index c3500962..9fedcd47 100644 --- a/samples/gltf/app/src/main/java/com/google/ar/sceneform/samples/gltf/GltfActivity.java +++ b/samples/gltf/app/src/main/java/com/google/ar/sceneform/samples/gltf/GltfActivity.java @@ -36,10 +36,13 @@ import com.google.ar.core.HitResult; import com.google.ar.core.Plane; import com.google.ar.sceneform.AnchorNode; +import com.google.ar.sceneform.Node; +import com.google.ar.sceneform.math.Vector3; import com.google.ar.sceneform.rendering.Color; import com.google.ar.sceneform.rendering.Material; import com.google.ar.sceneform.rendering.ModelRenderable; import com.google.ar.sceneform.rendering.Renderable; +import com.google.ar.sceneform.rendering.ViewRenderable; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.TransformableNode; import java.lang.ref.WeakReference; @@ -152,6 +155,24 @@ protected void onCreate(Bundle savedInstanceState) { Material material = renderable.getMaterial(i); material.setFloat4("baseColorFactor", color); } + + Node tigerTitleNode = new Node(); + tigerTitleNode.setParent(model); + tigerTitleNode.setEnabled(false); + tigerTitleNode.setLocalPosition(new Vector3(0.0f, 1.0f, 0.0f)); + ViewRenderable.builder() + .setView(this, R.layout.tiger_card_view) + .build() + .thenAccept( + (renderable) -> { + tigerTitleNode.setRenderable(renderable); + tigerTitleNode.setEnabled(true); + }) + .exceptionally( + (throwable) -> { + throw new AssertionError("Could not load card view.", throwable); + } + ); }); arFragment diff --git a/samples/gltf/app/src/main/res/drawable/rounded_bg.xml b/samples/gltf/app/src/main/res/drawable/rounded_bg.xml new file mode 100644 index 00000000..59cea04a --- /dev/null +++ b/samples/gltf/app/src/main/res/drawable/rounded_bg.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/samples/gltf/app/src/main/res/layout/tiger_card_view.xml b/samples/gltf/app/src/main/res/layout/tiger_card_view.xml new file mode 100644 index 00000000..c59fe99a --- /dev/null +++ b/samples/gltf/app/src/main/res/layout/tiger_card_view.xml @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/sceneformsrc/sceneform/build.gradle b/sceneformsrc/sceneform/build.gradle index 7d565371..ccb0a0ca 100644 --- a/sceneformsrc/sceneform/build.gradle +++ b/sceneformsrc/sceneform/build.gradle @@ -39,8 +39,8 @@ android { } dependencies { - api 'com.google.android.filament:filament-android:1.4.5' - api 'com.google.android.filament:gltfio-android:1.4.5' + api 'com.google.android.filament:filament-android:1.7.0' + api 'com.google.android.filament:gltfio-android:1.7.0' implementation files("../libs/libsceneform_runtime_schemas.jar") api "com.google.ar:core:1.16.0" diff --git a/sceneformsrc/sceneform/sampleData/sceneform_camera_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_camera_material.mat new file mode 100755 index 00000000..eb50c14c --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_camera_material.mat @@ -0,0 +1,25 @@ +material { + "name" : "Camera", + + "parameters" : [ + { + "type" : "samplerExternal", + "name" : "cameraTexture" + } + ], + "requires" : [ + "uv0" + ], + "vertexDomain" : "device", + "depthWrite" : false, + "shadingModel" : "unlit", + "doubleSided" : true +} +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + + vec4 color = texture(materialParams_cameraTexture, getUV0()); + material.baseColor.rgb = inverseTonemapSRGB(color.rgb); + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_opaque_colored_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_opaque_colored_material.mat new file mode 100755 index 00000000..b799eb57 --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_opaque_colored_material.mat @@ -0,0 +1,37 @@ +material { + "name" : "Opaque Colored", + + "parameters" : [ + { + "type" : "float3", + "name" : "color" + }, + { + "type" : "float", + "name" : "metallic" + }, + { + "type" : "float", + "name" : "roughness" + }, + { + "type" : "float", + "name" : "reflectance" + } + ], + "requires" : [ + "position", + "uv0" + ], + "shadingModel" : "lit", + "blending" : "opaque" +} +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + material.baseColor.rgb = materialParams.color; + material.metallic = materialParams.metallic; + material.roughness = materialParams.roughness; + material.reflectance = materialParams.reflectance; + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_opaque_textured_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_opaque_textured_material.mat new file mode 100755 index 00000000..be9a088c --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_opaque_textured_material.mat @@ -0,0 +1,37 @@ +material { + "name" : "Opaque Textured", + + "parameters" : [ + { + "type" : "sampler2d", + "name" : "texture" + }, + { + "type" : "float", + "name" : "metallic" + }, + { + "type" : "float", + "name" : "roughness" + }, + { + "type" : "float", + "name" : "reflectance" + } + ], + "requires" : [ + "position", + "uv0" + ], + "shadingModel" : "lit", + "blending" : "opaque" +} +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + material.baseColor = texture(materialParams_texture, getUV0()); + material.metallic = materialParams.metallic; + material.roughness = materialParams.roughness; + material.reflectance = materialParams.reflectance; + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_plane_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_plane_material.mat new file mode 100755 index 00000000..66cbcccb --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_plane_material.mat @@ -0,0 +1,74 @@ +material { + name : "AR Core Plane Material", + + "parameters": [ + { + "type": "sampler2d", + "name": "texture" + }, + { + "type": "float3", + "name": "color" + }, + { + "type": "float2", + "name": "uvScale" + }, + { + "type": "float3", + "name": "focusPoint" + }, + { + "type": "float", + "name": "radius" + } + ], + "variables" : [ + "texCoordsAlpha", + "smoothWorldPosition" + ], + "requires" : [ + "position" + ], + shadingModel : unlit, + "blending": "transparent" +} + +vertex { + void materialVertex(inout MaterialVertexInputs material) { + float3 pos = getPosition().xyz; + + // The Y position of the vertex represents the Alpha of the plane at this Vertex. + material.texCoordsAlpha.z = pos.y; + + // Zero out the Y vertex and compute the world position. + pos.y = 0.0; + material.worldPosition = mulMat4x4Float3(getWorldFromModelMatrix(), pos); + material.smoothWorldPosition = material.worldPosition; + + // Compute the texture coordinates. + // The X axis of the texture corresponds to the local X axis of the plane. + // The Y axis of the texture corresponds to the local Z axis of the plane. + // Scale the texture coordinates by the scale parameter passed into the material. + material.texCoordsAlpha.x = pos.x * materialParams.uvScale.x; + material.texCoordsAlpha.y = pos.z * materialParams.uvScale.y; + } +} + +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + + material.baseColor = texture(materialParams_texture, variable_texCoordsAlpha.xy); + material.baseColor.rgb *= materialParams.color; + float textureAlpha = material.baseColor.a; + + // Create a spotlight effect around the focus point. + float distToFocus = distance(variable_smoothWorldPosition.xyz, materialParams.focusPoint); + float alpha = smoothstep(materialParams.radius, materialParams.radius * .5f, distToFocus); + + // Transparent blending uses pre-multiplied alpha, + // so multiply the entire baseColor by the alpha for this fragment. + material.baseColor *= variable_texCoordsAlpha.z * alpha; + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_plane_shadow_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_plane_shadow_material.mat new file mode 100755 index 00000000..82a57aa2 --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_plane_shadow_material.mat @@ -0,0 +1,24 @@ +material { + name : "AR Core Plane Shadow Material", + shadingModel : unlit, + blending : transparent, + shadowMultiplier : true +} + +vertex { + void materialVertex(inout MaterialVertexInputs material) { + float3 pos = getPosition().xyz; + + // Shift the verticies upwards so we don't z-fight with the plane material. + pos.y = 0.005f; + material.worldPosition = mulMat4x4Float3(getWorldFromModelMatrix(), pos); + } +} + +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + + material.baseColor = float4(0.0f, 0.0f, 0.0f, .6f); + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_transparent_colored_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_transparent_colored_material.mat new file mode 100755 index 00000000..44aa2b93 --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_transparent_colored_material.mat @@ -0,0 +1,37 @@ +material { + "name" : "Transparent Colored", + + "parameters" : [ + { + "type" : "float4", + "name" : "color" + }, + { + "type" : "float", + "name" : "metallic" + }, + { + "type" : "float", + "name" : "roughness" + }, + { + "type" : "float", + "name" : "reflectance" + } + ], + "requires" : [ + "position", + "uv0" + ], + "shadingModel" : "lit", + "blending" : "transparent" +} +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + material.baseColor = materialParams.color; + material.metallic = materialParams.metallic; + material.roughness = materialParams.roughness; + material.reflectance = materialParams.reflectance; + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_transparent_textured_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_transparent_textured_material.mat new file mode 100755 index 00000000..858c82d7 --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_transparent_textured_material.mat @@ -0,0 +1,37 @@ +material { + "name" : "Transparent Textured", + + "parameters" : [ + { + "type" : "sampler2d", + "name" : "texture" + }, + { + "type" : "float", + "name" : "metallic" + }, + { + "type" : "float", + "name" : "roughness" + }, + { + "type" : "float", + "name" : "reflectance" + } + ], + "requires" : [ + "position", + "uv0" + ], + "shadingModel" : "lit", + "blending" : "transparent" +} +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + material.baseColor = texture(materialParams_texture, getUV0()); + material.metallic = materialParams.metallic; + material.roughness = materialParams.roughness; + material.reflectance = materialParams.reflectance; + } +} diff --git a/sceneformsrc/sceneform/sampleData/sceneform_view_material.mat b/sceneformsrc/sceneform/sampleData/sceneform_view_material.mat new file mode 100755 index 00000000..eae3d460 --- /dev/null +++ b/sceneformsrc/sceneform/sampleData/sceneform_view_material.mat @@ -0,0 +1,43 @@ +material { + "name" : "View", + "defines" : [ + "baseColor" + ], + "parameters" : [ + { + "type" : "samplerExternal", + "name" : "viewTexture" + }, + { + "type" : "float2", + "name" : "offsetUv" + } + ], + "requires" : [ + "position", + "uv0" + ], + "shadingModel" : "unlit", + "blending" : "transparent", + "doubleSided" : true +} + +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + + vec2 uv = getUV0(); + + if (!gl_FrontFacing) { + uv.x = 1.0 - uv.x; + } + + // Set offsetUv if we want to invert around an axis. + // In front facing camera, set offsetUv.x to 1 and offsetUv.y to 0. + uv.x = uv.x + materialParams.offsetUv.x * (1.0 - 2.0 * uv.x); + uv.y = uv.y + materialParams.offsetUv.y * (1.0 - 2.0 * uv.y); + + material.baseColor = texture(materialParams_viewTexture, uv); + material.baseColor.rgb = inverseTonemapSRGB(material.baseColor.rgb); + } +} diff --git a/sceneformsrc/sceneform/sampleData/small_empty_house_2k.exr b/sceneformsrc/sceneform/sampleData/small_empty_house_2k.exr new file mode 100644 index 00000000..b9259635 Binary files /dev/null and b/sceneformsrc/sceneform/sampleData/small_empty_house_2k.exr differ diff --git a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/Renderer.java b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/Renderer.java index 3c4c27ad..f4528651 100644 --- a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/Renderer.java +++ b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/Renderer.java @@ -154,7 +154,12 @@ public SurfaceView getSurfaceView() { /** @hide */ public void setClearColor(Color color) { - view.setClearColor(color.r, color.g, color.b, color.a); + com.google.android.filament.Renderer.ClearOptions options = new com.google.android.filament.Renderer.ClearOptions(); + options.clearColor[0] = color.r; + options.clearColor[1] = color.g; + options.clearColor[2] = color.b; + options.clearColor[3] = color.a; + renderer.setClearOptions(options); } /** @hide */ @@ -275,7 +280,7 @@ public void render(boolean debugEnabled) { throw new AssertionError("Internal Error: Failed to get swap chain"); } - if (renderer.beginFrame(swapChainLocal)) { + if (renderer.beginFrame(swapChainLocal, 0)) { if (preRenderCallback != null) { preRenderCallback.preRender(renderer, swapChainLocal, camera); } @@ -411,7 +416,6 @@ public void setDynamicResolutionEnabled(boolean isEnabled) { // TODO: This functionality should probably be exposed to the developer eventually. DynamicResolutionOptions options = new DynamicResolutionOptions(); options.enabled = isEnabled; - options.targetFrameTimeMilli = 1000.0f / 30.0f; view.setDynamicResolutionOptions(options); } @@ -554,7 +558,6 @@ private void initialize() { setDynamicResolutionEnabled(true); - emptyView.setClearColor(0, 0, 0, 1); emptyView.setCamera(engine.createCamera()); emptyView.setScene(engine.createScene()); } diff --git a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/RenderingResources.java b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/RenderingResources.java index 3d18baf5..780310db 100644 --- a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/RenderingResources.java +++ b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/RenderingResources.java @@ -15,7 +15,7 @@ public static enum Resource { PLANE_SHADOW_MATERIAL, PLANE_MATERIAL, PLANE, - VIEW_RENDERABLE, + VIEW_RENDERABLE_MATERIAL, }; @@ -40,8 +40,8 @@ private static int GetSceneformSourceResource(Context context, Resource resource return LoadHelper.rawResourceNameToIdentifier(context, "sceneform_plane_material"); case PLANE: return LoadHelper.drawableResourceNameToIdentifier(context, "sceneform_plane"); - case VIEW_RENDERABLE: - return LoadHelper.rawResourceNameToIdentifier(context, "sceneform_view_renderable"); + case VIEW_RENDERABLE_MATERIAL: + return LoadHelper.rawResourceNameToIdentifier(context, "sceneform_view_material"); } return 0; } diff --git a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/ViewRenderable.java b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/ViewRenderable.java index 820e476f..8a8f9c25 100644 --- a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/ViewRenderable.java +++ b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/ViewRenderable.java @@ -17,8 +17,12 @@ import com.google.ar.sceneform.resources.ResourceRegistry; import com.google.ar.sceneform.utilities.AndroidPreconditions; import com.google.ar.sceneform.utilities.Preconditions; + +import java.util.ArrayList; +import java.util.Arrays; import java.util.OptionalInt; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; /** * Renders a 2D Android view in 3D space by attaching it to a {@link com.google.ar.sceneform.Node} @@ -429,17 +433,61 @@ public Builder setVerticalAlignment(VerticalAlignment verticalAlignment) { @SuppressWarnings("AndroidApiChecker") // java.util.concurrent.CompletableFuture public CompletableFuture build() { if (!hasSource() && context != null) { - setSource( - context, - RenderingResources.GetSceneformResource( - context, RenderingResources.Resource.VIEW_RENDERABLE)); + // For ViewRenderables, the registryId must come from the View, not the RCB source. + // If the source is a View, use that as the registryId. If the view is null, then the source + // is a resource id and the registryId should also be null. + registryId = view; + + CompletableFuture setSourceFuture = Material.builder() + .setSource( + context, + RenderingResources.GetSceneformResource( + context, RenderingResources.Resource.VIEW_RENDERABLE_MATERIAL)) + .build() + .thenAccept( + material -> { + + ArrayList vertices = new ArrayList<>(); + vertices.add(Vertex.builder() + .setPosition(new Vector3(-0.5f, 0.0f, 0.0f)) + .setNormal(new Vector3(0.0f, 0.0f, 1.0f)) + .setUvCoordinate(new Vertex.UvCoordinate(0.0f, 0.0f)) + .build()); + vertices.add(Vertex.builder() + .setPosition(new Vector3(0.5f, 0.0f, 0.0f)) + .setNormal(new Vector3(0.0f, 0.0f, 1.0f)) + .setUvCoordinate(new Vertex.UvCoordinate(1.0f, 0.0f)) + .build()); + vertices.add(Vertex.builder() + .setPosition(new Vector3(-0.5f, 1.0f, 0.0f)) + .setNormal(new Vector3(0.0f, 0.0f, 1.0f)) + .setUvCoordinate(new Vertex.UvCoordinate(0.0f, 1.0f)) + .build()); + vertices.add(Vertex.builder() + .setPosition(new Vector3(0.5f, 1.0f, 0.0f)) + .setNormal(new Vector3(0.0f, 0.0f, 1.0f)) + .setUvCoordinate(new Vertex.UvCoordinate(1.0f, 1.0f)) + .build()); + ArrayList triangleIndices = new ArrayList<>(); + triangleIndices.add(0); + triangleIndices.add(1); + triangleIndices.add(2); + triangleIndices.add(1); + triangleIndices.add(3); + triangleIndices.add(2); + RenderableDefinition.Submesh submesh = + RenderableDefinition.Submesh.builder().setTriangleIndices(triangleIndices).setMaterial(material).build(); + setSource( + RenderableDefinition.builder() + .setVertices(vertices) + .setSubmeshes(Arrays.asList(submesh)) + .build() + ); + } + ); + return setSourceFuture.thenCompose((Void) -> super.build()); } - // For ViewRenderables, the registryId must come from the View, not the RCB source. - // If the source is a View, use that as the registryId. If the view is null, then the source - // is a resource id and the registryId should also be null. - registryId = view; - return super.build(); } diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_camera_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_camera_material.matc index 5074a1aa..cbec83be 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_camera_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_camera_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_colored_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_colored_material.matc index b2732aad..909b8d9b 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_colored_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_colored_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_textured_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_textured_material.matc index 67849ccc..21835044 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_textured_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_opaque_textured_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_material.matc index cb3d3990..2b3dcb9b 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_shadow_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_shadow_material.matc index 8a45e9ee..e5c9e521 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_shadow_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_plane_shadow_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_colored_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_colored_material.matc index eb4857a1..8183c778 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_colored_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_colored_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_textured_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_textured_material.matc index e06ba892..bcf1ec46 100644 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_textured_material.matc and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_transparent_textured_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_view_material.matc b/sceneformsrc/sceneform/src/main/res/raw/sceneform_view_material.matc new file mode 100755 index 00000000..028d3ae8 Binary files /dev/null and b/sceneformsrc/sceneform/src/main/res/raw/sceneform_view_material.matc differ diff --git a/sceneformsrc/sceneform/src/main/res/raw/sceneform_view_renderable.sfb b/sceneformsrc/sceneform/src/main/res/raw/sceneform_view_renderable.sfb deleted file mode 100644 index d0ade6c8..00000000 Binary files a/sceneformsrc/sceneform/src/main/res/raw/sceneform_view_renderable.sfb and /dev/null differ