Merge pull request #46800 from The-O-King/normal_compression

[3.x] Implement Octahedral Map Normal/Tangent Attribute Compression
This commit is contained in:
Rémi Verschelde 2021-07-30 17:34:47 +02:00 committed by GitHub
commit 9735f2803c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 526 additions and 165 deletions

View file

@ -47,7 +47,7 @@
</argument>
<argument index="2" name="blend_shapes" type="Array" default="[ ]">
</argument>
<argument index="3" name="compress_flags" type="int" default="97280">
<argument index="3" name="compress_flags" type="int" default="2194432">
</argument>
<description>
Creates a new surface.

View file

@ -207,8 +207,11 @@
<constant name="ARRAY_FLAG_USE_16_BIT_BONES" value="524288" enum="ArrayFormat">
Flag used to mark that the array uses 16-bit bones instead of 8-bit.
</constant>
<constant name="ARRAY_COMPRESS_DEFAULT" value="97280" enum="ArrayFormat">
Used to set flags [constant ARRAY_COMPRESS_VERTEX], [constant ARRAY_COMPRESS_NORMAL], [constant ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant ARRAY_COMPRESS_TEX_UV], [constant ARRAY_COMPRESS_TEX_UV2] and [constant ARRAY_COMPRESS_WEIGHTS] quickly.
<constant name="ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION" value="2097152" enum="ArrayFormat">
Flag used to mark that the array uses an octahedral representation of normal and tangent vectors rather than cartesian.
</constant>
<constant name="ARRAY_COMPRESS_DEFAULT" value="2194432" enum="ArrayFormat">
Used to set flags [constant ARRAY_COMPRESS_VERTEX], [constant ARRAY_COMPRESS_NORMAL], [constant ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant ARRAY_COMPRESS_TEX_UV], [constant ARRAY_COMPRESS_TEX_UV2], [constant ARRAY_COMPRESS_WEIGHTS], and [constant ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION] quickly.
</constant>
<constant name="ARRAY_VERTEX" value="0" enum="ArrayType">
Array of vertices.

View file

@ -167,11 +167,11 @@
</return>
<argument index="0" name="existing" type="ArrayMesh" default="null">
</argument>
<argument index="1" name="flags" type="int" default="97280">
<argument index="1" name="flags" type="int" default="2194432">
</argument>
<description>
Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh].
Default flag is [constant Mesh.ARRAY_COMPRESS_DEFAULT]. See [code]ARRAY_COMPRESS_*[/code] constants in [enum Mesh.ArrayFormat] for other flags.
Default flag is [constant Mesh.ARRAY_COMPRESS_DEFAULT] if compression is enabled. If compression is disabled the default flag is [constant Mesh.ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION]. See [code]ARRAY_COMPRESS_*[/code] constants in [enum Mesh.ArrayFormat] for other flags.
</description>
</method>
<method name="commit_to_arrays">

View file

@ -2518,7 +2518,7 @@
</argument>
<argument index="3" name="blend_shapes" type="Array" default="[ ]">
</argument>
<argument index="4" name="compress_format" type="int" default="97280">
<argument index="4" name="compress_format" type="int" default="2194432">
</argument>
<description>
Adds a surface generated from the Arrays to a mesh. See [enum PrimitiveType] constants for types.
@ -4489,8 +4489,11 @@
<constant name="ARRAY_FLAG_USE_16_BIT_BONES" value="524288" enum="ArrayFormat">
Flag used to mark that the array uses 16-bit bones instead of 8-bit.
</constant>
<constant name="ARRAY_COMPRESS_DEFAULT" value="97280" enum="ArrayFormat">
Used to set flags [constant ARRAY_COMPRESS_NORMAL], [constant ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant ARRAY_COMPRESS_TEX_UV], [constant ARRAY_COMPRESS_TEX_UV2] and [constant ARRAY_COMPRESS_WEIGHTS] quickly.
<constant name="ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION" value="2097152" enum="ArrayFormat">
Flag used to mark that the array uses an octahedral representation of normal and tangent vectors rather than cartesian.
</constant>
<constant name="ARRAY_COMPRESS_DEFAULT" value="2194432" enum="ArrayFormat">
Used to set flags [constant ARRAY_COMPRESS_NORMAL], [constant ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant ARRAY_COMPRESS_TEX_UV], [constant ARRAY_COMPRESS_TEX_UV2], [constant ARRAY_COMPRESS_WEIGHTS], and [constant ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION] quickly.
</constant>
<constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType">
Primitive to draw consists of points.

