2
0
Эх сурвалжийг харах

Skeletons are now working.

Juan Linietsky 6 жил өмнө
parent
commit
b08f13d558

+ 8 - 0
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);

+ 1 - 0
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 {

+ 290 - 2
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);

+ 53 - 10
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 */
 

+ 23 - 1
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

+ 1 - 0
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 {