Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Implement Octahedral Map Normal/Tangent Attribute Compression #46800

Merged
merged 1 commit into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/classes/ArrayMesh.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions doc/classes/Mesh.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions doc/classes/SurfaceTool.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
9 changes: 6 additions & 3 deletions doc/classes/VisualServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
10 changes: 10 additions & 0 deletions drivers/gles2/rasterizer_scene_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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++;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
96 changes: 70 additions & 26 deletions drivers/gles2/rasterizer_storage_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
clayjohn marked this conversation as resolved.
Show resolved Hide resolved
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;
clayjohn marked this conversation as resolved.
Show resolved Hide resolved
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;
Expand Down
8 changes: 4 additions & 4 deletions drivers/gles2/shader_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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];
Expand Down
22 changes: 12 additions & 10 deletions drivers/gles2/shader_gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class ShaderGLES2 {
Vector<StringName> texture_uniforms;
Vector<StringName> custom_uniforms;
Vector<CharString> custom_defines;
Set<uint32_t> versions;
Set<uint64_t> versions;
};

struct Version {
Expand All @@ -125,16 +125,16 @@ class ShaderGLES2 {

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..
Expand Down Expand Up @@ -222,13 +222,13 @@ class ShaderGLES2 {
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;
Expand Down Expand Up @@ -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);
}
}

Expand Down
26 changes: 26 additions & 0 deletions drivers/gles2/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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

Expand Down
Loading