View file

@ -2417,6 +2417,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
RasterizerStorageGLES2::Skeleton *prev_skeleton = nullptr;
RasterizerStorageGLES2::GeometryOwner *prev_owner = nullptr;
bool prev_octahedral_compression = false;
Transform view_transform_inverse = p_view_transform.inverse();
CameraMatrix projection_inverse = p_projection.inverse();
@ -2666,6 +2668,12 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
storage->info.render.surface_switch_count++;
}
bool octahedral_compression = ((RasterizerStorageGLES2::Surface *)e->geometry)->format & VisualServer::ArrayFormat::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION;
if (octahedral_compression != prev_octahedral_compression) {
state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_OCTAHEDRAL_COMPRESSION, octahedral_compression);
rebind = true;
}
bool shader_rebind = false;
if (rebind || material != prev_material) {
storage->info.render.material_switch_count++;
@ -2783,6 +2791,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
prev_material = material;
prev_skeleton = skeleton;
prev_instancing = instancing;
prev_octahedral_compression = octahedral_compression;
prev_light = light;
prev_refprobe_1 = refprobe_1;
prev_refprobe_2 = refprobe_2;
@ -2791,6 +2800,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
}
_setup_light_type(nullptr, nullptr); //clear light stuff
state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_OCTAHEDRAL_COMPRESSION, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false);
state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false);
state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false);

View file

@ -2098,22 +2098,42 @@ static PoolVector<uint8_t> _unpack_half_floats(const PoolVector<uint8_t> &array,
} break;
case VS::ARRAY_NORMAL: {
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
src_size[i] = 4;
dst_size[i] = 4;
if (p_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
src_size[i] = 2;
dst_size[i] = 2;
} else {
src_size[i] = 4;
dst_size[i] = 4;
}
} else {
src_size[i] = 12;
dst_size[i] = 12;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
src_size[i] = 4;
dst_size[i] = 4;
} else {
src_size[i] = 12;
dst_size[i] = 12;
}
}
} break;
case VS::ARRAY_TANGENT: {
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
src_size[i] = 4;
dst_size[i] = 4;
if (p_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
src_size[i] = 2;
dst_size[i] = 2;
} else {
src_size[i] = 4;
dst_size[i] = 4;
}
} else {
src_size[i] = 16;
dst_size[i] = 16;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
src_size[i] = 4;
dst_size[i] = 4;
} else {
src_size[i] = 16;
dst_size[i] = 16;
}
}
} break;
@ -2288,30 +2308,54 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
} break;
case VS::ARRAY_NORMAL: {
attribs[i].size = 3;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
attributes_stride += 4; //pad extra byte
if (p_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
attribs[i].normalized = GL_TRUE;
attribs[i].size = 2;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
attributes_stride += 2;
} else {
attribs[i].type = GL_SHORT;
attributes_stride += 4;
}
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 12;
attribs[i].normalized = GL_FALSE;
attribs[i].size = 3;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
attributes_stride += 4; //pad extra byte
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 12;
attribs[i].normalized = GL_FALSE;
}
}
} break;
case VS::ARRAY_TANGENT: {
attribs[i].size = 4;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
attributes_stride += 4;
if (p_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
attribs[i].normalized = GL_TRUE;
attribs[i].size = 2;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
attributes_stride += 2;
} else {
attribs[i].type = GL_SHORT;
attributes_stride += 4;
}
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
attribs[i].size = 4;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
attributes_stride += 4;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}
}
} break;

View file

