From 6c0ff26f354d877b69ab4bee6f6b44c134572a72 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Fri, 26 Jun 2020 20:22:25 -0700 Subject: [PATCH] Use mesh instead of immediate for drawing Sprite3D --- doc/classes/VisualServer.xml | 2 +- scene/3d/sprite_3d.cpp | 175 ++++++++++++++++++++++++++++------- scene/3d/sprite_3d.h | 11 ++- scene/resources/material.cpp | 2 + 4 files changed, 155 insertions(+), 35 deletions(-) diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 81acdf04997c..6642152749e9 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -4431,7 +4431,7 @@ Flag used to mark that the array uses 16-bit bones instead of 8-bit. - 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. + 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. Primitive to draw consists of points. diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index a4c81b864df2..d1edcd2496d7 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -383,22 +383,73 @@ SpriteBase3D::SpriteBase3D() { modulate = Color(1, 1, 1, 1); pending_update = false; opacity = 1.0; - immediate = VisualServer::get_singleton()->immediate_create(); - set_base(immediate); + + material = VisualServer::get_singleton()->material_create(); + // Set defaults for material, names need to match up those in SpatialMaterial + VS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1)); + VS::get_singleton()->material_set_param(material, "specular", 0.5); + VS::get_singleton()->material_set_param(material, "metallic", 0.0); + VS::get_singleton()->material_set_param(material, "roughness", 1.0); + VS::get_singleton()->material_set_param(material, "uv1_offset", Vector3(0, 0, 0)); + VS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1)); + VS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0)); + VS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1)); + + mesh = VisualServer::get_singleton()->mesh_create(); + + PoolVector2Array mesh_vertices; + PoolVector3Array mesh_normals; + PoolRealArray mesh_tangents; + PoolColorArray mesh_colors; + PoolVector2Array mesh_uvs; + + mesh_vertices.resize(4); + mesh_normals.resize(4); + mesh_tangents.resize(16); + mesh_colors.resize(4); + mesh_uvs.resize(4); + + // create basic mesh and store format information + for (int i = 0; i < 4; i++) { + mesh_normals.write()[i] = Vector3(0.0, 0.0, 0.0); + mesh_tangents.write()[i * 4 + 0] = 0.0; + mesh_tangents.write()[i * 4 + 1] = 0.0; + mesh_tangents.write()[i * 4 + 2] = 0.0; + mesh_tangents.write()[i * 4 + 3] = 0.0; + mesh_colors.write()[i] = Color(1.0, 1.0, 1.0, 1.0); + mesh_uvs.write()[i] = Vector2(0.0, 0.0); + mesh_vertices.write()[i] = Vector2(0.0, 0.0); + } + + Array mesh_array; + mesh_array.resize(VS::ARRAY_MAX); + mesh_array[VS::ARRAY_VERTEX] = mesh_vertices; + mesh_array[VS::ARRAY_NORMAL] = mesh_normals; + mesh_array[VS::ARRAY_TANGENT] = mesh_tangents; + mesh_array[VS::ARRAY_COLOR] = mesh_colors; + mesh_array[VS::ARRAY_TEX_UV] = mesh_uvs; + + VS::get_singleton()->mesh_add_surface_from_arrays(mesh, VS::PRIMITIVE_TRIANGLE_FAN, mesh_array); + const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, 0); + const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, 0); + const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, 0); + + mesh_buffer = VS::get_singleton()->mesh_surface_get_array(mesh, 0); + mesh_stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, mesh_surface_offsets); } SpriteBase3D::~SpriteBase3D() { - VisualServer::get_singleton()->free(immediate); + VisualServer::get_singleton()->free(mesh); + VisualServer::get_singleton()->free(material); } /////////////////////////////////////////// void Sprite3D::_draw() { - RID immediate = get_immediate(); + set_base(RID()); - VS::get_singleton()->immediate_clear(immediate); if (!texture.is_valid()) return; Vector2 tsize = texture->get_size(); @@ -480,11 +531,6 @@ void Sprite3D::_draw() { tangent = Plane(1, 0, 0, 1); } - RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); - VS::get_singleton()->immediate_set_material(immediate, mat); - - VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); - int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); @@ -504,25 +550,61 @@ void Sprite3D::_draw() { AABB aabb; - for (int i = 0; i < 4; i++) { - VS::get_singleton()->immediate_normal(immediate, normal); - VS::get_singleton()->immediate_tangent(immediate, tangent); - VS::get_singleton()->immediate_color(immediate, color); - VS::get_singleton()->immediate_uv(immediate, uvs[i]); + // Buffer is using default compression, so everything except position is compressed + PoolVector::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, + }; + + 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) + }; + + uint8_t v_color[4] = { + (uint8_t)CLAMP(int(color.r * 255.0), 0, 255), + (uint8_t)CLAMP(int(color.g * 255.0), 0, 255), + (uint8_t)CLAMP(int(color.b * 255.0), 0, 255), + (uint8_t)CLAMP(int(color.a * 255.0), 0, 255) + }; + + for (int i = 0; i < 4; i++) { Vector3 vtx; vtx[x_axis] = vertices[i][0]; vtx[y_axis] = vertices[i][1]; - VS::get_singleton()->immediate_vertex(immediate, vtx); if (i == 0) { aabb.position = vtx; aabb.size = Vector3(); } else { aabb.expand_to(vtx); } + + uint16_t v_uv[2] = { Math::make_half_float(uvs[i].x), Math::make_half_float(uvs[i].y) }; + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_VERTEX]], &vertices[i], sizeof(float) * 2); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 4); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 4); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_COLOR]], v_color, 4); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TEX_UV]], v_uv, 2 * 2); } set_aabb(aabb); - VS::get_singleton()->immediate_end(immediate); + + write_buffer.release(); + + RID mesh = get_mesh(); + VS::get_singleton()->mesh_surface_update_region(mesh, 0, 0, mesh_buffer); + + set_base(mesh); + + RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); + VS::get_singleton()->material_set_shader(get_material(), VS::get_singleton()->material_get_shader(mat)); + VS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid()); + VS::get_singleton()->instance_set_surface_material(get_instance(), 0, get_material()); } void Sprite3D::set_texture(const Ref &p_texture) { @@ -716,8 +798,7 @@ Sprite3D::Sprite3D() { void AnimatedSprite3D::_draw() { - RID immediate = get_immediate(); - VS::get_singleton()->immediate_clear(immediate); + set_base(RID()); if (frames.is_null()) { return; @@ -808,12 +889,6 @@ void AnimatedSprite3D::_draw() { tangent = Plane(1, 0, 0, -1); } - RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); - - VS::get_singleton()->immediate_set_material(immediate, mat); - - VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); - int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); @@ -833,25 +908,61 @@ void AnimatedSprite3D::_draw() { AABB aabb; - for (int i = 0; i < 4; i++) { - VS::get_singleton()->immediate_normal(immediate, normal); - VS::get_singleton()->immediate_tangent(immediate, tangent); - VS::get_singleton()->immediate_color(immediate, color); - VS::get_singleton()->immediate_uv(immediate, uvs[i]); + // Buffer is using default compression, so everything except position is compressed + PoolVector::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, + }; + + 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) + }; + + uint8_t v_color[4] = { + (uint8_t)CLAMP(int(color.r * 255.0), 0, 255), + (uint8_t)CLAMP(int(color.g * 255.0), 0, 255), + (uint8_t)CLAMP(int(color.b * 255.0), 0, 255), + (uint8_t)CLAMP(int(color.a * 255.0), 0, 255) + }; + for (int i = 0; i < 4; i++) { Vector3 vtx; vtx[x_axis] = vertices[i][0]; vtx[y_axis] = vertices[i][1]; - VS::get_singleton()->immediate_vertex(immediate, vtx); if (i == 0) { aabb.position = vtx; aabb.size = Vector3(); } else { aabb.expand_to(vtx); } + + uint16_t v_uv[2] = { Math::make_half_float(uvs[i].x), Math::make_half_float(uvs[i].y) }; + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_VERTEX]], &vertices[i], sizeof(float) * 2); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 4); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 4); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_COLOR]], v_color, 4); + copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TEX_UV]], v_uv, 2 * 2); } set_aabb(aabb); - VS::get_singleton()->immediate_end(immediate); + + write_buffer.release(); + + RID mesh = get_mesh(); + VS::get_singleton()->mesh_surface_update_region(mesh, 0, 0, mesh_buffer); + + set_base(mesh); + + RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); + VS::get_singleton()->material_set_shader(get_material(), VS::get_singleton()->material_get_shader(mat)); + VS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid()); + VS::get_singleton()->instance_set_surface_material(get_instance(), 0, get_material()); } void AnimatedSprite3D::_validate_property(PropertyInfo &property) const { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index ddbade147c82..72416e892248 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -76,7 +76,8 @@ class SpriteBase3D : public GeometryInstance { float pixel_size; AABB aabb; - RID immediate; + RID mesh; + RID material; bool flags[FLAG_MAX]; AlphaCutMode alpha_cut; @@ -92,7 +93,13 @@ class SpriteBase3D : public GeometryInstance { static void _bind_methods(); virtual void _draw() = 0; _FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; } - _FORCE_INLINE_ RID &get_immediate() { return immediate; } + _FORCE_INLINE_ RID &get_mesh() { return mesh; } + _FORCE_INLINE_ RID &get_material() { return material; } + + uint32_t mesh_surface_offsets[VS::ARRAY_MAX]; + PoolByteArray mesh_buffer; + uint32_t mesh_stride; + void _queue_update(); public: diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index ab4dbb758ac1..bb9c3697d4fc 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1838,6 +1838,8 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, } materials_for_2d[version] = material; + // flush before using so we can access the shader right away + flush_changes(); return materials_for_2d[version]->get_rid(); }