Skeletons are now working.

This commit is contained in:
Juan Linietsky 2019-09-23 18:53:05 -03:00
parent e3b76fd040
commit b08f13d558
6 changed files with 376 additions and 13 deletions

View file

@ -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);

View file

@ -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 {

View file

@ -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);

View file

@ -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 */

View file

@ -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

View file

@ -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 {