@ -195,7 +195,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
}
for (int j = 0; j < conditional_count; j++) {
bool enable = (conditional_version.version & (1 << j)) > 0;
bool enable = (conditional_version.version & (uint64_t(1) << j)) > 0;
if (enable) {
strings.push_back(conditional_defines[j]);
@ -488,8 +488,8 @@ void ShaderGLES2::setup(
int p_fragment_code_start) {
ERR_FAIL_COND(version);
conditional_version.key = 0;
new_conditional_version.key = 0;
memset(conditional_version.key, 0, sizeof(conditional_version.key));
memset(new_conditional_version.key, 0, sizeof(new_conditional_version.key));
uniform_count = p_uniform_count;
conditional_count = p_conditional_count;
conditional_defines = p_conditional_defines;
@ -634,7 +634,7 @@ void ShaderGLES2::free_custom_shader(uint32_t p_code_id) {
VersionKey key;
key.code_version = p_code_id;
for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) {
for (Set<uint64_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) {
key.version = E->get();
ERR_CONTINUE(!version_map.has(key));
Version &v = version_map[key];

View file

@ -99,7 +99,7 @@ private:
Vector<StringName> texture_uniforms;
Vector<StringName> custom_uniforms;
Vector<CharString> custom_defines;
Set<uint32_t> versions;
Set<uint64_t> versions;
};
struct Version {
@ -125,16 +125,16 @@ private:
union VersionKey {
struct {
uint32_t version;
uint64_t version;
uint32_t code_version;
};
uint64_t key;
bool operator==(const VersionKey &p_key) const { return key == p_key.key; }
bool operator<(const VersionKey &p_key) const { return key < p_key.key; }
unsigned char key[12];
bool operator==(const VersionKey &p_key) const { return version == p_key.version && code_version == p_key.code_version; }
bool operator<(const VersionKey &p_key) const { return version < p_key.version || (version == p_key.version && code_version < p_key.code_version); }
};
struct VersionKeyHash {
static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); }
static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return hash_djb2_buffer(p_key.key, sizeof(p_key.key)); }
};
//this should use a way more cachefriendly version..
@ -222,13 +222,13 @@ public:
void set_custom_shader(uint32_t p_code_id);
void free_custom_shader(uint32_t p_code_id);
uint32_t get_version_key() const { return conditional_version.version; }
uint64_t get_version_key() const { return conditional_version.version; }
// this void* is actually a RasterizerStorageGLES2::Material, but C++ doesn't
// like forward declared nested classes.
void use_material(void *p_material);
_FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; }
_FORCE_INLINE_ uint64_t get_version() const { return new_conditional_version.version; }
_FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; }
virtual void init() = 0;
@ -261,10 +261,12 @@ int ShaderGLES2::_get_uniform(int p_which) const {
void ShaderGLES2::_set_conditional(int p_which, bool p_value) {
ERR_FAIL_INDEX(p_which, conditional_count);
ERR_FAIL_INDEX(static_cast<unsigned int>(p_which), sizeof(new_conditional_version.version) * 8)
if (p_value) {
new_conditional_version.version |= (1 << p_which);
new_conditional_version.version |= (uint64_t(1) << p_which);
} else {
new_conditional_version.version &= ~(1 << p_which);
new_conditional_version.version &= ~(uint64_t(1) << p_which);
}
}

View file

@ -31,11 +31,19 @@ precision highp int;
attribute highp vec4 vertex_attrib; // attrib:0
/* clang-format on */
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
attribute vec2 normal_attrib; // attrib:1
#else
attribute vec3 normal_attrib; // attrib:1
#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
attribute vec2 tangent_attrib; // attrib:2
#else
attribute vec4 tangent_attrib; // attrib:2
#endif
#endif
#if defined(ENABLE_COLOR_INTERP)
attribute vec4 color_attrib; // attrib:3
@ -102,6 +110,15 @@ uniform float light_normal_bias;
uniform highp int view_index;
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
return v;
}
#endif
//
// varyings
//
@ -341,11 +358,20 @@ void main() {
#endif
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
vec3 normal = oct_to_vec3(normal_attrib);
#else
vec3 normal = normal_attrib;
#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
vec3 tangent = oct_to_vec3(vec2(tangent_attrib.x, abs(tangent_attrib.y) * 2.0 - 1.0));
float binormalf = sign(tangent_attrib.y);
#else
vec3 tangent = tangent_attrib.xyz;
float binormalf = tangent_attrib.a;
#endif
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif

View file

@ -1944,6 +1944,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
bool first = true;
bool prev_use_instancing = false;
bool prev_octahedral_compression = false;
storage->info.render.draw_call_count += p_element_count;
bool prev_opaque_prepass = false;
@ -2108,6 +2109,12 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
}
}
bool octahedral_compression = ((RasterizerStorageGLES3::Surface *)e->geometry)->format & VisualServer::ArrayFormat::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION;
if (octahedral_compression != prev_octahedral_compression) {
state.scene_shader.set_conditional(SceneShaderGLES3::ENABLE_OCTAHEDRAL_COMPRESSION, octahedral_compression);
rebind = true;
}
if (material != prev_material || rebind) {
storage->info.render.material_switch_count++;
@ -2140,12 +2147,14 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
prev_shading = shading;
prev_skeleton = skeleton;
prev_use_instancing = use_instancing;
prev_octahedral_compression = octahedral_compression;
prev_opaque_prepass = use_opaque_prepass;
first = false;
}
glBindVertexArray(0);
state.scene_shader.remove_custom_define("#define ENABLE_OCTAHEDRAL_COMPRESSION\n");
state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false);

