Octahedral Normal/Tangent Compression
Implement Octahedral Compression for normal/tangent vectors *Oct32 for uncompressed vectors *Oct16 for compressed vectors Reduces vertex size for each attribute by *Uncompressed: 12 bytes, vec4<float32> -> vec2<unorm16> *Compressed: 2 bytes, vec4<unorm8> -> vec2<unorm8> Binormal sign is encoded in the y coordinate of the encoded tangent Added conversion functions to go from octahedral mapping to cartesian for normal and tangent vectors sprite_3d and soft_body meshes write to their vertex buffer memory directly and need to convert their normals and tangents to the new oct format before writing Created a new mesh flag to specify whether a mesh is using octahedral compression or not Updated documentation to discuss new flag/defaults Created shader flags to specify whether octahedral or cartesian vectors are being used Updated importers to use octahedral representation as the default format for importing meshes Updated ShaderGLES2 to support 64 bit version codes as we hit the limit of the 32-bit integer that was previously used as a bitset to store enabled/disabled flags
This commit is contained in:
parent
883bb2f4f6
commit
d274284069
21 changed files with 526 additions and 165 deletions
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue