Merge pull request #46800 from The-O-King/normal_compression
[3.x] Implement Octahedral Map Normal/Tangent Attribute Compression
This commit is contained in:
commit
9735f2803c
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