Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f64e345e9b | ||
|
|
2e83be8414 | ||
|
|
e7b5f24cf7 | ||
|
|
f4665a4c9f | ||
|
|
72f21a21af | ||
|
|
f677d522b4 | ||
|
|
13d3372fc4 | ||
|
|
55b9c00292 | ||
|
|
7b41c64a59 | ||
|
|
bf43130c0d | ||
|
|
65c561c440 | ||
|
|
d6818e8816 | ||
|
|
cbe0056ab2 | ||
|
|
9aa28ca830 | ||
|
|
db128c8f49 | ||
|
|
3e33975e2a | ||
|
|
86889c334e | ||
|
|
0db09f12c3 | ||
|
|
481bdefa74 | ||
|
|
41adba285d | ||
|
|
3f7faff423 | ||
|
|
4721726618 | ||
|
|
aa9a524c33 | ||
|
|
1d1a1a4907 | ||
|
|
58f8c42b04 | ||
|
|
701187ec11 | ||
|
|
cb7b600eda | ||
|
|
e7834d7032 | ||
|
|
f7fd225bc6 | ||
|
|
dfb973bed0 | ||
|
|
326593eb4f | ||
|
|
57ac3a674c | ||
|
|
db5fb1e04a | ||
|
|
c17ac7e6b5 | ||
|
|
3c0dda0e28 | ||
|
|
7d3427e4c0 | ||
|
|
75c20ecfed | ||
|
|
5455da4a57 | ||
|
|
67404122fb | ||
|
|
1a621bd5bf | ||
|
|
8d195515c3 | ||
|
|
a9239fc39f | ||
|
|
8dc5aab8fe | ||
|
|
c711a90592 | ||
|
|
41081bf62d | ||
|
|
acd9eea405 | ||
|
|
a112cecfbf | ||
|
|
ceba7f90ac | ||
|
|
7ff02db939 | ||
|
|
599e041732 | ||
|
|
48517e685d | ||
|
|
a64a6715ee | ||
|
|
847918884e | ||
|
|
2acce4ad70 | ||
|
|
b5f1e076a0 | ||
|
|
0318224673 | ||
|
|
610537fe9d | ||
|
|
cb59a5c1c8 | ||
|
|
f7d41908dc | ||
|
|
e1f4c01ce6 | ||
|
|
526e8d22f2 | ||
|
|
3207c47dd2 | ||
|
|
60afc59582 | ||
|
|
12b26a0555 | ||
|
|
f36ec52f4a | ||
|
|
4f0be3ecc1 | ||
|
|
1070b2f098 | ||
|
|
51616af8ce | ||
|
|
ded9642c4d | ||
|
|
86e903fc86 | ||
|
|
628597fe59 | ||
|
|
365387b8d9 | ||
|
|
09b7bddc84 | ||
|
|
cf07788d74 | ||
|
|
8c39579e1c | ||
|
|
a43bd12970 | ||
|
|
1852717ae3 | ||
|
|
af56b1e5c4 | ||
|
|
4e7ef7ed93 | ||
|
|
1b201b8831 | ||
|
|
ad8ce037fd | ||
|
|
41756e71df | ||
|
|
adf45c1b55 | ||
|
|
f63f46e975 | ||
|
|
3ca95b90f8 | ||
|
|
225591bf22 | ||
|
|
baa6733872 | ||
|
|
00106ac0f6 | ||
|
|
cbdbdb5698 | ||
|
|
203b211bde | ||
|
|
fc9f9d7054 | ||
|
|
2026c41a23 | ||
|
|
6a5b5d9d5d | ||
|
|
0a2a5c45be | ||
|
|
8e721b9c42 | ||
|
|
0d90c33380 | ||
|
|
ea602c4f8f | ||
|
|
e4c89a2651 | ||
|
|
64ebe51ea4 | ||
|
|
541b610c87 | ||
|
|
ef7318dd35 | ||
|
|
2b4066fa32 | ||
|
|
a8eebf519f | ||
|
|
742635813b | ||
|
|
7cb94d268c | ||
|
|
a418be886c | ||
|
|
3d205ab184 | ||
|
|
e6bef08ecf | ||
|
|
fab00f8466 | ||
|
|
ac43d3b0aa | ||
|
|
2e059eef07 | ||
|
|
bf8a14f549 | ||
|
|
8e1c574122 | ||
|
|
ef5f391ef5 | ||
|
|
e8cf1c6a2f | ||
|
|
80ff2a091a | ||
|
|
bf99aeb1db |
@@ -20,8 +20,10 @@ android {
|
|||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
abiFilters.addAll( 'arm64-v8a', 'x86_64')
|
abiFilters.addAll( 'arm64-v8a')
|
||||||
arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static', '-DVKB_VALIDATION_LAYERS=OFF'
|
arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static', '-DVKB_VALIDATION_LAYERS=OFF'
|
||||||
|
//arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static', '-DVKB_VALIDATION_LAYERS=OFF', "-DCMAKE_BUILD_TYPE=Release"
|
||||||
|
//cppFlags "-DRELEASE_MODE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,5 +99,5 @@ dependencies {
|
|||||||
implementation "androidx.camera:camera-lifecycle:$camerax_version"
|
implementation "androidx.camera:camera-lifecycle:$camerax_version"
|
||||||
implementation "androidx.camera:camera-view:$camerax_version"
|
implementation "androidx.camera:camera-view:$camerax_version"
|
||||||
//noinspection Aligned16KB
|
//noinspection Aligned16KB
|
||||||
implementation 'com.google.mediapipe:tasks-vision:0.20230731'
|
implementation 'com.google.mediapipe:tasks-vision:0.10.26'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
#version 450
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2023 Nintendo
|
* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -14,12 +13,10 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
task downloadTaskFile(type: Download) {
|
||||||
layout (location = 0) in vec3 inColor;
|
src 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task'
|
||||||
|
dest project.ext.ASSET_DIR + '/face_landmarker.task'
|
||||||
layout (location = 0) out vec4 outColor;
|
overwrite false
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outColor = vec4(inColor, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preBuild.dependsOn downloadTaskFile
|
||||||
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1,120 @@
|
|||||||
|
{
|
||||||
|
"accessors" : [
|
||||||
|
{
|
||||||
|
"bufferView" : 0,
|
||||||
|
"componentType" : 5126,
|
||||||
|
"count" : 24,
|
||||||
|
"type" : "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView" : 1,
|
||||||
|
"componentType" : 5126,
|
||||||
|
"count" : 24,
|
||||||
|
"max" : [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min" : [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type" : "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView" : 2,
|
||||||
|
"componentType" : 5126,
|
||||||
|
"count" : 24,
|
||||||
|
"type" : "VEC4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView" : 3,
|
||||||
|
"componentType" : 5126,
|
||||||
|
"count" : 24,
|
||||||
|
"type" : "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView" : 4,
|
||||||
|
"componentType" : 5121,
|
||||||
|
"count" : 36,
|
||||||
|
"type" : "SCALAR"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"asset" : {
|
||||||
|
"generator" : "Khronos Blender glTF 2.0 I/O",
|
||||||
|
"version" : "2.0"
|
||||||
|
},
|
||||||
|
"bufferViews" : [
|
||||||
|
{
|
||||||
|
"buffer" : 0,
|
||||||
|
"byteLength" : 288,
|
||||||
|
"byteOffset" : 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer" : 0,
|
||||||
|
"byteLength" : 288,
|
||||||
|
"byteOffset" : 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer" : 0,
|
||||||
|
"byteLength" : 384,
|
||||||
|
"byteOffset" : 576
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer" : 0,
|
||||||
|
"byteLength" : 192,
|
||||||
|
"byteOffset" : 960
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer" : 0,
|
||||||
|
"byteLength" : 36,
|
||||||
|
"byteOffset" : 1152
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers" : [
|
||||||
|
{
|
||||||
|
"byteLength" : 1188,
|
||||||
|
"uri" : "data:application/octet-stream;base64,AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAgAAAAAAAAIC/AAAAgAAAAAAAAIC/AAAAgAAAAAAAAIC/AACAPwAAAAAAAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAAAAgAAAAIAAAIA/AAAAgAAAAIAAAIA/AAAAgAAAAIAAAIA/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AACAPwAAAIAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAACAvwAAgD8AAIC/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAPwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD8AAIA/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAvwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAPwAAgD8AAIC/AACAvwAAgD8AAIA/AACAPwAAgD8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/AAAAAAAAAAAAAIC/AACAvwAAAAAAAAAAAACAvwAAgL8AAAAAAAAAAAAAgL8AAIC/AACAPwAAAAAAAACAAACAvwAAgD8AAAAAAAAAgAAAgL8AAIA/AAAAAAAAAIAAAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAvwAAgD8AAAAAAAAAAAAAgL8AAIA/AACAPwAAAAAAAACAAACAPwAAgD8AAAAAAAAAgAAAgD8AAIA/AAAAAAAAAIAAAIA/AACAPwAAAAAAAACAAACAvwAAgD8AAAAAAAAAgAAAgL8AAIA/AAAAAAAAAIAAAIC/AACAPwAAAAAAAACAAACAPwAAgD8AAAAAAAAAgAAAgD8AAIA/AAAAAAAAAIAAAIA/AAAAAAAAAAAAAIC/AACAvwAAgD8AAAAAAAAAgAAAgL8AAAAAAAAAAAAAgL8AAIA/AACAPwAAAAAAAACAAACAPwAAgD8AAAAAAAAAgAAAgL8AAIA/AAAAAAAAAIAAAIA/AAAAAAAAgD8AAIC/AAAAQAAAgL8AAIA/AAAAAAAAgD8AAIC/AAAAQAAAgL8AAIA/AAAAAAAAgD8AAIA/AAAAQAAAgD8AAIA/AAAAAAAAgD8AAIA/AAAAQAAAgD8AAIA/AAAAAAAAgD8AAIA/AAAAQAAAAAAAAABAAAAAAAAAgD8AAIC/AAAAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAEAAAIA/AACAPwAAgL8AAIA/AAECAwQFBgcICQoLDA0ODxARABIBAxMEBhQHCRUKDBYNDxcQ"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensions" : {},
|
||||||
|
"materials" : [
|
||||||
|
{
|
||||||
|
"name" : "Material",
|
||||||
|
"pbrMetallicRoughness" : {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes" : [
|
||||||
|
{
|
||||||
|
"name" : "Cube.001",
|
||||||
|
"primitives" : [
|
||||||
|
{
|
||||||
|
"attributes" : {
|
||||||
|
"NORMAL" : 0,
|
||||||
|
"POSITION" : 1,
|
||||||
|
"TANGENT" : 2,
|
||||||
|
"TEXCOORD_0" : 3
|
||||||
|
},
|
||||||
|
"indices" : 4,
|
||||||
|
"material" : 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes" : [
|
||||||
|
{
|
||||||
|
"mesh" : 0,
|
||||||
|
"name" : "Cube"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene" : 0,
|
||||||
|
"scenes" : [
|
||||||
|
{
|
||||||
|
"name" : "Scene",
|
||||||
|
"nodes" : [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
////
|
||||||
|
- Copyright (c) 2024-2025, Sascha Willems
|
||||||
|
-
|
||||||
|
- SPDX-License-Identifier: Apache-2.0
|
||||||
|
-
|
||||||
|
- Licensed under the Apache License, Version 2.0 the "License";
|
||||||
|
- you may not use this file except in compliance with the License.
|
||||||
|
- You may obtain a copy of the License at
|
||||||
|
-
|
||||||
|
- http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
-
|
||||||
|
- Unless required by applicable law or agreed to in writing, software
|
||||||
|
- distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
- See the License for the specific language governing permissions and
|
||||||
|
- limitations under the License.
|
||||||
|
-
|
||||||
|
////
|
||||||
|
= Shaders
|
||||||
|
|
||||||
|
== Shader languages
|
||||||
|
|
||||||
|
This folder contains the textual shaders for the samples. All samples come with GLSL shaders and some optionally with HLSL shaders. For samples that support both shader language this is a good way to compare GLSL to HLSL syntax when targeting SPIR-V for Vulkan.
|
||||||
|
|
||||||
|
== Compiling shaders
|
||||||
|
|
||||||
|
The samples load offline compiled SPIR-V variants of the GLSL/HLSL shaders. If you have the appropriate compiler installed, e.g. via the LunarG VUlkan SDK, shaders will be automatically compiled when building the samples project.
|
||||||
|
|
||||||
|
== Further information
|
||||||
|
|
||||||
|
The xref:guide:ROOT:index.adoc[Vulkan Guide] contains further information on how to use HLSL with Vulkan and how it compares to GLSL:
|
||||||
|
|
||||||
|
* xref:guide::hlsl.adoc[HLSL in Vulkan]
|
||||||
|
* xref:guide::high_level_shader_language_comparison.adoc[High level shading language comparison]
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MAX_LIGHT_COUNT 8
|
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler2D base_color_texture;
|
layout(set = 0, binding = 0) uniform sampler2D base_color_texture;
|
||||||
@@ -28,21 +26,31 @@ layout(location = 2) in vec3 in_normal;
|
|||||||
|
|
||||||
layout(location = 0) out vec4 o_color;
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
layout(set = 0, binding = 1) uniform MVPUniform
|
layout(set = 0, binding = 1) uniform GlobalUniform
|
||||||
{
|
{
|
||||||
mat4 model;
|
mat4 model;
|
||||||
mat4 view_proj;
|
mat4 view_proj;
|
||||||
mat4 scale;
|
vec3 camera_position;
|
||||||
mat4 padding;
|
}
|
||||||
} mvp_uniform;
|
global_uniform;
|
||||||
|
|
||||||
|
// Push constants come with a limitation in the size of data.
|
||||||
|
// The standard requires at least 128 bytes
|
||||||
|
layout(push_constant, std430) uniform PBRMaterialUniform
|
||||||
|
{
|
||||||
|
vec4 base_color_factor;
|
||||||
|
float metallic_factor;
|
||||||
|
float roughness_factor;
|
||||||
|
}
|
||||||
|
pbr_material_uniform;
|
||||||
|
|
||||||
#include "lighting.h"
|
#include "lighting.h"
|
||||||
|
|
||||||
layout(set = 0, binding = 4) uniform LightsInfo
|
layout(set = 0, binding = 4) uniform LightsInfo
|
||||||
{
|
{
|
||||||
Light directional_lights[MAX_LIGHT_COUNT];
|
Light directional_lights[48];
|
||||||
Light point_lights[MAX_LIGHT_COUNT];
|
Light point_lights[48];
|
||||||
Light spot_lights[MAX_LIGHT_COUNT];
|
Light spot_lights[48];
|
||||||
}
|
}
|
||||||
lights_info;
|
lights_info;
|
||||||
|
|
||||||
@@ -15,11 +15,16 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
layout (location = 0) out vec2 outUV;
|
layout (binding = 0) uniform sampler2D fontSampler;
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 inUV;
|
||||||
|
layout (location = 1) in vec4 inColor;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
outColor = inColor * texture(fontSampler, inUV);
|
||||||
gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 320 es
|
||||||
/* Copyright (c) 2021-2024, Sascha Willems
|
/* Copyright (c) 2019, Arm Limited and Contributors
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -16,19 +16,27 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
layout (location = 0) in vec3 inPos;
|
precision mediump float;
|
||||||
layout (location = 1) in vec2 inUV;
|
|
||||||
|
|
||||||
layout (binding = 0) uniform UBO
|
layout (location = 0) in vec2 inPos;
|
||||||
{
|
layout (location = 1) in vec2 inUV;
|
||||||
mat4 projection;
|
layout (location = 2) in vec4 inColor;
|
||||||
mat4 model;
|
|
||||||
} ubo;
|
layout (push_constant) uniform PushConstants {
|
||||||
|
mat4 transform;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
layout (location = 0) out vec2 outUV;
|
layout (location = 0) out vec2 outUV;
|
||||||
|
layout (location = 1) out vec4 outColor;
|
||||||
|
|
||||||
void main()
|
out gl_PerVertex
|
||||||
|
{
|
||||||
|
vec4 gl_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main()
|
||||||
{
|
{
|
||||||
outUV = inUV;
|
outUV = inUV;
|
||||||
gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0);
|
outColor = inColor;
|
||||||
|
gl_Position = pushConstants.transform * vec4(inPos.xy, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/* Copyright (c) 2020-2025, Arm Limited and Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 the "License";
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Light
|
||||||
|
{
|
||||||
|
vec4 position; // position.w represents type of light
|
||||||
|
vec4 color; // color.w represents light intensity
|
||||||
|
vec4 direction; // direction.w represents range
|
||||||
|
vec2 info; // (only used for spot lights) info.x represents light inner cone angle, info.y represents light outer cone angle
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 apply_directional_light(Light light, vec3 normal)
|
||||||
|
{
|
||||||
|
vec3 world_to_light = -light.direction.xyz;
|
||||||
|
world_to_light = normalize(world_to_light);
|
||||||
|
float ndotl = clamp(dot(normal, world_to_light), 0.0, 1.0);
|
||||||
|
return ndotl * light.color.w * light.color.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 apply_point_light(Light light, vec3 pos, vec3 normal)
|
||||||
|
{
|
||||||
|
vec3 world_to_light = light.position.xyz - pos;
|
||||||
|
float dist = length(world_to_light) * 0.005;
|
||||||
|
float atten = 1.0 / (dist * dist);
|
||||||
|
world_to_light = normalize(world_to_light);
|
||||||
|
float ndotl = clamp(dot(normal, world_to_light), 0.0, 1.0);
|
||||||
|
return ndotl * light.color.w * atten * light.color.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 apply_spot_light(Light light, vec3 pos, vec3 normal)
|
||||||
|
{
|
||||||
|
vec3 light_to_pixel = normalize(pos - light.position.xyz);
|
||||||
|
float theta = dot(light_to_pixel, normalize(light.direction.xyz));
|
||||||
|
float inner_cone_angle = light.info.x;
|
||||||
|
float outer_cone_angle = light.info.y;
|
||||||
|
float intensity = (theta - outer_cone_angle) / (inner_cone_angle - outer_cone_angle);
|
||||||
|
return smoothstep(0.0, 1.0, intensity) * light.color.w * light.color.rgb;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 450
|
||||||
/* Copyright (c) 2023-2024, Sascha Willems
|
/* Copyright (c) 2022-2024, Sascha Willems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -16,13 +16,16 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
layout (set = 2, binding = 0) uniform sampler2D samplerColorMap;
|
#extension GL_EXT_nonuniform_qualifier : require
|
||||||
|
|
||||||
|
layout (set = 0, binding = 1) uniform sampler2D textures[];
|
||||||
|
|
||||||
layout (location = 0) in vec2 inUV;
|
layout (location = 0) in vec2 inUV;
|
||||||
|
layout (location = 1) flat in int inTexIndex;
|
||||||
|
|
||||||
layout (location = 0) out vec4 outFragColor;
|
layout (location = 0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
outFragColor = texture(samplerColorMap, inUV);
|
outFragColor = texture(textures[nonuniformEXT(inTexIndex)], inUV);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 450
|
||||||
/* Copyright (c) 2023-2024, Sascha Willems
|
/* Copyright (c) 2022-2024, Sascha Willems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -18,19 +18,20 @@
|
|||||||
|
|
||||||
layout (location = 0) in vec3 inPos;
|
layout (location = 0) in vec3 inPos;
|
||||||
layout (location = 1) in vec2 inUV;
|
layout (location = 1) in vec2 inUV;
|
||||||
layout (location = 2) in vec3 inNormal;
|
layout (location = 2) in int inTexIndex;
|
||||||
|
|
||||||
layout (binding = 0) uniform UBO
|
layout (binding = 0) uniform UBO
|
||||||
{
|
{
|
||||||
mat4 projection;
|
mat4 projection;
|
||||||
mat4 model;
|
mat4 view;
|
||||||
vec4 viewPos;
|
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
layout (location = 0) out vec2 outUV;
|
layout (location = 0) out vec2 outUV;
|
||||||
|
layout (location = 1) flat out int outTexIndex;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
outUV = inUV;
|
outUV = inUV;
|
||||||
gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0);
|
outTexIndex = inTexIndex;
|
||||||
|
gl_Position = ubo.projection * ubo.view * vec4(inPos.xyz, 1.0);
|
||||||
}
|
}
|
||||||
@@ -16,17 +16,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
[[vk::binding(1, 0)]]
|
[[vk::binding(1, 0)]]
|
||||||
Texture2D textureColor : register(t1, space0);
|
Texture2D textures[] : register(t1, space0);
|
||||||
[[vk::binding(1, 0)]]
|
[[vk::binding(1, 0)]]
|
||||||
SamplerState samplerColor : register(s1, space0);
|
SamplerState samplers[] : register(s1, space0);
|
||||||
|
|
||||||
struct VSOutput
|
struct VSOutput
|
||||||
{
|
{
|
||||||
float4 Pos : SV_POSITION;
|
float4 Pos : SV_POSITION;
|
||||||
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
||||||
|
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
float4 main(VSOutput input) : SV_TARGET0
|
float4 main(VSOutput input) : SV_TARGET
|
||||||
{
|
{
|
||||||
return textureColor.Sample(samplerColor, input.UV);
|
return textures[NonUniformResourceIndex(input.TexIndex)].Sample(samplers[NonUniformResourceIndex(input.TexIndex)], input.UV);
|
||||||
}
|
}
|
||||||
@@ -15,18 +15,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
struct VSInput
|
struct VSInput
|
||||||
{
|
{
|
||||||
[[vk::location(0)]] float3 Pos : POSITION0;
|
[[vk::location(0)]] float3 Pos : POSITION0;
|
||||||
[[vk::location(1)]] float2 UV : TEXCOORD0;
|
[[vk::location(1)]] float2 UV : TEXCOORD0;
|
||||||
[[vk::location(2)]] float3 Normal : NORMAL0;
|
[[vk::location(2)]] int TexIndex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UBO
|
struct UBO
|
||||||
{
|
{
|
||||||
float4x4 projection;
|
float4x4 projection;
|
||||||
float4x4 model;
|
float4x4 view;
|
||||||
float4 viewPos;
|
|
||||||
};
|
};
|
||||||
[[vk::binding(0, 0)]]
|
[[vk::binding(0, 0)]]
|
||||||
ConstantBuffer<UBO> ubo : register(b0, space0);
|
ConstantBuffer<UBO> ubo : register(b0, space0);
|
||||||
@@ -35,12 +35,14 @@ struct VSOutput
|
|||||||
{
|
{
|
||||||
float4 Pos : SV_POSITION;
|
float4 Pos : SV_POSITION;
|
||||||
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
||||||
|
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
VSOutput main(VSInput input)
|
VSOutput main(VSInput input)
|
||||||
{
|
{
|
||||||
VSOutput output = (VSOutput) 0;
|
VSOutput output = (VSOutput) 0;
|
||||||
output.UV = input.UV;
|
output.UV = input.UV;
|
||||||
output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
|
output.TexIndex = input.TexIndex;
|
||||||
|
output.Pos = mul(ubo.projection, mul(ubo.view, float4(input.Pos.xyz, 1.0)));
|
||||||
return output;
|
return output;
|
||||||
};
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2024, Sascha Willems
|
/* Copyright (c) 2025, Sascha Willems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -15,16 +15,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Texture2D textureColor : register(t1);
|
[[vk::binding(1, 0)]]
|
||||||
SamplerState samplerColor : register(s1);
|
Sampler2D textures[] : register(t1, space0);
|
||||||
|
|
||||||
struct VSOutput
|
struct VSOutput
|
||||||
{
|
{
|
||||||
float4 Pos : SV_POSITION;
|
float4 Pos : SV_POSITION;
|
||||||
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
||||||
|
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[shader("fragment")]
|
||||||
float4 main(VSOutput input) : SV_TARGET
|
float4 main(VSOutput input) : SV_TARGET
|
||||||
{
|
{
|
||||||
return textureColor.Sample(samplerColor, input.UV);
|
return textures[NonUniformResourceIndex(input.TexIndex)].Sample(input.UV);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2024, Sascha Willems
|
/* Copyright (c) 2025, Sascha Willems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -15,34 +15,35 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
struct VSInput
|
struct VSInput
|
||||||
{
|
{
|
||||||
[[vk::location(0)]] float3 Pos : POSITION0;
|
[[vk::location(0)]] float3 Pos : POSITION0;
|
||||||
[[vk::location(1)]] float2 UV : TEXCOORD0;
|
[[vk::location(1)]] float2 UV : TEXCOORD0;
|
||||||
|
[[vk::location(2)]] int TexIndex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UBO
|
struct UBO
|
||||||
{
|
{
|
||||||
float4x4 projection;
|
float4x4 projection;
|
||||||
float4x4 view;
|
float4x4 view;
|
||||||
float4x4 model;
|
|
||||||
};
|
};
|
||||||
[[vk::binding(0, 0)]]
|
[[vk::binding(0, 0)]]
|
||||||
ConstantBuffer<UBO> ubo : register(b0);
|
ConstantBuffer<UBO> ubo : register(b0, space0);
|
||||||
|
|
||||||
struct VSOutput
|
struct VSOutput
|
||||||
{
|
{
|
||||||
float4 Pos : SV_POSITION;
|
float4 Pos : SV_POSITION;
|
||||||
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
||||||
[[vk::location(1)]] nointerpolation uint ColorOffset : TEXCOORD1;
|
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[shader("vertex")]
|
||||||
VSOutput main(VSInput input)
|
VSOutput main(VSInput input)
|
||||||
{
|
{
|
||||||
VSOutput output = (VSOutput) 0;
|
VSOutput output = (VSOutput) 0;
|
||||||
output.UV = input.UV;
|
output.UV = input.UV;
|
||||||
output.ColorOffset = input.Pos.z == 1.0 ? 4 : 0;
|
output.TexIndex = input.TexIndex;
|
||||||
output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
|
output.Pos = mul(ubo.projection, mul(ubo.view, float4(input.Pos.xyz, 1.0)));
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// 输入变量(与顶点着色器输出对应)
|
||||||
|
layout(location = 0) in vec2 inTexCoord;
|
||||||
|
|
||||||
|
// 输出颜色
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
// 纹理采样器
|
||||||
|
layout(binding = 0) uniform sampler2D texSampler;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 采样纹理
|
||||||
|
outColor = texture(texSampler, inTexCoord);
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// 硬编码的顶点数据 - 4个顶点组成三角形带覆盖整个屏幕
|
||||||
|
// const vec2 positions[6] = vec2[6](
|
||||||
|
// vec2( 1.0, 1.0), // 右上 - 三角形1
|
||||||
|
// vec2(-1.0, 1.0), // 左上 - 三角形1
|
||||||
|
// vec2(-1.0, -1.0), // 左下 - 三角形1
|
||||||
|
|
||||||
|
// vec2(-1.0, -1.0), // 左下 - 三角形2
|
||||||
|
// vec2( 1.0, -1.0), // 右下 - 三角形2
|
||||||
|
// vec2( 1.0, 1.0) // 右上 - 三角形2
|
||||||
|
// );
|
||||||
|
|
||||||
|
const float offset = (640-480)/(480.0);
|
||||||
|
|
||||||
|
|
||||||
|
const vec2 positions[6] = vec2[6](
|
||||||
|
vec2( 1.0, -1.0 -offset), // 右下
|
||||||
|
vec2(1.0, 1.0 + offset), // 右上 - 三角形1
|
||||||
|
vec2(-1.0, 1.0 + offset), // 左上 - 三角形1
|
||||||
|
|
||||||
|
vec2(-1.0, 1.0 + offset), // 左上 - 三角形2
|
||||||
|
vec2( -1.0, -1.0-offset), // 左下 - 三角形2
|
||||||
|
vec2( 1.0, -1.0-offset) // 右下 - 三角形2
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const vec2 texCoords[6] = vec2[6](
|
||||||
|
vec2(1.0, 1.0), // 右上
|
||||||
|
vec2(0.0, 1.0), // 左上
|
||||||
|
vec2(0.0, 0.0), // 左下
|
||||||
|
|
||||||
|
vec2(0.0, 0.0), // 左下
|
||||||
|
vec2(1.0, 0.0), // 右下
|
||||||
|
vec2(1.0, 1.0) // 右上
|
||||||
|
);
|
||||||
|
|
||||||
|
// 定义 Push Constant,只有一个 float
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
float myValue;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
|
|
||||||
|
// 输出变量
|
||||||
|
layout(location = 0) out vec2 outTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 获取顶点位置
|
||||||
|
vec2 position = positions[gl_VertexIndex];
|
||||||
|
position = position * pushConstants.myValue;
|
||||||
|
|
||||||
|
// 设置输出位置(Vulkan使用不同的坐标系)
|
||||||
|
gl_Position = vec4(position, 0.0, 1.0);
|
||||||
|
|
||||||
|
// 输出纹理坐标
|
||||||
|
outTexCoord = texCoords[gl_VertexIndex];
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 1) in vec3 fragLineStart;
|
||||||
|
layout(location = 2) in vec3 fragLineEnd;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UniformBufferObject {
|
||||||
|
mat4 proj;
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
layout(binding = 1) uniform DashParameters {
|
||||||
|
float dashSize;
|
||||||
|
float gapSize;
|
||||||
|
float dashOffset;
|
||||||
|
float uAASize;
|
||||||
|
int useWorldSpace;
|
||||||
|
} dashParams;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragPos = gl_FragCoord.xy;
|
||||||
|
|
||||||
|
// 网格参数
|
||||||
|
float gridSize = 14.0; // 网格大小
|
||||||
|
float dotRadius = 6.0; // 点状半径
|
||||||
|
|
||||||
|
// 计算当前片段所在的网格和网格中心坐标
|
||||||
|
vec2 gridCoord = fragPos / gridSize;
|
||||||
|
vec2 gridCenter = (floor(gridCoord) + 0.5) * gridSize;
|
||||||
|
|
||||||
|
// 计算片段到网格中心的距离
|
||||||
|
float distanceToCenter = length(fragPos - gridCenter);
|
||||||
|
|
||||||
|
// 如果距离超过点状半径,丢弃(创建点状虚线)
|
||||||
|
if (distanceToCenter > dotRadius && fragColor.y > 0.5) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
outColor = vec4(fragColor, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 inPosition;
|
||||||
|
layout(location = 1) in vec3 inColor;
|
||||||
|
layout(location = 2) in vec3 inLineStart;
|
||||||
|
layout(location = 3) in vec3 inLineEnd;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
layout(location = 1) out vec3 fragLineStart;
|
||||||
|
layout(location = 2) out vec3 fragLineEnd;
|
||||||
|
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UniformBufferObject {
|
||||||
|
mat4 proj;
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
float myValue;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
mat4 worldviewproj = ubo.proj * ubo.view * ubo.model;
|
||||||
|
//gl_Position = worldviewproj * vec4(inPosition, 1.0);
|
||||||
|
|
||||||
|
vec2 position = vec2(inPosition.xy*2 -1);
|
||||||
|
//gl_Position = vec4(inPosition.xy*2 -1, 0.5, 1.0);
|
||||||
|
position = position * pushConstants.myValue;
|
||||||
|
gl_Position = vec4(position, 0.5, 1.0);
|
||||||
|
|
||||||
|
fragColor = inColor;
|
||||||
|
|
||||||
|
fragLineStart = (worldviewproj * vec4(inLineStart, 1.0)).xyz;
|
||||||
|
fragLineEnd = (worldviewproj * vec4(inLineEnd, 1.0)).xyz;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(1, 0, 0, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 inPosition;
|
||||||
|
layout(location = 1) in vec3 inColor;
|
||||||
|
layout(location = 2) in vec3 inLineStart;
|
||||||
|
layout(location = 3) in vec3 inLineEnd;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UniformBufferObject {
|
||||||
|
mat4 proj;
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//mat4 worldviewproj = ubo.proj * ubo.view * ubo.model;
|
||||||
|
mat4 mvp = ubo.proj * ubo.view * ubo.model;
|
||||||
|
//gl_Position = worldviewproj * vec4(inPosition, 1.0);
|
||||||
|
gl_Position = mvp * vec4(inPosition, 1.0);
|
||||||
|
|
||||||
|
fragColor = inColor;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// 从顶点着色器接收的颜色
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
|
||||||
|
// 输出颜色
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(fragColor, 1.0); // 使用传入的颜色
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 inPosition;
|
||||||
|
layout(location = 1) in vec3 inColor;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UniformBufferObject {
|
||||||
|
mat4 proj;
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
float myValue;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 预计算MVP矩阵以减少乘法次数
|
||||||
|
//mat4 mvp = ubo.proj * ubo.view * ubo.model;
|
||||||
|
//vec3 pos = vec3(2.0, inPosition.y, inPosition.z);
|
||||||
|
//gl_Position = mvp * vec4(inPosition, 1.0);
|
||||||
|
|
||||||
|
vec2 position = vec2(inPosition.xy*2 -1);
|
||||||
|
//gl_Position = vec4(inPosition.xy*2 -1, 0.5, 1.0);
|
||||||
|
position = position * pushConstants.myValue;
|
||||||
|
gl_Position = vec4(position, 0.5, 1.0);
|
||||||
|
|
||||||
|
fragColor = inColor;
|
||||||
|
gl_PointSize = 2.0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout (binding = 1) uniform sampler2D samplerColor;
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 inUV;
|
||||||
|
layout (location = 1) in vec3 inNormal;
|
||||||
|
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = texture(samplerColor, inUV);
|
||||||
|
|
||||||
|
vec3 N = normalize(inNormal);
|
||||||
|
|
||||||
|
vec4 textureColor = color;
|
||||||
|
if (textureColor.a < 0.1) {
|
||||||
|
//textureColor = vec4(0.2, 0.2, 0.2, 0.5);
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
outFragColor = textureColor;
|
||||||
|
|
||||||
|
// outFragColor = vec4(1, 0, 0, 1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 inPos;
|
||||||
|
layout (location = 1) in vec2 inUV;
|
||||||
|
layout (location = 2) in vec3 inNormal;
|
||||||
|
|
||||||
|
layout (binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 projection;
|
||||||
|
mat4 model;
|
||||||
|
vec4 viewPos;
|
||||||
|
float lodBias;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
layout (location = 0) out vec2 outUV;
|
||||||
|
layout (location = 1) out vec3 outNormal;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
float myValue;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
|
out gl_PerVertex
|
||||||
|
{
|
||||||
|
vec4 gl_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outUV = inUV;
|
||||||
|
|
||||||
|
vec2 position = vec2(inPos.xy*2 -1);
|
||||||
|
position = position * pushConstants.myValue;
|
||||||
|
gl_Position = vec4(position, 0.5, 1.0);
|
||||||
|
|
||||||
|
vec4 pos = ubo.model * vec4(inPos, 1.0);
|
||||||
|
outNormal = mat3(inverse(transpose(ubo.model))) * inNormal;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,23 +15,29 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
[[vk::binding(1, 0)]]
|
||||||
|
Texture2D textureColor : register(t1);
|
||||||
|
[[vk::binding(1, 0)]]
|
||||||
|
SamplerState samplerColor : register(s1);
|
||||||
|
|
||||||
struct VSOutput
|
struct VSOutput
|
||||||
{
|
{
|
||||||
float4 Pos : SV_POSITION;
|
float4 Pos : SV_POSITION;
|
||||||
[[vk::location(0)]] float3 Normal : NORMAL0;
|
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
||||||
[[vk::location(1)]] float3 Color : COLOR0;
|
[[vk::location(1)]] float LodBias : FLOAT0;
|
||||||
[[vk::location(2)]] float3 ViewVec : TEXCOORD0;
|
[[vk::location(2)]] float3 Normal : NORMAL0;
|
||||||
[[vk::location(3)]] float3 LightVec : TEXCOORD1;
|
[[vk::location(3)]] float3 ViewVec : VECTOR0;
|
||||||
|
[[vk::location(4)]] float3 LightVec : VECTOR1;
|
||||||
};
|
};
|
||||||
|
|
||||||
float4 main(VSOutput input) : SV_TARGET0
|
float4 main(VSOutput input) : SV_TARGET0
|
||||||
{
|
{
|
||||||
|
float4 color = textureColor.SampleBias(samplerColor, input.UV, input.LodBias);
|
||||||
float3 N = normalize(input.Normal);
|
float3 N = normalize(input.Normal);
|
||||||
float3 L = normalize(input.LightVec);
|
float3 L = normalize(input.LightVec);
|
||||||
float3 V = normalize(input.ViewVec);
|
float3 V = normalize(input.ViewVec);
|
||||||
float3 R = reflect(-L, N);
|
float3 R = reflect(-L, N);
|
||||||
float3 ambient = (0.25).xxx;
|
|
||||||
float3 diffuse = max(dot(N, L), 0.0).xxx;
|
float3 diffuse = max(dot(N, L), 0.0).xxx;
|
||||||
float3 specular = (pow(max(dot(R, V), 0.0), 16.0)).xxx * 0.75;
|
float3 specular = (pow(max(dot(R, V), 0.0), 16.0)).xxx * color.a;
|
||||||
return float4((ambient + diffuse) * input.Color + specular, 1.0);
|
return float4(diffuse * color.rgb + specular, 1.0);
|
||||||
}
|
}
|
||||||
@@ -27,8 +27,7 @@ struct UBO
|
|||||||
float4x4 projection;
|
float4x4 projection;
|
||||||
float4x4 model;
|
float4x4 model;
|
||||||
float4 viewPos;
|
float4 viewPos;
|
||||||
float locSpeed;
|
float lodBias;
|
||||||
float globSpeed;
|
|
||||||
};
|
};
|
||||||
[[vk::binding(0, 0)]]
|
[[vk::binding(0, 0)]]
|
||||||
ConstantBuffer<UBO> ubo : register(b0);
|
ConstantBuffer<UBO> ubo : register(b0);
|
||||||
@@ -37,12 +36,25 @@ struct VSOutput
|
|||||||
{
|
{
|
||||||
float4 Pos : SV_POSITION;
|
float4 Pos : SV_POSITION;
|
||||||
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
[[vk::location(0)]] float2 UV : TEXCOORD0;
|
||||||
|
[[vk::location(1)]] float LodBias : FLOAT0;
|
||||||
|
[[vk::location(2)]] float3 Normal : NORMAL0;
|
||||||
|
[[vk::location(3)]] float3 ViewVec : VECTOR0;
|
||||||
|
[[vk::location(4)]] float3 LightVec : VECTOR1;
|
||||||
};
|
};
|
||||||
|
|
||||||
VSOutput main(VSInput input)
|
VSOutput main(VSInput input)
|
||||||
{
|
{
|
||||||
VSOutput output = (VSOutput) 0;
|
VSOutput output = (VSOutput) 0;
|
||||||
|
|
||||||
|
float3 vecPos = mul((float3x3) ubo.model, input.Pos.xyz).xyz;
|
||||||
|
float3 lightPos = mul((float3x3) ubo.model, (1.0).xxx);
|
||||||
|
|
||||||
output.UV = input.UV;
|
output.UV = input.UV;
|
||||||
|
output.LodBias = ubo.lodBias;
|
||||||
output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
|
output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
|
||||||
|
output.Normal = mul((float3x3) ubo.model, input.Normal);
|
||||||
|
output.LightVec = lightPos - vecPos;
|
||||||
|
output.ViewVec = ubo.viewPos.xyz - vecPos;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 320 es
|
||||||
/* Copyright (c) 2024-2025, Huawei Technologies Co., Ltd.
|
/* Copyright (c) 2019, Arm Limited and Contributors
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
layout(location = 0) in vec3 in_color;
|
layout(location = 0) in vec3 in_color;
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
@@ -23,4 +25,4 @@ layout(location = 0) out vec4 out_color;
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
out_color = vec4(in_color, 1.0);
|
out_color = vec4(in_color, 1.0);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 320 es
|
||||||
/* Copyright (c) 2023-2024, Mobica Limited
|
/* Copyright (c) 2019-2023, Arm Limited and Contributors
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -16,10 +16,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
layout(location = 0) out vec3 out_color;
|
layout(location = 0) out vec3 out_color;
|
||||||
|
|
||||||
vec2 triangle_positions[3] = vec2[](
|
vec2 triangle_positions[3] = vec2[](
|
||||||
vec2(0.0, -0.5),
|
vec2(0.5, -0.5),
|
||||||
vec2(0.5, 0.5),
|
vec2(0.5, 0.5),
|
||||||
vec2(-0.5, 0.5)
|
vec2(-0.5, 0.5)
|
||||||
);
|
);
|
||||||
@@ -32,6 +34,7 @@ vec3 triangle_colors[3] = vec3[](
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = vec4(triangle_positions[gl_VertexIndex], 0.0, 1.0);
|
gl_Position = vec4(triangle_positions[gl_VertexIndex], 0.5, 1.0);
|
||||||
|
|
||||||
out_color = triangle_colors[gl_VertexIndex];
|
out_color = triangle_colors[gl_VertexIndex];
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 450
|
||||||
/* Copyright (c) 2020-2024, Sascha Willems
|
/* Copyright (c) 2019, Sascha Willems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
layout (binding = 0) uniform sampler2D samplerColor0;
|
layout (binding = 0) uniform sampler2D fontSampler;
|
||||||
layout (binding = 1) uniform sampler2D samplerColor1;
|
|
||||||
|
|
||||||
layout (location = 0) in vec2 inUV;
|
layout (location = 0) in vec2 inUV;
|
||||||
|
layout (location = 1) in vec4 inColor;
|
||||||
|
|
||||||
layout (location = 0) out vec4 outColor;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
outColor = texture(samplerColor0, inUV);
|
outColor = inColor * texture(fontSampler, inUV);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#version 450
|
#version 450
|
||||||
/* Copyright (c) 2021-2024, Sascha Willems
|
/* Copyright (c) 2019, Sascha Willems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -16,21 +16,25 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
layout (location = 0) in vec3 inPos;
|
layout (location = 0) in vec2 inPos;
|
||||||
layout (location = 1) in vec2 inUV;
|
layout (location = 1) in vec2 inUV;
|
||||||
layout (location = 2) in vec3 inNormal;
|
layout (location = 2) in vec4 inColor;
|
||||||
|
|
||||||
layout (set = 0, binding = 0) uniform UBO
|
layout (push_constant) uniform PushConstants {
|
||||||
{
|
mat4 transform;
|
||||||
mat4 projection;
|
} pushConstants;
|
||||||
mat4 model;
|
|
||||||
vec4 viewPos;
|
|
||||||
} ubo;
|
|
||||||
|
|
||||||
layout (location = 0) out vec2 outUV;
|
layout (location = 0) out vec2 outUV;
|
||||||
|
layout (location = 1) out vec4 outColor;
|
||||||
|
|
||||||
void main()
|
out gl_PerVertex
|
||||||
|
{
|
||||||
|
vec4 gl_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main()
|
||||||
{
|
{
|
||||||
outUV = inUV;
|
outUV = inUV;
|
||||||
gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0);
|
outColor = inColor;
|
||||||
|
gl_Position = pushConstants.transform * vec4(inPos.xy, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
|
||||||
- Copyright (c) 2019-2024, Arm Limited and Contributors
|
|
||||||
-
|
|
||||||
- SPDX-License-Identifier: Apache-2.0
|
|
||||||
-
|
|
||||||
- Licensed under the Apache License, Version 2.0 the "License";
|
|
||||||
- you may not use this file except in compliance with the License.
|
|
||||||
- You may obtain a copy of the License at
|
|
||||||
-
|
|
||||||
- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
-
|
|
||||||
- Unless required by applicable law or agreed to in writing, software
|
|
||||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
- See the License for the specific language governing permissions and
|
|
||||||
- limitations under the License.
|
|
||||||
-
|
|
||||||
-->
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
@@ -28,12 +11,15 @@
|
|||||||
<!-- Declare permissions -->
|
<!-- Declare permissions -->
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<application android:label="@string/app_name"
|
<application android:label="@string/app_name"
|
||||||
android:debuggable="true"
|
android:debuggable="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
tools:ignore="GoogleAppIndexingWarning,HardcodedDebugMode">
|
tools:ignore="GoogleAppIndexingWarning,HardcodedDebugMode">
|
||||||
|
|
||||||
<activity android:name="com.khronos.vulkan_samples.MainActivity"
|
<activity android:name="com.khronos.vulkan_samples.MainActivity"
|
||||||
|
|||||||
@@ -0,0 +1,391 @@
|
|||||||
|
package com.khronos.vulkan_samples;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AssetsCopyUtil {
|
||||||
|
private static final String TAG = "AssetsCopyUtil";
|
||||||
|
private static final String PREF_NAME = "assets_copy_pref";
|
||||||
|
private static final String PREF_KEY_COPIED_FILES = "copied_files";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制 assets 到应用专属外部存储的 files 目录(递归复制子文件夹)
|
||||||
|
*/
|
||||||
|
public static void copyAssetsToAppFiles(Context context, String assetsPath) {
|
||||||
|
try {
|
||||||
|
AssetManager assetManager = context.getAssets();
|
||||||
|
|
||||||
|
// 获取应用专属外部存储的 files 目录
|
||||||
|
File externalFilesDir = context.getExternalFilesDir(null);
|
||||||
|
if (externalFilesDir == null) {
|
||||||
|
Log.e(TAG, "External files directory is not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归复制
|
||||||
|
copyAssetsRecursive(context, assetManager, assetsPath, externalFilesDir.getAbsolutePath());
|
||||||
|
|
||||||
|
Log.i(TAG, "Assets copy completed for: " + assetsPath);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error copying assets from: " + assetsPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归复制 assets 中的文件和文件夹
|
||||||
|
*/
|
||||||
|
private static void copyAssetsRecursive(Context context, AssetManager assetManager,
|
||||||
|
String assetsPath, String targetBasePath) {
|
||||||
|
try {
|
||||||
|
// 获取 assets 路径下的所有项目
|
||||||
|
String[] items = assetManager.list(assetsPath);
|
||||||
|
if (items == null || items.length == 0) {
|
||||||
|
Log.w(TAG, "No items found in assets path: " + assetsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建目标目录
|
||||||
|
File targetDir = new File(targetBasePath, assetsPath);
|
||||||
|
if (!targetDir.exists() && !targetDir.mkdirs()) {
|
||||||
|
Log.e(TAG, "Failed to create target directory: " + targetDir.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取已复制的文件列表
|
||||||
|
Set<String> copiedFiles = getCopiedFiles(context);
|
||||||
|
boolean hasNewFiles = false;
|
||||||
|
|
||||||
|
for (String item : items) {
|
||||||
|
String assetItemPath = assetsPath.isEmpty() ? item : assetsPath + "/" + item;
|
||||||
|
String fileKey = assetItemPath;
|
||||||
|
|
||||||
|
// 检查是否已经复制过
|
||||||
|
if (copiedFiles.contains(fileKey)) {
|
||||||
|
Log.d(TAG, "Item already copied: " + assetItemPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 判断是文件还是目录的正确方法
|
||||||
|
boolean isFile = isAssetFile(assetManager, assetsPath, item);
|
||||||
|
|
||||||
|
if (isFile) {
|
||||||
|
// 复制文件
|
||||||
|
if (copySingleFile(assetManager, assetItemPath, targetDir, item)) {
|
||||||
|
copiedFiles.add(fileKey);
|
||||||
|
hasNewFiles = true;
|
||||||
|
Log.d(TAG, "Successfully copied file: " + assetItemPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 递归复制子目录
|
||||||
|
copyAssetsRecursive(context, assetManager, assetItemPath, targetBasePath);
|
||||||
|
// 将目录也标记为已处理
|
||||||
|
copiedFiles.add(fileKey);
|
||||||
|
hasNewFiles = true;
|
||||||
|
Log.d(TAG, "Processed directory: " + assetItemPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error processing: " + assetItemPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有新文件被复制,更新记录
|
||||||
|
if (hasNewFiles) {
|
||||||
|
saveCopiedFiles(context, copiedFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in recursive copy for path: " + assetsPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正确判断 assets 中的项目是文件还是目录
|
||||||
|
*/
|
||||||
|
private static boolean isAssetFile(AssetManager assetManager, String basePath, String item) {
|
||||||
|
try {
|
||||||
|
// 方法1:尝试列出子项,如果能列出且不为空,说明是目录
|
||||||
|
String testPath = basePath.isEmpty() ? item : basePath + "/" + item;
|
||||||
|
String[] subItems = assetManager.list(testPath);
|
||||||
|
|
||||||
|
// 如果子项为空,说明是文件或者是空目录
|
||||||
|
if (subItems == null) {
|
||||||
|
return true; // 应该是文件
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有子项,说明是目录
|
||||||
|
if (subItems.length > 0) {
|
||||||
|
return false; // 是目录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果子项为空数组,需要进一步判断
|
||||||
|
// 尝试打开它,如果能打开说明是文件,不能打开说明是空目录
|
||||||
|
try {
|
||||||
|
InputStream test = assetManager.open(testPath);
|
||||||
|
test.close();
|
||||||
|
return true; // 能打开,是文件
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false; // 不能打开,是空目录
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error checking asset type: " + item, e);
|
||||||
|
return true; // 默认当作文件处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更可靠的递归复制方法
|
||||||
|
*/
|
||||||
|
public static void copyAssetsToAppFilesSimple(Context context, String assetsPath) {
|
||||||
|
try {
|
||||||
|
AssetManager assetManager = context.getAssets();
|
||||||
|
File externalFilesDir = context.getExternalFilesDir(null);
|
||||||
|
if (externalFilesDir == null) {
|
||||||
|
Log.e(TAG, "External storage not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建目标目录
|
||||||
|
File targetBaseDir = new File(externalFilesDir, assetsPath);
|
||||||
|
if (!targetBaseDir.exists() && !targetBaseDir.mkdirs()) {
|
||||||
|
Log.e(TAG, "Failed to create base directory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copyAssetsRecursiveSimple(assetManager, assetsPath, targetBaseDir.getAbsolutePath());
|
||||||
|
Log.i(TAG, "Simple copy completed for: " + assetsPath);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in simple copy", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyAssetsRecursiveSimple(AssetManager assetManager, String assetsPath, String targetPath) {
|
||||||
|
try {
|
||||||
|
String[] items = assetManager.list(assetsPath);
|
||||||
|
if (items == null || items.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String item : items) {
|
||||||
|
String fullAssetPath = assetsPath.isEmpty() ? item : assetsPath + "/" + item;
|
||||||
|
|
||||||
|
// 判断是文件还是目录
|
||||||
|
boolean isFile = isAssetFileSimple(assetManager, fullAssetPath);
|
||||||
|
|
||||||
|
if (isFile) {
|
||||||
|
// 复制文件
|
||||||
|
copySingleFileSimple(assetManager, fullAssetPath, targetPath, item);
|
||||||
|
Log.d(TAG, "Copied file: " + fullAssetPath + " to " + targetPath);
|
||||||
|
} else {
|
||||||
|
// 创建子目录并递归复制
|
||||||
|
File subDir = new File(targetPath, item);
|
||||||
|
if (!subDir.exists()) {
|
||||||
|
subDir.mkdirs();
|
||||||
|
}
|
||||||
|
copyAssetsRecursiveSimple(assetManager, fullAssetPath, subDir.getAbsolutePath());
|
||||||
|
Log.d(TAG, "Processed directory: " + fullAssetPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in simple recursive copy: " + assetsPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAssetFileSimple(AssetManager assetManager, String path) {
|
||||||
|
try {
|
||||||
|
String[] subItems = assetManager.list(path);
|
||||||
|
if (subItems == null) return true; // 应该是文件
|
||||||
|
|
||||||
|
if (subItems.length > 0) return false; // 有子项,是目录
|
||||||
|
|
||||||
|
// 空数组,尝试打开判断
|
||||||
|
try {
|
||||||
|
InputStream test = assetManager.open(path);
|
||||||
|
test.close();
|
||||||
|
return true; // 能打开,是文件
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false; // 不能打开,是空目录
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return true; // 出错时默认当作文件
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制单个文件
|
||||||
|
*/
|
||||||
|
private static boolean copySingleFile(AssetManager assetManager, String assetFilePath, File targetDir, String filename) {
|
||||||
|
InputStream in = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
File outFile = new File(targetDir, filename);
|
||||||
|
in = assetManager.open(assetFilePath);
|
||||||
|
out = new FileOutputStream(outFile);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read;
|
||||||
|
while ((read = in.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "File copied: " + outFile.getAbsolutePath());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to copy file: " + assetFilePath, e);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (in != null) in.close();
|
||||||
|
if (out != null) {
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error closing streams", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copySingleFileSimple(AssetManager assetManager, String assetFilePath,
|
||||||
|
String targetPath, String filename) {
|
||||||
|
InputStream in = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
File outFile = new File(targetPath, filename);
|
||||||
|
in = assetManager.open(assetFilePath);
|
||||||
|
out = new FileOutputStream(outFile);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read;
|
||||||
|
while ((read = in.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error copying: " + assetFilePath, e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (in != null) in.close();
|
||||||
|
if (out != null) {
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error closing streams", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调试方法:打印 assets 结构
|
||||||
|
*/
|
||||||
|
public static void printAssetsStructure(Context context, String path) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "=== Assets Structure for: " + path + " ===");
|
||||||
|
AssetManager am = context.getAssets();
|
||||||
|
printAssetsRecursive(am, path, 0);
|
||||||
|
Log.d(TAG, "=== End of Assets Structure ===");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error printing assets structure", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printAssetsRecursive(AssetManager am, String path, int depth) {
|
||||||
|
try {
|
||||||
|
String indent = "";
|
||||||
|
for (int i = 0; i < depth; i++) indent += " ";
|
||||||
|
|
||||||
|
String[] items = am.list(path);
|
||||||
|
if (items != null) {
|
||||||
|
for (String item : items) {
|
||||||
|
String fullPath = path.isEmpty() ? item : path + "/" + item;
|
||||||
|
boolean isFile = isAssetFileSimple(am, fullPath);
|
||||||
|
|
||||||
|
if (isFile) {
|
||||||
|
Log.d(TAG, indent + "📄 " + item + " (file)");
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, indent + "📁 " + item + " (dir)");
|
||||||
|
printAssetsRecursive(am, fullPath, depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in recursive print", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取已复制的文件列表
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Set<String> getCopiedFiles(Context context) {
|
||||||
|
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
|
.getStringSet(PREF_KEY_COPIED_FILES, new HashSet<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存已复制的文件列表
|
||||||
|
*/
|
||||||
|
private static void saveCopiedFiles(Context context, Set<String> copiedFiles) {
|
||||||
|
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
|
.edit()
|
||||||
|
.putStringSet(PREF_KEY_COPIED_FILES, new HashSet<>(copiedFiles))
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空复制记录
|
||||||
|
*/
|
||||||
|
public static void clearCopyRecords(Context context) {
|
||||||
|
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
|
.edit()
|
||||||
|
.remove(PREF_KEY_COPIED_FILES)
|
||||||
|
.apply();
|
||||||
|
Log.d(TAG, "Copy records cleared");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查外部存储是否可用
|
||||||
|
*/
|
||||||
|
public static boolean isExternalStorageAvailable() {
|
||||||
|
String state = Environment.getExternalStorageState();
|
||||||
|
return Environment.MEDIA_MOUNTED.equals(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目标文件的完整路径
|
||||||
|
*/
|
||||||
|
public static String getFilePath(Context context, String relativePath) {
|
||||||
|
File externalFilesDir = context.getExternalFilesDir(null);
|
||||||
|
if (externalFilesDir == null) return null;
|
||||||
|
|
||||||
|
File targetFile = new File(externalFilesDir, relativePath);
|
||||||
|
return targetFile.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查文件是否存在
|
||||||
|
*/
|
||||||
|
public static boolean fileExists(Context context, String relativePath) {
|
||||||
|
File externalFilesDir = context.getExternalFilesDir(null);
|
||||||
|
if (externalFilesDir == null) return false;
|
||||||
|
|
||||||
|
File targetFile = new File(externalFilesDir, relativePath);
|
||||||
|
return targetFile.exists();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package com.khronos.vulkan_samples;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class CameraDataFetcher {
|
||||||
|
|
||||||
|
public interface CameraDataCallback {
|
||||||
|
void onSuccess(CameraData data);
|
||||||
|
void onError(String errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据模型类
|
||||||
|
public static class CameraData {
|
||||||
|
public float fov = 47;
|
||||||
|
public float x = -0.5f;
|
||||||
|
public float y = -0.51f;
|
||||||
|
public float z;
|
||||||
|
public float sx = 1;
|
||||||
|
public float sy = 1;
|
||||||
|
public float sz = 1;
|
||||||
|
public float rotx;
|
||||||
|
public float roty;
|
||||||
|
public float rotz;
|
||||||
|
public float camx;
|
||||||
|
public float camy;
|
||||||
|
public float camz;
|
||||||
|
public float z_rate = -1;
|
||||||
|
public float dashSize = 5;
|
||||||
|
public float gapSize = 3;
|
||||||
|
public float dashOffset = 0;
|
||||||
|
public float uAASize = 1.5f;
|
||||||
|
|
||||||
|
// 从JSONObject解析数据
|
||||||
|
public static CameraData fromJson(JSONObject json) {
|
||||||
|
CameraData data = new CameraData();
|
||||||
|
try {
|
||||||
|
data.fov = (float) json.getDouble("fov");
|
||||||
|
data.x = (float)json.getDouble("x");
|
||||||
|
data.y = (float)json.getDouble("y");
|
||||||
|
data.z = (float)json.getDouble("z");
|
||||||
|
data.sx = (float)json.getDouble("sx");
|
||||||
|
data.sy = (float)json.getDouble("sy");
|
||||||
|
data.sz = (float)json.getDouble("sz");
|
||||||
|
data.rotx = (float)json.getDouble("rotx");
|
||||||
|
data.roty = (float)json.getDouble("roty");
|
||||||
|
data.rotz = (float)json.getDouble("rotz");
|
||||||
|
data.camx = (float)json.getDouble("camx");
|
||||||
|
data.camy = (float)json.getDouble("camy");
|
||||||
|
data.camz = (float)json.getDouble("camz");
|
||||||
|
data.z_rate = (float)json.getDouble("z_rate");
|
||||||
|
data.dashSize = (float)json.getDouble("dashSize");
|
||||||
|
data.gapSize = (float)json.getDouble("gapSize");
|
||||||
|
data.dashOffset = (float)json.getDouble("dashOffset");
|
||||||
|
data.uAASize = (float)json.getDouble("uAASize");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("CameraData", "解析JSON失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"CameraData{fov=%.2f, x=%.2f, y=%.2f, z=%.2f," +
|
||||||
|
"rotx=%.2f, roty=%.2f, rotz=%.2f, camx=%.2f, camy=%.2f, camz=%.2f}",
|
||||||
|
fov, x, y, z, rotx, roty, rotz, camx, camy, camz
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步获取相机数据
|
||||||
|
* @param apiUrl 接口URL
|
||||||
|
* @param callback 回调接口
|
||||||
|
*/
|
||||||
|
public static void fetchCameraData(String apiUrl, CameraDataCallback callback) {
|
||||||
|
new FetchCameraDataTask(callback).execute(apiUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步任务类
|
||||||
|
private static class FetchCameraDataTask extends AsyncTask<String, Void, CameraData> {
|
||||||
|
private CameraDataCallback callback;
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
public FetchCameraDataTask(CameraDataCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CameraData doInBackground(String... urls) {
|
||||||
|
if (urls.length == 0) {
|
||||||
|
errorMessage = "URL不能为空";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String apiUrl = urls[0];
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
BufferedReader reader = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(apiUrl);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setConnectTimeout(10000); // 10秒连接超时
|
||||||
|
connection.setReadTimeout(10000); // 10秒读取超时
|
||||||
|
connection.setRequestProperty("Accept", "application/json");
|
||||||
|
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
InputStream inputStream = connection.getInputStream();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
response.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObject = new JSONObject(response.toString());
|
||||||
|
return CameraData.fromJson(jsonObject);
|
||||||
|
} else {
|
||||||
|
errorMessage = "HTTP请求失败,响应码: " + responseCode;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
errorMessage = "获取相机数据时发生错误: " + e.getMessage();
|
||||||
|
Log.e("CameraDataFetcher", errorMessage, e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("CameraDataFetcher", "关闭流时出错", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(CameraData result) {
|
||||||
|
if (callback != null) {
|
||||||
|
if (result != null) {
|
||||||
|
callback.onSuccess(result);
|
||||||
|
} else {
|
||||||
|
callback.onError(errorMessage != null ? errorMessage : "未知错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.mediapipe.examples.facelandmarker
|
package com.khronos.vulkan_samples
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
@@ -176,7 +176,7 @@ class FaceLandmarkerHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val rotatedBitmap = Bitmap.createBitmap(
|
val rotatedBitmap = Bitmap.createBitmap(
|
||||||
bitmapBuffer, 0, 0, bitmapBuffer.width, bitmapBuffer.height,
|
bitmapBuffer, (640-480)/2, 0, bitmapBuffer.height, bitmapBuffer.height,
|
||||||
matrix, true
|
matrix, true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,61 +3,44 @@ package com.khronos.vulkan_samples;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.graphics.SurfaceTexture;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.WindowManager;
|
||||||
import android.view.SurfaceView;
|
|
||||||
import android.view.TextureView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.camera.core.AspectRatio;
|
||||||
import androidx.camera.core.CameraSelector;
|
import androidx.camera.core.CameraSelector;
|
||||||
import androidx.camera.core.Preview;
|
import androidx.camera.core.ImageAnalysis;
|
||||||
import androidx.camera.core.SurfaceRequest;
|
import androidx.camera.core.ImageProxy;
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import com.google.androidgamesdk.GameActivity;
|
import com.google.androidgamesdk.GameActivity;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.mediapipe.tasks.components.containers.NormalizedLandmark;
|
||||||
|
import com.google.mediapipe.tasks.vision.core.RunningMode;
|
||||||
|
import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker;
|
||||||
|
import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarkerResult;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class MainActivity extends GameActivity {
|
public class MainActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener, CameraDataFetcher.CameraDataCallback {
|
||||||
private TextureView textureView; // 使用 TextureView 替代 PreviewView
|
|
||||||
private ProcessCameraProvider cameraProvider;
|
private ProcessCameraProvider cameraProvider;
|
||||||
private FrameLayout containerLayout;
|
|
||||||
private void initCamera(){
|
private void initCamera(){
|
||||||
// 获取 GameActivity 的根视图
|
backgroundExecutor = Executors.newSingleThreadExecutor();
|
||||||
ViewGroup rootView = (ViewGroup) getWindow().getDecorView();
|
|
||||||
|
|
||||||
// 创建容器布局
|
|
||||||
containerLayout = new FrameLayout(this);
|
|
||||||
containerLayout.setLayoutParams(new ViewGroup.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
));
|
|
||||||
|
|
||||||
// 创建 TextureView 用于摄像头预览
|
|
||||||
textureView = new TextureView(this);
|
|
||||||
textureView.setLayoutParams(new ViewGroup.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
));
|
|
||||||
|
|
||||||
// 将 TextureView 添加到容器
|
|
||||||
containerLayout.addView(textureView);
|
|
||||||
|
|
||||||
// 将容器添加到根视图的底部(作为背景)
|
|
||||||
//rootView.addView(containerLayout); // 添加到索引0(最底层)
|
|
||||||
rootView.addView(containerLayout, 0);
|
|
||||||
|
|
||||||
|
|
||||||
if (hasCameraPermission()) {
|
if (hasCameraPermission()) {
|
||||||
startCamera();
|
startCamera();
|
||||||
} else {
|
} else {
|
||||||
@@ -65,9 +48,28 @@ public class MainActivity extends GameActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void detectFace(ImageProxy imageProxy) {
|
||||||
|
faceLandmarkerHelper.detectLiveStream(
|
||||||
|
imageProxy,false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
private Runnable cameraDataRunnable;
|
||||||
|
private static final long INTERVAL = 1000; // 5秒间隔
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
// if (!AssetsCopyUtil.isExternalStorageAvailable()) {
|
||||||
|
// Log.w(TAG, "External storage not available, skipping assets copy");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
AssetsCopyUtil.copyAssetsToAppFiles(this, "assets");
|
||||||
|
AssetsCopyUtil.copyAssetsToAppFiles(this, "shaders");
|
||||||
|
|
||||||
|
|
||||||
String native_lib_name = getResources().getString(R.string.native_lib_name);
|
String native_lib_name = getResources().getString(R.string.native_lib_name);
|
||||||
try {
|
try {
|
||||||
System.loadLibrary(native_lib_name);
|
System.loadLibrary(native_lib_name);
|
||||||
@@ -76,15 +78,70 @@ public class MainActivity extends GameActivity {
|
|||||||
}
|
}
|
||||||
String[] argArray = new String[2];
|
String[] argArray = new String[2];
|
||||||
argArray[0] = "sample";
|
argArray[0] = "sample";
|
||||||
argArray[1] = "hello_triangle";
|
argArray[1] = "texture_loading";//"hello_triangle";
|
||||||
sendArgumentsToPlatform(argArray);
|
sendArgumentsToPlatform(argArray);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// 隐藏状态栏
|
||||||
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||||
|
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
|
||||||
initCamera();
|
initCamera();
|
||||||
|
|
||||||
|
backgroundExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
faceLandmarkerHelper = new FaceLandmarkerHelper(
|
||||||
|
0.5f,
|
||||||
|
0.5f,
|
||||||
|
0.5f,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
RunningMode.LIVE_STREAM,
|
||||||
|
MainActivity.this,
|
||||||
|
MainActivity.this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化Runnable
|
||||||
|
cameraDataRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
fetchCameraData();
|
||||||
|
handler.postDelayed(this, INTERVAL); // 再次调度
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始周期性调用
|
||||||
|
startPeriodicFetching();
|
||||||
|
|
||||||
|
|
||||||
Log.i("MainActivity", "onCreate: ");
|
Log.i("MainActivity", "onCreate: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canFetch = true;
|
||||||
|
private void fetchCameraData() {
|
||||||
|
if(canFetch)
|
||||||
|
{
|
||||||
|
CameraDataFetcher.fetchCameraData("http://175.178.100.240:5000/data", MainActivity.this);
|
||||||
|
canFetch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void startPeriodicFetching() {
|
||||||
|
handler.postDelayed(cameraDataRunnable, INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPeriodicFetching() {
|
||||||
|
handler.removeCallbacks(cameraDataRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
stopPeriodicFetching(); // 避免内存泄漏
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasCameraPermission() {
|
private boolean hasCameraPermission() {
|
||||||
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||||
== PackageManager.PERMISSION_GRANTED;
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
@@ -97,6 +154,9 @@ public class MainActivity extends GameActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final int REQUEST_CAMERA_PERMISSION = 1001;
|
private static final int REQUEST_CAMERA_PERMISSION = 1001;
|
||||||
|
ImageAnalysis imageAnalyzer;
|
||||||
|
ExecutorService backgroundExecutor;
|
||||||
|
FaceLandmarkerHelper faceLandmarkerHelper;
|
||||||
|
|
||||||
private void startCamera() {
|
private void startCamera() {
|
||||||
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
|
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
|
||||||
@@ -106,26 +166,33 @@ public class MainActivity extends GameActivity {
|
|||||||
try {
|
try {
|
||||||
cameraProvider = cameraProviderFuture.get();
|
cameraProvider = cameraProviderFuture.get();
|
||||||
|
|
||||||
Preview preview = new Preview.Builder().build();
|
|
||||||
|
|
||||||
CameraSelector cameraSelector = new CameraSelector.Builder()
|
CameraSelector cameraSelector = new CameraSelector.Builder()
|
||||||
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
|
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// 使用 TextureView 的 SurfaceTexture
|
imageAnalyzer = new ImageAnalysis.Builder()
|
||||||
SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
|
.setTargetAspectRatio(AspectRatio.RATIO_4_3)
|
||||||
if (surfaceTexture != null) {
|
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||||
Surface surface = new Surface(surfaceTexture);
|
.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
|
||||||
preview.setSurfaceProvider(new Preview.SurfaceProvider() {
|
.build();
|
||||||
@Override
|
|
||||||
public void onSurfaceRequested(@NonNull SurfaceRequest request) {
|
|
||||||
request.provideSurface(surface, ContextCompat.getMainExecutor(MainActivity.this),
|
|
||||||
result -> {});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cameraProvider.bindToLifecycle(this, cameraSelector, preview);
|
|
||||||
|
imageAnalyzer.setAnalyzer(backgroundExecutor, new ImageAnalysis.Analyzer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void analyze(@NonNull ImageProxy image) {
|
||||||
|
try {
|
||||||
|
//Log.d("Camera", "Received image: " + image.getWidth() + "x" + image.getHeight());
|
||||||
|
processImageForVulkan(image);
|
||||||
|
detectFace(image);
|
||||||
|
} finally {
|
||||||
|
//image.close(); // 确保在这里关闭
|
||||||
|
//Log.d("Camera", "Image closed, ready for next frame");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cameraProvider.bindToLifecycle(this, cameraSelector, imageAnalyzer);
|
||||||
|
|
||||||
} catch (ExecutionException | InterruptedException e) {
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
Log.e("MainActivity", "Error starting camera: " + e.getMessage());
|
Log.e("MainActivity", "Error starting camera: " + e.getMessage());
|
||||||
@@ -134,6 +201,34 @@ public class MainActivity extends GameActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void processImageForVulkan(ImageProxy image) {
|
||||||
|
// 获取图像信息
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
int format = image.getFormat();
|
||||||
|
|
||||||
|
// 获取图像数据平面
|
||||||
|
ImageProxy.PlaneProxy[] planes = image.getPlanes();
|
||||||
|
|
||||||
|
// 对于 RGBA_8888 格式,通常只有一个平面
|
||||||
|
if (planes.length > 0) {
|
||||||
|
ImageProxy.PlaneProxy plane = planes[0];
|
||||||
|
ByteBuffer buffer = plane.getBuffer();
|
||||||
|
int rowStride = plane.getRowStride();
|
||||||
|
int pixelStride = plane.getPixelStride();
|
||||||
|
|
||||||
|
// 调用 Native 方法处理图像
|
||||||
|
processImageNative(buffer, width, height, format,
|
||||||
|
rowStride, pixelStride, image.getImageInfo().getRotationDegrees());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native 方法
|
||||||
|
private native void processImageNative(ByteBuffer buffer, int width, int height,
|
||||||
|
int format, int rowStride, int pixelStride,
|
||||||
|
int rotation);
|
||||||
|
|
||||||
|
|
||||||
private static final int REQUEST_CODE_PERMISSIONS = 1001;
|
private static final int REQUEST_CODE_PERMISSIONS = 1001;
|
||||||
private static final String[] REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA};
|
private static final String[] REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA};
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
@@ -161,4 +256,133 @@ public class MainActivity extends GameActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private native void sendArgumentsToPlatform(String[] args);
|
private native void sendArgumentsToPlatform(String[] args);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NotNull String error, int errorCode) {
|
||||||
|
Log.e(TAG, "onError: Face Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteBuffer nativeBuffer = null;
|
||||||
|
float[] points = new float[480 * 3];
|
||||||
|
|
||||||
|
|
||||||
|
public class Vector {
|
||||||
|
public float x, y, z;
|
||||||
|
|
||||||
|
public Vector(float x, float y, float z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toObjString(ArrayList<Vector> vertices, ArrayList<Integer> triangleIndices) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
// 写入顶点数据 (v x y z)
|
||||||
|
for (Vector v : vertices) {
|
||||||
|
sb.append(String.format("v %.6f %.6f %.6f\n", v.x, v.y, v.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入面数据 (f i1 i2 i3),OBJ索引从1开始,因此每个索引+1
|
||||||
|
int size = triangleIndices.size();
|
||||||
|
for (int i = 0; i < size; i += 3) {
|
||||||
|
if (i + 2 < size) {
|
||||||
|
int i1 = triangleIndices.get(i) + 1;
|
||||||
|
int i2 = triangleIndices.get(i + 1) + 1;
|
||||||
|
int i3 = triangleIndices.get(i + 2) + 1;
|
||||||
|
sb.append(String.format("f %d %d %d\n", i1, i2, i3));
|
||||||
|
} else {
|
||||||
|
// 如果剩余索引不足3个,说明数据不完整
|
||||||
|
System.err.println("Warning: Incomplete triangle face at the end of index list.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResults(FaceLandmarkerHelper.@NotNull ResultBundle resultBundle) {
|
||||||
|
FaceLandmarkerResult faceLandmarkerResult = resultBundle.getResult();
|
||||||
|
int height = resultBundle.getInputImageHeight();
|
||||||
|
int width = resultBundle.getInputImageWidth();
|
||||||
|
int bufferSize = 480 * 3 * 4;
|
||||||
|
|
||||||
|
if(nativeBuffer == null)
|
||||||
|
{
|
||||||
|
// 创建直接ByteBuffer(在native内存中)
|
||||||
|
nativeBuffer = ByteBuffer.allocateDirect(bufferSize);
|
||||||
|
nativeBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ArrayList<Vector> vertexs = new ArrayList<>();
|
||||||
|
// ArrayList<Integer> triangle_index = new ArrayList<>();
|
||||||
|
//
|
||||||
|
// for (var conn : FaceLandmarker.FACE_LANDMARKS_TESSELATION) {
|
||||||
|
// triangle_index.add(conn.start());
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// StringBuilder sb = new StringBuilder();
|
||||||
|
// sb.append("[");
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
// Iterate through each detected face
|
||||||
|
for (List<NormalizedLandmark> faceLandmarks : faceLandmarkerResult.faceLandmarks()) {
|
||||||
|
//should be 1
|
||||||
|
|
||||||
|
int arrayIndex = 0;
|
||||||
|
for (NormalizedLandmark p : faceLandmarks)
|
||||||
|
{
|
||||||
|
//sb.append("[");
|
||||||
|
//Log.i(TAG, "Index" + index + " x:"+p.x() + " y:"+p.y() + " z:"+p.z());
|
||||||
|
points[arrayIndex++] = p.x();
|
||||||
|
//sb.append(""+p.x()+",");
|
||||||
|
points[arrayIndex++] = p.y();
|
||||||
|
//sb.append(""+p.y()+",");
|
||||||
|
points[arrayIndex++] = p.z() * z_rate;
|
||||||
|
//sb.append(""+p.z());
|
||||||
|
//vertexs.add(new Vector(p.x(), p.y(), p.z()));
|
||||||
|
//sb.append("],");
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//sb.append("]");
|
||||||
|
//String objStr = sb.toString();
|
||||||
|
|
||||||
|
//String objStr = toObjString(vertexs, triangle_index);
|
||||||
|
|
||||||
|
// 转换为FloatBuffer并填充数据
|
||||||
|
FloatBuffer floatBuffer = nativeBuffer.asFloatBuffer();
|
||||||
|
floatBuffer.put(points);
|
||||||
|
floatBuffer.position(0);
|
||||||
|
passDataToNative(nativeBuffer, index, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float z_rate = -1.0f;
|
||||||
|
|
||||||
|
public native void passDataToNative(ByteBuffer buffer, int pointCount, int width, int height);
|
||||||
|
public native void upDateCameraData(float fov, float x, float y, float z, float sx, float sy, float sz, float rotx, float roty, float rotz,
|
||||||
|
float camx, float camy, float camz, float dashSize, float gapSize, float dashOffset, float uAASize);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(CameraDataFetcher.CameraData data) {
|
||||||
|
z_rate = data.z_rate;
|
||||||
|
upDateCameraData(data.fov, data.x, data.y, data.z, data.sx, data.sy, data.sz,
|
||||||
|
data.rotx, data.roty, data.rotz,
|
||||||
|
data.camx, data.camy, data.camz,
|
||||||
|
data.dashSize, data.gapSize, data.dashOffset, data.uAASize
|
||||||
|
);
|
||||||
|
canFetch = true;
|
||||||
|
Log.e(TAG, "GetCameraData " + data.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(String errorMessage) {
|
||||||
|
Log.e(TAG, "GetCameraData Error");
|
||||||
|
canFetch = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 157 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<!-- 底层:CameraX 预览 -->
|
||||||
|
<androidx.camera.view.PreviewView
|
||||||
|
android:id="@+id/previewView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<!-- 上层:GameActivity 的容器 -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/gameActivityContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 36 KiB |
@@ -1,24 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
|
||||||
- Copyright (c) 2019-2023, Arm Limited and Contributors
|
|
||||||
-
|
|
||||||
- SPDX-License-Identifier: Apache-2.0
|
|
||||||
-
|
|
||||||
- Licensed under the Apache License, Version 2.0 the "License";
|
|
||||||
- you may not use this file except in compliance with the License.
|
|
||||||
- You may obtain a copy of the License at
|
|
||||||
-
|
|
||||||
- http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
-
|
|
||||||
- Unless required by applicable law or agreed to in writing, software
|
|
||||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
- See the License for the specific language governing permissions and
|
|
||||||
- limitations under the License.
|
|
||||||
-
|
|
||||||
-->
|
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Vulkan Samples</string>
|
<string name="app_name">inewme</string>
|
||||||
<string name="channel_name">vkb_channel</string>
|
<string name="channel_name">vkb_channel</string>
|
||||||
<string name="channel_desc">vkb_channel is a channel for the vulkan best practice application notifications</string>
|
<string name="channel_desc">vkb_channel is a channel for the vulkan best practice application notifications</string>
|
||||||
<string name="native_lib_name">vulkan_samples</string>
|
<string name="native_lib_name">vulkan_samples</string>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<base-config cleartextTrafficPermitted="true">
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
<!-- 如果需要兼容非常旧的Android版本(API 23及以下),可以加上 user -->
|
||||||
|
<!-- <certificates src="user" /> -->
|
||||||
|
</trust-anchors>
|
||||||
|
</base-config>
|
||||||
|
</network-security-config>
|
||||||