diff options
6 files changed, 376 insertions, 13 deletions
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index 503d36e7b1..e44955d666 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -626,7 +626,12 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, } id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + } else if (e->instance->base_type == VS::INSTANCE_MESH) { + if (e->instance->skeleton.is_valid()) { + id.flags |= INSTANCE_DATA_FLAG_SKELETON; + } } + //forward uint32_t reflection_count = 0; @@ -746,6 +751,9 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l switch (e->instance->base_type) { case VS::INSTANCE_MESH: { primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index); + if (e->instance->skeleton.is_valid()) { + xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, 1); + } } break; case VS::INSTANCE_MULTIMESH: { RID mesh = storage->multimesh_get_mesh(e->instance->base); diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index bd6d6563f5..73d48c5fe8 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -254,6 +254,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, + INSTANCE_DATA_FLAG_SKELETON = 1 << 19, }; struct InstanceData { diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index fc6147316f..c90a280fdc 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -2010,11 +2010,104 @@ AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { return mesh->custom_aabb; } - if (!p_skeleton.is_valid()) { + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + if (!skeleton || skeleton->size == 0) { return mesh->aabb; } - return mesh->aabb; + AABB aabb; + + for (int i = 0; i < mesh->surface_count; i++) { + + AABB laabb; + if ((mesh->surfaces[i]->format & VS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) { + + int bs = mesh->surfaces[i]->bone_aabbs.size(); + const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr(); + + int sbs = skeleton->size; + ERR_CONTINUE(bs > sbs); + const float *baseptr = skeleton->data.ptr(); + + bool first = true; + + if (skeleton->use_2d) { + for (int j = 0; j < bs; j++) { + + if (skbones[0].size == Vector3()) + continue; //bone is unused + + const float *dataptr = baseptr + j * 8; + + Transform mtx; + + mtx.basis.elements[0].x = dataptr[0]; + mtx.basis.elements[1].x = dataptr[1]; + mtx.origin.x = dataptr[3]; + + mtx.basis.elements[0].y = dataptr[4]; + mtx.basis.elements[1].y = dataptr[5]; + mtx.origin.y = dataptr[7]; + + AABB baabb = mtx.xform(skbones[j]); + + if (first) { + laabb = baabb; + first = false; + } else { + laabb.merge_with(baabb); + } + } + } else { + for (int j = 0; j < bs; j++) { + + if (skbones[0].size == Vector3()) + continue; //bone is unused + + const float *dataptr = baseptr + j * 12; + + Transform mtx; + + mtx.basis.elements[0][0] = dataptr[0]; + mtx.basis.elements[0][1] = dataptr[1]; + mtx.basis.elements[0][2] = dataptr[2]; + mtx.origin.x = dataptr[3]; + mtx.basis.elements[1][0] = dataptr[4]; + mtx.basis.elements[1][1] = dataptr[5]; + mtx.basis.elements[1][2] = dataptr[6]; + mtx.origin.y = dataptr[7]; + mtx.basis.elements[2][0] = dataptr[8]; + mtx.basis.elements[2][1] = dataptr[9]; + mtx.basis.elements[2][2] = dataptr[10]; + mtx.origin.z = dataptr[11]; + + AABB baabb = mtx.xform(skbones[j]); + if (first) { + laabb = baabb; + first = false; + } else { + laabb.merge_with(baabb); + } + } + } + + if (laabb.size == Vector3()) { + laabb = mesh->surfaces[i]->aabb; + } + } else { + + laabb = mesh->surfaces[i]->aabb; + } + + if (i == 0) { + aabb = laabb; + } else { + aabb.merge_with(laabb); + } + } + + return aabb; } void RasterizerStorageRD::mesh_clear(RID p_mesh) { @@ -2783,6 +2876,186 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { multimesh_dirty_list = nullptr; } +/* SKELETON */ + +/* SKELETON API */ + +RID RasterizerStorageRD::skeleton_create() { + + return skeleton_owner.make_rid(Skeleton()); +} + +void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { + + if (!skeleton->dirty) { + skeleton->dirty = true; + skeleton->dirty_list = skeleton_dirty_list; + skeleton_dirty_list = skeleton; + } +} + +void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + ERR_FAIL_COND(p_bones < 0); + + if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) + return; + + skeleton->size = p_bones; + skeleton->use_2d = p_2d_skeleton; + skeleton->uniform_set_3d = RID(); + + if (skeleton->buffer.is_valid()) { + RD::get_singleton()->free(skeleton->buffer); + skeleton->buffer = RID(); + skeleton->data.resize(0); + } + + if (skeleton->size) { + + skeleton->data.resize(skeleton->size * (skeleton->use_2d ? 8 : 12)); + skeleton->buffer = RD::get_singleton()->storage_buffer_create(skeleton->data.size() * sizeof(float)); + zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float)); + + _skeleton_make_dirty(skeleton); + } +} +int RasterizerStorageRD::skeleton_get_bone_count(RID p_skeleton) const { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND_V(!skeleton, 0); + + return skeleton->size; +} + +void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + ERR_FAIL_COND(!skeleton); + ERR_FAIL_INDEX(p_bone, skeleton->size); + ERR_FAIL_COND(skeleton->use_2d); + + float *dataptr = skeleton->data.ptrw() + p_bone * 12; + + dataptr[0] = p_transform.basis.elements[0][0]; + dataptr[1] = p_transform.basis.elements[0][1]; + dataptr[2] = p_transform.basis.elements[0][2]; + dataptr[3] = p_transform.origin.x; + dataptr[4] = p_transform.basis.elements[1][0]; + dataptr[5] = p_transform.basis.elements[1][1]; + dataptr[6] = p_transform.basis.elements[1][2]; + dataptr[7] = p_transform.origin.y; + dataptr[8] = p_transform.basis.elements[2][0]; + dataptr[9] = p_transform.basis.elements[2][1]; + dataptr[10] = p_transform.basis.elements[2][2]; + dataptr[11] = p_transform.origin.z; + + _skeleton_make_dirty(skeleton); +} + +Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + ERR_FAIL_COND_V(!skeleton, Transform()); + ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform()); + ERR_FAIL_COND_V(skeleton->use_2d, Transform()); + + const float *dataptr = skeleton->data.ptr() + p_bone * 12; + + Transform t; + + t.basis.elements[0][0] = dataptr[0]; + t.basis.elements[0][1] = dataptr[1]; + t.basis.elements[0][2] = dataptr[2]; + t.origin.x = dataptr[3]; + t.basis.elements[1][0] = dataptr[4]; + t.basis.elements[1][1] = dataptr[5]; + t.basis.elements[1][2] = dataptr[6]; + t.origin.y = dataptr[7]; + t.basis.elements[2][0] = dataptr[8]; + t.basis.elements[2][1] = dataptr[9]; + t.basis.elements[2][2] = dataptr[10]; + t.origin.z = dataptr[11]; + + return t; +} +void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + ERR_FAIL_COND(!skeleton); + ERR_FAIL_INDEX(p_bone, skeleton->size); + ERR_FAIL_COND(!skeleton->use_2d); + + float *dataptr = skeleton->data.ptrw() + p_bone * 8; + + dataptr[0] = p_transform.elements[0][0]; + dataptr[1] = p_transform.elements[1][0]; + dataptr[2] = 0; + dataptr[3] = p_transform.elements[2][0]; + dataptr[4] = p_transform.elements[0][1]; + dataptr[5] = p_transform.elements[1][1]; + dataptr[6] = 0; + dataptr[7] = p_transform.elements[2][1]; + + _skeleton_make_dirty(skeleton); +} +Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + ERR_FAIL_COND_V(!skeleton, Transform2D()); + ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D()); + ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D()); + + const float *dataptr = skeleton->data.ptr() + p_bone * 8; + + Transform2D t; + t.elements[0][0] = dataptr[0]; + t.elements[1][0] = dataptr[1]; + t.elements[2][0] = dataptr[3]; + t.elements[0][1] = dataptr[4]; + t.elements[1][1] = dataptr[5]; + t.elements[2][1] = dataptr[7]; + + return t; +} + +void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + ERR_FAIL_COND(!skeleton->use_2d); + + skeleton->base_transform_2d = p_base_transform; +} + +void RasterizerStorageRD::_update_dirty_skeletons() { + + while (skeleton_dirty_list) { + + Skeleton *skeleton = skeleton_dirty_list; + + if (skeleton->size) { + + RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr(), false); + } + + skeleton_dirty_list = skeleton->dirty_list; + + skeleton->instance_dependency.instance_notify_changed(true, false); + + skeleton->dirty = false; + skeleton->dirty_list = nullptr; + } + + skeleton_dirty_list = nullptr; +} + /* LIGHT */ RID RasterizerStorageRD::light_create(VS::LightType p_type) { @@ -3601,6 +3874,14 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In } } +void RasterizerStorageRD::skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + p_instance->update_dependency(&skeleton->instance_dependency); +} + VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { @@ -3621,6 +3902,7 @@ VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { void RasterizerStorageRD::update_dirty_resources() { _update_queued_materials(); _update_dirty_multimeshes(); + _update_dirty_skeletons(); } bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { @@ -3705,6 +3987,12 @@ bool RasterizerStorageRD::free(RID p_rid) { MultiMesh *multimesh = multimesh_owner.getornull(p_rid); multimesh->instance_dependency.instance_notify_deleted(p_rid); multimesh_owner.free(p_rid); + } else if (skeleton_owner.owns(p_rid)) { + _update_dirty_skeletons(); + skeleton_allocate(p_rid, 0); + Skeleton *skeleton = skeleton_owner.getornull(p_rid); + skeleton->instance_dependency.instance_notify_deleted(p_rid); + skeleton_owner.free(p_rid); } else if (reflection_probe_owner.owns(p_rid)) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); reflection_probe->instance_dependency.instance_notify_deleted(p_rid); diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 670c97a1c1..397e3c1b95 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -327,6 +327,32 @@ private: _FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb); _FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances); void _update_dirty_multimeshes(); + + /* Skeleton */ + + struct Skeleton { + bool use_2d = false; + int size = 0; + Vector<float> data; + RID buffer; + + bool dirty = false; + Skeleton *dirty_list = nullptr; + Transform2D base_transform_2d; + + RID uniform_set_3d; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner<Skeleton> skeleton_owner; + + _FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton); + + Skeleton *skeleton_dirty_list = nullptr; + + void _update_dirty_skeletons(); + /* LIGHT */ struct Light { @@ -740,16 +766,33 @@ public: /* SKELETON API */ - RID skeleton_create() { return RID(); } - void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) {} - void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {} - void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) {} - int skeleton_get_bone_count(RID p_skeleton) const { return 0; } - void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {} - Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { return Transform(); } - void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {} - Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { return Transform2D(); } + RID skeleton_create(); + void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false); + void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); + void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform); + int skeleton_get_bone_count(RID p_skeleton) const; + void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform); + Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; + void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); + Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; + + _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const { + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + if (skeleton->use_2d) { + return RID(); + } + if (!skeleton->uniform_set_3d.is_valid()) { + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(skeleton->buffer); + uniforms.push_back(u); + skeleton->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set); + } + return skeleton->uniform_set_3d; + } /* Light API */ RID light_create(VS::LightType p_type); @@ -873,7 +916,7 @@ public: float reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const; void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {} + void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); /* GI PROBE API */ diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl index 3f5a81ee93..711da3be9b 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -136,13 +136,35 @@ void main() { #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 tangent = tangent_attrib.xyz; float binormalf = tangent_attrib.a; + vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { + //multimesh, instances are for it + + uvec2 bones_01 = uvec2(bone_attrib.x&0xFFFF,bone_attrib.x>>16) * 3; + uvec2 bones_23 = uvec2(bone_attrib.y&0xFFFF,bone_attrib.y>>16) * 3; + vec2 weights_01 = unpackUnorm2x16(bone_attrib.z); + vec2 weights_23 = unpackUnorm2x16(bone_attrib.w); + + mat4 m = mat4(transforms.data[bones_01.x],transforms.data[bones_01.x+1],transforms.data[bones_01.x+2],vec4(0.0,0.0,0.0,1.0)) * weights_01.x; + m += mat4(transforms.data[bones_01.y],transforms.data[bones_01.y+1],transforms.data[bones_01.y+2],vec4(0.0,0.0,0.0,1.0)) * weights_01.y; + m += mat4(transforms.data[bones_23.x],transforms.data[bones_23.x+1],transforms.data[bones_23.x+2],vec4(0.0,0.0,0.0,1.0)) * weights_23.x; + m += mat4(transforms.data[bones_23.y],transforms.data[bones_23.y+1],transforms.data[bones_23.y+2],vec4(0.0,0.0,0.0,1.0)) * weights_23.y; + + //reverse order because its transposed + vertex = (vec4(vertex,1.0) * m).xyz; + normal = (vec4(normal,0.0) * m).xyz; + #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 binormal = normalize(cross(normal, tangent) * binormalf); + tangent = (vec4(tangent,0.0) * m).xyz; + binormal = (vec4(binormal,0.0) * m).xyz; #endif + } + #if defined(UV_USED) uv_interp = uv_attrib; #endif diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl index 4d1a1c9495..81cf47b192 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl @@ -131,6 +131,7 @@ layout(set=0,binding=8,std140) uniform SceneData { //3 bits of stride #define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 +#define INSTANCE_FLAGS_SKELETON (1 << 19) struct InstanceData { |