50 Commits
Author SHA1 Message Date
xsl f64e345e9b 发版本 2025-09-29 23:42:16 +08:00
xsl 2e83be8414 发版本 2025-09-29 23:41:51 +08:00
xsl e7b5f24cf7 发版本了v2 2025-09-29 23:40:22 +08:00
xsl f4665a4c9f 放到android 包里面 2025-09-29 23:23:16 +08:00
xsl 72f21a21af 放到android 包里面 2025-09-29 23:22:34 +08:00
xsl f677d522b4 更新纹理 2025-09-29 23:07:41 +08:00
xsl 13d3372fc4 打包通过 2025-09-29 22:53:48 +08:00
xsl 55b9c00292 覆盖input 函数 2025-09-29 18:02:56 +08:00
xsl 7b41c64a59 添加新模型 2025-09-29 17:48:07 +08:00
xsl bf43130c0d 添加点 2025-09-29 16:18:16 +08:00
xsl 65c561c440 完成 2025-09-28 22:20:46 +08:00
xsl d6818e8816 完成 2025-09-28 22:20:28 +08:00
xsl cbe0056ab2 完成 2025-09-28 22:20:13 +08:00
xsl 9aa28ca830 windows 复现问题。 2025-09-28 21:29:27 +08:00
xsl db128c8f49 windows 复现问题。 2025-09-28 21:29:11 +08:00
xsl 3e33975e2a 添加顶点延长。 2025-09-28 18:20:50 +08:00
xsl 86889c334e 完成UV对齐 2025-09-28 17:18:58 +08:00
xsl 0db09f12c3 完成UV对齐 2025-09-28 17:18:37 +08:00
xsl 481bdefa74 asdf 2025-09-27 23:17:38 +08:00
xsl 41adba285d asdf 2025-09-27 23:17:21 +08:00
xsl 3f7faff423 asdf 2025-09-27 22:17:10 +08:00
xsl 4721726618 asdf 2025-09-27 22:16:53 +08:00
xsl aa9a524c33 asdf 2025-09-27 21:37:26 +08:00
xsl 1d1a1a4907 asdf 2025-09-27 21:27:53 +08:00
xsl 58f8c42b04 阿斯蒂芬 2025-09-27 20:58:57 +08:00
xsl 701187ec11 加入所有顶点 2025-09-27 20:05:03 +08:00
xsl cb7b600eda 查找相同的顶点 2025-09-27 18:44:23 +08:00
xsl e7834d7032 asdf 2025-09-27 11:45:32 +08:00
xsl f7fd225bc6 阿斯蒂芬 2025-09-27 11:44:43 +08:00
xsl dfb973bed0 android 设备上跑通透明 2025-09-26 21:52:54 +08:00
xsl 326593eb4f 完成透明的渲染 2025-09-26 18:21:06 +08:00
xsl 57ac3a674c 调整图片大小 2025-09-26 15:21:16 +08:00
xsl db5fb1e04a add assets 2025-09-26 15:20:20 +08:00
xsl c17ac7e6b5 推送常量完成。 2025-09-26 15:10:10 +08:00
xsl 3c0dda0e28 推送常量完成。 2025-09-26 15:09:51 +08:00
xsl 7d3427e4c0 添加法线 2025-09-26 12:21:54 +08:00
xsl 75c20ecfed utf-8 编码 2025-09-26 10:56:17 +08:00
xsl 5455da4a57 加入顶点注释和面注释 2025-09-26 10:51:12 +08:00
xsl 67404122fb 阿斯蒂芬 2025-09-25 22:36:32 +08:00
xsl 1a621bd5bf 阿斯蒂芬 2025-09-25 22:35:41 +08:00
xsl 8d195515c3 python 生成模型 2025-09-25 22:34:34 +08:00
xsl a9239fc39f 点和线 2025-09-25 21:51:58 +08:00
xsl 8dc5aab8fe 完成背景的推送 2025-09-24 23:23:39 +08:00
xsl c711a90592 完成背景的推送。 2025-09-24 23:23:16 +08:00
xsl 41081bf62d 正交投影完成 2025-09-24 22:20:45 +08:00
xsl acd9eea405 正交投影完成 2025-09-24 22:20:22 +08:00
xsl a112cecfbf 正交投影完成 2025-09-24 22:20:07 +08:00
xsl ceba7f90ac 添加复制 2025-09-23 20:04:23 +08:00
xsl 7ff02db939 添加复制 2025-09-23 20:04:09 +08:00
xsl 599e041732 添加复制的资源 2025-09-23 20:03:06 +08:00
130 changed files with 80304 additions and 551 deletions
+3 -3
View File
@@ -21,9 +21,9 @@ android {
externalNativeBuild {
cmake {
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', "-DCMAKE_BUILD_TYPE=Release"
cppFlags "-DRELEASE_MODE"
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"
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -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
]
}
]
}
Binary file not shown.

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]
@@ -0,0 +1,89 @@
#version 320 es
/* Copyright (c) 2019-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.
*/
precision highp float;
layout(set = 0, binding = 0) uniform sampler2D base_color_texture;
layout(location = 0) in vec4 in_pos;
layout(location = 1) in vec2 in_uv;
layout(location = 2) in vec3 in_normal;
layout(location = 0) out vec4 o_color;
layout(set = 0, binding = 1) uniform GlobalUniform
{
mat4 model;
mat4 view_proj;
vec3 camera_position;
}
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"
layout(set = 0, binding = 4) uniform LightsInfo
{
Light directional_lights[48];
Light point_lights[48];
Light spot_lights[48];
}
lights_info;
layout(constant_id = 0) const uint DIRECTIONAL_LIGHT_COUNT = 0U;
layout(constant_id = 1) const uint POINT_LIGHT_COUNT = 0U;
layout(constant_id = 2) const uint SPOT_LIGHT_COUNT = 0U;
void main(void)
{
vec3 normal = normalize(in_normal);
vec3 light_contribution = vec3(0.0);
for (uint i = 0U; i < DIRECTIONAL_LIGHT_COUNT; ++i)
{
light_contribution += apply_directional_light(lights_info.directional_lights[i], normal);
}
for (uint i = 0U; i < POINT_LIGHT_COUNT; ++i)
{
light_contribution += apply_point_light(lights_info.point_lights[i], in_pos.xyz, normal);
}
for (uint i = 0U; i < SPOT_LIGHT_COUNT; ++i)
{
light_contribution += apply_spot_light(lights_info.spot_lights[i], in_pos.xyz, normal);
}
vec4 base_color = vec4(1.0, 0.0, 0.0, 1.0);
base_color = texture(base_color_texture, in_uv);
vec3 ambient_color = vec3(0.2) * base_color.xyz;
o_color = vec4(ambient_color + light_contribution * base_color.xyz, base_color.w);
}
Binary file not shown.
@@ -0,0 +1,42 @@
#version 320 es
/* Copyright (c) 2019, 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.
*/
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texcoord_0;
layout(location = 2) in vec3 normal;
layout(set = 0, binding = 1) uniform GlobalUniform {
mat4 model;
mat4 view_proj;
vec3 camera_position;
} global_uniform;
layout (location = 0) out vec4 o_pos;
layout (location = 1) out vec2 o_uv;
layout (location = 2) out vec3 o_normal;
void main(void)
{
o_pos = global_uniform.model * vec4(position, 1.0);
o_uv = texcoord_0;
o_normal = mat3(global_uniform.model) * normal;
gl_Position = global_uniform.view_proj * o_pos;
}
Binary file not shown.
@@ -0,0 +1,30 @@
#version 320 es
/* Copyright (c) 2019, 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.
*/
precision mediump float;
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()
{
outColor = inColor * texture(fontSampler, inUV);
}
Binary file not shown.
@@ -0,0 +1,42 @@
#version 320 es
/* Copyright (c) 2019, 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.
*/
precision mediump float;
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUV;
layout (location = 2) in vec4 inColor;
layout (push_constant) uniform PushConstants {
mat4 transform;
} pushConstants;
layout (location = 0) out vec2 outUV;
layout (location = 1) out vec4 outColor;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outUV = inUV;
outColor = inColor;
gl_Position = pushConstants.transform * vec4(inPos.xy, 0.0, 1.0);
}
Binary file not shown.
@@ -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;
}
@@ -0,0 +1,31 @@
#version 450
/* Copyright (c) 2022-2024, 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.
*/
#extension GL_EXT_nonuniform_qualifier : require
layout (set = 0, binding = 1) uniform sampler2D textures[];
layout (location = 0) in vec2 inUV;
layout (location = 1) flat in int inTexIndex;
layout (location = 0) out vec4 outFragColor;
void main()
{
outFragColor = texture(textures[nonuniformEXT(inTexIndex)], inUV);
}
@@ -0,0 +1,37 @@
#version 450
/* Copyright (c) 2022-2024, 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.
*/
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;
layout (location = 2) in int inTexIndex;
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 view;
} ubo;
layout (location = 0) out vec2 outUV;
layout (location = 1) flat out int outTexIndex;
void main()
{
outUV = inUV;
outTexIndex = inTexIndex;
gl_Position = ubo.projection * ubo.view * vec4(inPos.xyz, 1.0);
}
@@ -0,0 +1,33 @@
/* Copyright (c) 2024, 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.
*/
[[vk::binding(1, 0)]]
Texture2D textures[] : register(t1, space0);
[[vk::binding(1, 0)]]
SamplerState samplers[] : register(s1, space0);
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float2 UV : TEXCOORD0;
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
};
float4 main(VSOutput input) : SV_TARGET
{
return textures[NonUniformResourceIndex(input.TexIndex)].Sample(samplers[NonUniformResourceIndex(input.TexIndex)], input.UV);
}
@@ -0,0 +1,48 @@
/* Copyright (c) 2024, 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.
*/
struct VSInput
{
[[vk::location(0)]] float3 Pos : POSITION0;
[[vk::location(1)]] float2 UV : TEXCOORD0;
[[vk::location(2)]] int TexIndex : TEXCOORD1;
};
struct UBO
{
float4x4 projection;
float4x4 view;
};
[[vk::binding(0, 0)]]
ConstantBuffer<UBO> ubo : register(b0, space0);
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float2 UV : TEXCOORD0;
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
};
VSOutput main(VSInput input)
{
VSOutput output = (VSOutput) 0;
output.UV = input.UV;
output.TexIndex = input.TexIndex;
output.Pos = mul(ubo.projection, mul(ubo.view, float4(input.Pos.xyz, 1.0)));
return output;
}
@@ -0,0 +1,32 @@
/* Copyright (c) 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.
*/
[[vk::binding(1, 0)]]
Sampler2D textures[] : register(t1, space0);
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float2 UV : TEXCOORD0;
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
};
[shader("fragment")]
float4 main(VSOutput input) : SV_TARGET
{
return textures[NonUniformResourceIndex(input.TexIndex)].Sample(input.UV);
}
@@ -0,0 +1,49 @@
/* Copyright (c) 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.
*/
struct VSInput
{
[[vk::location(0)]] float3 Pos : POSITION0;
[[vk::location(1)]] float2 UV : TEXCOORD0;
[[vk::location(2)]] int TexIndex : TEXCOORD1;
};
struct UBO
{
float4x4 projection;
float4x4 view;
};
[[vk::binding(0, 0)]]
ConstantBuffer<UBO> ubo : register(b0, space0);
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float2 UV : TEXCOORD0;
[[vk::location(1)]] nointerpolation int TexIndex : TEXCOORD1;
};
[shader("vertex")]
VSOutput main(VSInput input)
{
VSOutput output = (VSOutput) 0;
output.UV = input.UV;
output.TexIndex = input.TexIndex;
output.Pos = mul(ubo.projection, mul(ubo.view, float4(input.Pos.xyz, 1.0)));
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;
}
@@ -0,0 +1,43 @@
/* Copyright (c) 2024, 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.
*/
[[vk::binding(1, 0)]]
Texture2D textureColor : register(t1);
[[vk::binding(1, 0)]]
SamplerState samplerColor : register(s1);
struct VSOutput
{
float4 Pos : SV_POSITION;
[[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;
};
float4 main(VSOutput input) : SV_TARGET0
{
float4 color = textureColor.SampleBias(samplerColor, input.UV, input.LodBias);
float3 N = normalize(input.Normal);
float3 L = normalize(input.LightVec);
float3 V = normalize(input.ViewVec);
float3 R = reflect(-L, N);
float3 diffuse = max(dot(N, L), 0.0).xxx;
float3 specular = (pow(max(dot(R, V), 0.0), 16.0)).xxx * color.a;
return float4(diffuse * color.rgb + specular, 1.0);
}
@@ -0,0 +1,60 @@
/* Copyright (c) 2024, 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.
*/
struct VSInput
{
[[vk::location(0)]] float3 Pos : POSITION0;
[[vk::location(1)]] float2 UV : TEXCOORD0;
[[vk::location(2)]] float3 Normal : NORMAL0;
};
struct UBO
{
float4x4 projection;
float4x4 model;
float4 viewPos;
float lodBias;
};
[[vk::binding(0, 0)]]
ConstantBuffer<UBO> ubo : register(b0);
struct VSOutput
{
float4 Pos : SV_POSITION;
[[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 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.LodBias = ubo.lodBias;
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;
}
@@ -0,0 +1,28 @@
#version 320 es
/* Copyright (c) 2019, 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.
*/
precision mediump float;
layout(location = 0) in vec3 in_color;
layout(location = 0) out vec4 out_color;
void main()
{
out_color = vec4(in_color, 1.0);
}
@@ -0,0 +1,40 @@
#version 320 es
/* 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.
*/
precision mediump float;
layout(location = 0) out vec3 out_color;
vec2 triangle_positions[3] = vec2[](
vec2(0.5, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
vec3 triangle_colors[3] = vec3[](
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
void main()
{
gl_Position = vec4(triangle_positions[gl_VertexIndex], 0.5, 1.0);
out_color = triangle_colors[gl_VertexIndex];
}
@@ -0,0 +1,29 @@
#version 450
/* Copyright (c) 2019, 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.
*/
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()
{
outColor = inColor * texture(fontSampler, inUV);
}
@@ -0,0 +1,40 @@
#version 450
/* Copyright (c) 2019, 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.
*/
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUV;
layout (location = 2) in vec4 inColor;
layout (push_constant) uniform PushConstants {
mat4 transform;
} pushConstants;
layout (location = 0) out vec2 outUV;
layout (location = 1) out vec4 outColor;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outUV = inUV;
outColor = inColor;
gl_Position = pushConstants.transform * vec4(inPos.xy, 0.0, 1.0);
}
@@ -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();
}
}
@@ -23,6 +23,7 @@ import com.google.androidgamesdk.GameActivity;
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;
@@ -30,6 +31,7 @@ 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.ExecutorService;
@@ -58,6 +60,16 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
@Override
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);
try {
System.loadLibrary(native_lib_name);
@@ -254,6 +266,41 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
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();
@@ -268,6 +315,19 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
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()) {
@@ -276,14 +336,25 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
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);
+18
View File
@@ -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>
+2263
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+3143
View File
File diff suppressed because it is too large Load Diff
+2674
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
+120
View File
@@ -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
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.
+2392
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+10226
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More