View file

@ -3396,30 +3396,54 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
} break;
case VS::ARRAY_NORMAL: {
attribs[i].size = 3;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
attributes_stride += 4; //pad extra byte
if (p_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
attribs[i].normalized = GL_TRUE;
attribs[i].size = 2;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
attributes_stride += 2;
} else {
attribs[i].type = GL_SHORT;
attributes_stride += 4;
}
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 12;
attribs[i].normalized = GL_FALSE;
attribs[i].size = 3;
if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
attributes_stride += 4; //pad extra byte
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 12;
attribs[i].normalized = GL_FALSE;
}
}
} break;
case VS::ARRAY_TANGENT: {
attribs[i].size = 4;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
attributes_stride += 4;
if (p_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
attribs[i].normalized = GL_TRUE;
attribs[i].size = 2;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
attributes_stride += 2;
} else {
attribs[i].type = GL_SHORT;
attributes_stride += 4;
}
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
attribs[i].size = 4;
if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
attributes_stride += 4;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 16;
attribs[i].normalized = GL_FALSE;
}
}
} break;

View file

@ -25,10 +25,18 @@ ARRAY_INDEX=8,
layout(location = 0) in highp vec4 vertex_attrib;
/* clang-format on */
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
layout(location = 1) in vec2 normal_attrib;
#else
layout(location = 1) in vec3 normal_attrib;
#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
layout(location = 2) in vec2 tangent_attrib;
#else
layout(location = 2) in vec4 tangent_attrib;
#endif
#endif
#if defined(ENABLE_COLOR_INTERP)
layout(location = 3) in vec4 color_attrib;
@ -251,6 +259,15 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float r
#endif
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
return v;
}
#endif
/* Varyings */
out highp vec3 vertex_interp;
@ -322,12 +339,21 @@ void main() {
}
#endif
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
vec3 normal = oct_to_vec3(normal_attrib);
#else
vec3 normal = normal_attrib;
#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
#ifdef ENABLE_OCTAHEDRAL_COMPRESSION
vec3 tangent = oct_to_vec3(vec2(tangent_attrib.x, abs(tangent_attrib.y) * 2.0 - 1.0));
float binormalf = sign(tangent_attrib.y);
#else
vec3 tangent = tangent_attrib.xyz;
float binormalf = tangent_attrib.a;
#endif
#endif
#if defined(ENABLE_COLOR_INTERP)
color_interp = color_attrib;
@ -338,7 +364,6 @@ void main() {
#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif

View file

@ -928,7 +928,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
mr.push_back(a);
}
p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0);
p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : Mesh::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION);
if (material.is_valid()) {
if (p_use_mesh_material) {

View file

@ -210,7 +210,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
bool generate_tangents = p_generate_tangents;
Vector3 scale_mesh = p_scale_mesh;
Vector3 offset_mesh = p_offset_mesh;
int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : Mesh::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION;
Vector<Vector3> vertices;
Vector<Vector3> normals;

View file

@ -386,7 +386,7 @@ MeshInstance *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDo
Mesh::PRIMITIVE_TRIANGLES,
surface->surface_tool->commit_to_arrays(),
surface->morphs,
use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0);
use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : Mesh::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION);
if (surface->material.is_valid()) {
mesh->surface_set_name(in_mesh_surface_id, surface->material->get_name());

View file

@ -84,7 +84,12 @@ void SoftBodyVisualServerHandler::set_vertex(int p_vertex_id, const void *p_vect
}
void SoftBodyVisualServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
Vector2 normal_oct = VisualServer::get_singleton()->norm_to_oct(*(Vector3 *)p_vector3);
int16_t v_normal[2] = {
(int16_t)CLAMP(normal_oct.x * 32767, -32768, 32767),
(int16_t)CLAMP(normal_oct.y * 32767, -32768, 32767),
};
memcpy(&write_buffer[p_vertex_id * stride + offset_normal], v_normal, sizeof(uint16_t) * 2);
}
void SoftBodyVisualServerHandler::set_aabb(const AABB &p_aabb) {

View file

@ -534,18 +534,16 @@ void Sprite3D::_draw() {
// Everything except position and UV is compressed
PoolVector<uint8_t>::Write write_buffer = mesh_buffer.write();
int8_t v_normal[4] = {
(int8_t)CLAMP(normal.x * 127, -128, 127),
(int8_t)CLAMP(normal.y * 127, -128, 127),
(int8_t)CLAMP(normal.z * 127, -128, 127),
0,
Vector2 normal_oct = VisualServer::get_singleton()->norm_to_oct(normal);
int8_t v_normal[2] = {
(int8_t)CLAMP(normal_oct.x * 127, -128, 127),
(int8_t)CLAMP(normal_oct.y * 127, -128, 127),
};
int8_t v_tangent[4] = {
(int8_t)CLAMP(tangent.normal.x * 127, -128, 127),
(int8_t)CLAMP(tangent.normal.y * 127, -128, 127),
(int8_t)CLAMP(tangent.normal.z * 127, -128, 127),
(int8_t)CLAMP(tangent.d * 127, -128, 127)
Vector2 tangent_oct = VisualServer::get_singleton()->tangent_to_oct(tangent.normal, tangent.d, false);
int8_t v_tangent[2] = {
(int8_t)CLAMP(tangent_oct.x * 127, -128, 127),
(int8_t)CLAMP(tangent_oct.y * 127, -128, 127),
};
uint8_t v_color[4] = {
@ -571,8 +569,8 @@ void Sprite3D::_draw() {
float v_vertex[3] = { vtx.x, vtx.y, vtx.z };
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 4);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 4);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 2);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 2);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_COLOR]], v_color, 4);
}
@ -888,18 +886,16 @@ void AnimatedSprite3D::_draw() {
// Everything except position and UV is compressed
PoolVector<uint8_t>::Write write_buffer = mesh_buffer.write();
int8_t v_normal[4] = {
(int8_t)CLAMP(normal.x * 127, -128, 127),
(int8_t)CLAMP(normal.y * 127, -128, 127),
(int8_t)CLAMP(normal.z * 127, -128, 127),
0,
Vector2 normal_oct = VisualServer::get_singleton()->norm_to_oct(normal);
int8_t v_normal[2] = {
(int8_t)CLAMP(normal_oct.x * 127, -128, 127),
(int8_t)CLAMP(normal_oct.y * 127, -128, 127),
};
int8_t v_tangent[4] = {
(int8_t)CLAMP(tangent.normal.x * 127, -128, 127),
(int8_t)CLAMP(tangent.normal.y * 127, -128, 127),
(int8_t)CLAMP(tangent.normal.z * 127, -128, 127),
(int8_t)CLAMP(tangent.d * 127, -128, 127)
Vector2 tangent_oct = VisualServer::get_singleton()->tangent_to_oct(tangent.normal, tangent.d, false);
int8_t v_tangent[2] = {
(int8_t)CLAMP(tangent_oct.x * 127, -128, 127),
(int8_t)CLAMP(tangent_oct.y * 127, -128, 127),
};
uint8_t v_color[4] = {
@ -925,8 +921,8 @@ void AnimatedSprite3D::_draw() {
float v_vertex[3] = { vtx.x, vtx.y, vtx.z };
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 4);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 4);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 2);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 2);
memcpy(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_COLOR]], v_color, 4);
}

View file

@ -546,6 +546,7 @@ void Mesh::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_16_BIT_BONES);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION);
BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);

View file

@ -96,8 +96,9 @@ public:
ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
ARRAY_FLAG_USE_16_BIT_BONES = ARRAY_COMPRESS_INDEX << 2,
ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION = ARRAY_COMPRESS_INDEX << 4,
ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS
ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS | ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION
};

View file

@ -329,6 +329,59 @@ RID VisualServer::get_white_texture() {
#define SMALL_VEC2 Vector2(0.00001, 0.00001)
#define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001)
// Maps normalized vector to an octohedron projected onto the cartesian plane
// Resulting 2D vector in range [-1, 1]
// See http://jcgt.org/published/0003/02/01/ for details
Vector2 VisualServer::norm_to_oct(const Vector3 v) {
const float invL1Norm = (1.0f) / (Math::absf(v.x) + Math::absf(v.y) + Math::absf(v.z));
Vector2 res;
if (v.z < 0.0f) {
res.x = (1.0f - Math::absf(v.y * invL1Norm)) * SGN(v.x);
res.y = (1.0f - Math::absf(v.x * invL1Norm)) * SGN(v.y);
} else {
res.x = v.x * invL1Norm;
res.y = v.y * invL1Norm;
}
return res;
}
// Maps normalized tangent vector to an octahedron projected onto the cartesian plane
// Encodes the tangent vector sign in the second componenet of the returned Vector2 for use in shaders
// high_precision specifies whether the encoding will be 32 bit (true) or 16 bit (false)
// Resulting 2D vector in range [-1, 1]
// See http://jcgt.org/published/0003/02/01/ for details
Vector2 VisualServer::tangent_to_oct(const Vector3 v, const float sign, const bool high_precision) {
float bias = high_precision ? 1.0f / 32767 : 1.0f / 127;
Vector2 res = norm_to_oct(v);
res.y = res.y * 0.5f + 0.5f;
res.y = MAX(res.y, bias) * SGN(sign);
return res;
}
// Convert Octohedron-mapped normalized vector back to Cartesian
// Assumes normalized format (elements of v within range [-1, 1])
Vector3 VisualServer::oct_to_norm(const Vector2 v) {
Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y)));
float t = MAX(-res.z, 0.0f);
res.x += t * -SGN(res.x);
res.y += t * -SGN(res.y);
return res;
}
// Convert Octohedron-mapped normalized tangent vector back to Cartesian
// out_sign provides the direction for the original cartesian tangent
// Assumes normalized format (elements of v within range [-1, 1])
Vector3 VisualServer::oct_to_tangent(const Vector2 v, float *out_sign) {
Vector2 v_decompressed = v;
v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1;
Vector3 res = oct_to_norm(v_decompressed);
*out_sign = SGN(v[1]);
return res;
}
Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t *p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) {
PoolVector<uint8_t>::Write vw = r_vertex_array.write();
@ -437,22 +490,47 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_
// setting vertices means regenerating the AABB
if (p_format & ARRAY_COMPRESS_NORMAL) {
for (int i = 0; i < p_vertex_array_len; i++) {
int8_t vector[4] = {
(int8_t)CLAMP(src[i].x * 127, -128, 127),
(int8_t)CLAMP(src[i].y * 127, -128, 127),
(int8_t)CLAMP(src[i].z * 127, -128, 127),
0,
};
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_NORMAL) {
for (int i = 0; i < p_vertex_array_len; i++) {
Vector2 res = norm_to_oct(src[i]);
int8_t vector[2] = {
(int8_t)CLAMP(res.x * 127, -128, 127),
(int8_t)CLAMP(res.y * 127, -128, 127),
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 2);
}
} else {
for (int i = 0; i < p_vertex_array_len; i++) {
Vector2 res = norm_to_oct(src[i]);
int16_t vector[2] = {
(int16_t)CLAMP(res.x * 32767, -32768, 32767),
(int16_t)CLAMP(res.y * 32767, -32768, 32767),
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
}
}
} else {
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[3] = { src[i].x, src[i].y, src[i].z };
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 3 * 4);
if (p_format & ARRAY_COMPRESS_NORMAL) {
for (int i = 0; i < p_vertex_array_len; i++) {
int8_t vector[4] = {
(int8_t)CLAMP(src[i].x * 127, -128, 127),
(int8_t)CLAMP(src[i].y * 127, -128, 127),
(int8_t)CLAMP(src[i].z * 127, -128, 127),
0,
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
}
} else {
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[3] = { src[i].x, src[i].y, src[i].z };
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 3 * 4);
}
}
}
@ -468,28 +546,57 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_
PoolVector<real_t>::Read read = array.read();
const real_t *src = read.ptr();
if (p_format & ARRAY_COMPRESS_TANGENT) {
for (int i = 0; i < p_vertex_array_len; i++) {
int8_t xyzw[4] = {
(int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
(int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
(int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
(int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
};
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_TANGENT) {
for (int i = 0; i < p_vertex_array_len; i++) {
Vector3 source(src[i * 4 + 0], src[i * 4 + 1], src[i * 4 + 2]);
Vector2 res = tangent_to_oct(source, src[i * 4 + 3], false);
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4);
int8_t vector[2] = {
(int8_t)CLAMP(res.x * 127, -128, 127),
(int8_t)CLAMP(res.y * 127, -128, 127)
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 2);
}
} else {
for (int i = 0; i < p_vertex_array_len; i++) {
Vector3 source(src[i * 4 + 0], src[i * 4 + 1], src[i * 4 + 2]);
Vector2 res = tangent_to_oct(source, src[i * 4 + 3], true);
int16_t vector[2] = {
(int16_t)CLAMP(res.x * 32767, -32768, 32767),
(int16_t)CLAMP(res.y * 32767, -32768, 32767)
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
}
}
} else {
for (int i = 0; i < p_vertex_array_len; i++) {
float xyzw[4] = {
src[i * 4 + 0],
src[i * 4 + 1],
src[i * 4 + 2],
src[i * 4 + 3]
};
if (p_format & ARRAY_COMPRESS_TANGENT) {
for (int i = 0; i < p_vertex_array_len; i++) {
int8_t xyzw[4] = {
(int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
(int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
(int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
(int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4 * 4);
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4);
}
} else {
for (int i = 0; i < p_vertex_array_len; i++) {
float xyzw[4] = {
src[i * 4 + 0],
src[i * 4 + 1],
src[i * 4 + 2],
src[i * 4 + 3]
};
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4 * 4);
}
}
}
@ -770,19 +877,35 @@ uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format,
} break;
case VS::ARRAY_NORMAL: {
if (p_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
elem_size = sizeof(float) * 3;
if (p_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 3;
}
}
} break;
case VS::ARRAY_TANGENT: {
if (p_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
elem_size = sizeof(float) * 4;
if (p_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 4;
}
}
} break;
@ -959,10 +1082,18 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
} break;
case VS::ARRAY_NORMAL: {
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
if (p_compress_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
elem_size = sizeof(float) * 3;
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 3;
}
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
@ -970,10 +1101,18 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
} break;
case VS::ARRAY_TANGENT: {
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
if (p_compress_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
elem_size = sizeof(float) * 4;
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 4;
}
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
@ -1146,19 +1285,35 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
} break;
case VS::ARRAY_NORMAL: {
if (p_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
elem_size = sizeof(float) * 3;
if (p_format & ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 3;
}
}
} break;
case VS::ARRAY_TANGENT: {
if (p_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
elem_size = sizeof(float) * 4;
if (p_format & ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 4;
}
}
} break;
@ -1287,20 +1442,42 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
PoolVector<Vector3> arr;
arr.resize(p_vertex_len);
if (p_format & ARRAY_COMPRESS_NORMAL) {
PoolVector<Vector3>::Write w = arr.write();
const float multiplier = 1.f / 127.f;
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_NORMAL) {
PoolVector<Vector3>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
for (int j = 0; j < p_vertex_len; j++) {
const int8_t *n = (const int8_t *)&r[j * total_elem_size + offsets[i]];
Vector2 enc(n[0] / 127.0f, n[1] / 127.0f);
w[j] = oct_to_norm(enc);
}
} else {
PoolVector<Vector3>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const int16_t *n = (const int16_t *)&r[j * total_elem_size + offsets[i]];
Vector2 enc(n[0] / 32767.0f, n[1] / 32767.0f);
w[j] = oct_to_norm(enc);
}
}
} else {
PoolVector<Vector3>::Write w = arr.write();
if (p_format & ARRAY_COMPRESS_NORMAL) {
PoolVector<Vector3>::Write w = arr.write();
const float multiplier = 1.f / 127.f;
for (int j = 0; j < p_vertex_len; j++) {
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
w[j] = Vector3(v[0], v[1], v[2]);
for (int j = 0; j < p_vertex_len; j++) {
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
}
} else {
PoolVector<Vector3>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
w[j] = Vector3(v[0], v[1], v[2]);
}
}
}
@ -1311,22 +1488,51 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
case VS::ARRAY_TANGENT: {
PoolVector<float> arr;
arr.resize(p_vertex_len * 4);
if (p_format & ARRAY_COMPRESS_TANGENT) {
PoolVector<float>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
for (int k = 0; k < 4; k++) {
w[j * 4 + k] = float(v[k] / 127.0);
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_format & ARRAY_COMPRESS_TANGENT) {
PoolVector<float>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const int8_t *t = (const int8_t *)&r[j * total_elem_size + offsets[i]];
Vector2 enc(t[0] / 127.0f, t[1] / 127.0f);
Vector3 dec = oct_to_tangent(enc, &w[j * 3 + 2]);
w[j * 3 + 0] = dec.x;
w[j * 3 + 1] = dec.y;
w[j * 3 + 2] = dec.z;
}
} else {
PoolVector<float>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const int16_t *t = (const int16_t *)&r[j * total_elem_size + offsets[i]];
Vector2 enc(t[0] / 32767.0f, t[1] / 32767.0f);
Vector3 dec = oct_to_tangent(enc, &w[j * 3 + 2]);
w[j * 3 + 0] = dec.x;
w[j * 3 + 1] = dec.y;
w[j * 3 + 2] = dec.z;
}
}
} else {
PoolVector<float>::Write w = arr.write();
if (p_format & ARRAY_COMPRESS_TANGENT) {
PoolVector<float>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
for (int k = 0; k < 4; k++) {
w[j * 4 + k] = v[k];
for (int j = 0; j < p_vertex_len; j++) {
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
for (int k = 0; k < 4; k++) {
w[j * 4 + k] = float(v[k] / 127.0);
}
}
} else {
PoolVector<float>::Write w = arr.write();
for (int j = 0; j < p_vertex_len; j++) {
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
for (int k = 0; k < 4; k++) {
w[j * 4 + k] = v[k];
}
}
}
}
@ -2019,6 +2225,7 @@ void VisualServer::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_16_BIT_BONES);
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION);
BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);

View file

@ -68,6 +68,10 @@ protected:
public:
static VisualServer *get_singleton();
static VisualServer *create();
static Vector2 norm_to_oct(const Vector3 v);
static Vector2 tangent_to_oct(const Vector3 v, const float sign, const bool high_precision);
static Vector3 oct_to_norm(const Vector2 v);
static Vector3 oct_to_tangent(const Vector2 v, float *out_sign);
enum {
@ -263,8 +267,9 @@ public:
ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
ARRAY_FLAG_USE_16_BIT_BONES = ARRAY_COMPRESS_INDEX << 2,
ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION = ARRAY_COMPRESS_INDEX << 4,
ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS
ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS | ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION
};