diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index dabb7918a91..63090e53a75 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -124,6 +124,7 @@ void RasterizerGLES3::begin_frame(){ storage->frame.time[3]=Math::fmod(time_total,60); storage->frame.count++; + storage->update_dirty_skeletons(); storage->update_dirty_shaders(); storage->update_dirty_materials(); scene->iteration(); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 3ead218226d..e0a3dbd36e8 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1329,6 +1329,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e int current_blend_mode=-1; int prev_shading=-1; + RID prev_skeleton; state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); //by default unshaded (easier to set) @@ -1338,6 +1339,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e RenderList::Element *e = p_elements[i]; RasterizerStorageGLES3::Material* material= e->material; + RID skeleton = e->instance->skeleton; bool rebind=first; @@ -1466,6 +1468,18 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } + if (prev_skeleton!=skeleton) { + if (prev_skeleton.is_valid() != skeleton.is_valid()) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,skeleton.is_valid()); + rebind=true; + } + if (skeleton.is_valid()) { + RasterizerStorageGLES3::Skeleton *sk = storage->skeleton_owner.getornull(skeleton); + if (sk->size) { + glBindBufferBase(GL_UNIFORM_BUFFER,7,sk->ubo); + } + } + } if (material!=prev_material || rebind) { @@ -1495,6 +1509,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e prev_base_type=e->instance->base_type; prev_geometry=e->geometry; prev_shading=shading; + prev_skeleton=skeleton; first=false; } @@ -1504,6 +1519,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); glBindVertexArray(0); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); @@ -3469,6 +3485,10 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.add_custom_define("#define MAX_REFLECTION_DATA_STRUCTS "+itos(state.max_ubo_reflections)+"\n"); + state.max_skeleton_bones=max_ubo_size/(12*sizeof(float)); + state.scene_shader.add_custom_define("#define MAX_SKELETON_BONES "+itos(state.max_skeleton_bones)+"\n"); + + } GLOBAL_DEF("rendering/gles3/shadow_filter_mode",1); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 81c13bdc08c..31253e56b6c 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -98,6 +98,7 @@ public: int max_ubo_lights; int max_forward_lights_per_object; int max_ubo_reflections; + int max_skeleton_bones; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 669ab960367..c2598e458fd 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2416,12 +2416,15 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P if (! (p_format&(1<size==p_bones && skeleton->use_2d==p_2d_skeleton) + return; + + if (skeleton->ubo) { + glDeleteBuffers(1,&skeleton->ubo); + skeleton->ubo=0; + } + + skeleton->size=p_bones; + if (p_2d_skeleton) { + skeleton->bones.resize(p_bones*8); + for(int i=0;ibones.size();i+=8) { + skeleton->bones[i+0]=1; + skeleton->bones[i+1]=0; + skeleton->bones[i+2]=0; + skeleton->bones[i+3]=0; + skeleton->bones[i+4]=0; + skeleton->bones[i+5]=1; + skeleton->bones[i+6]=0; + skeleton->bones[i+7]=0; + } + + } else { + skeleton->bones.resize(p_bones*12); + for(int i=0;ibones.size();i+=12) { + skeleton->bones[i+0]=1; + skeleton->bones[i+1]=0; + skeleton->bones[i+2]=0; + skeleton->bones[i+3]=0; + skeleton->bones[i+4]=0; + skeleton->bones[i+5]=1; + skeleton->bones[i+6]=0; + skeleton->bones[i+7]=0; + skeleton->bones[i+8]=0; + skeleton->bones[i+9]=0; + skeleton->bones[i+10]=1; + skeleton->bones[i+11]=0; + } + + } + + + + if (p_bones) { + glGenBuffers(1, &skeleton->ubo); + glBindBuffer(GL_UNIFORM_BUFFER, skeleton->ubo); + glBufferData(GL_UNIFORM_BUFFER, skeleton->bones.size()*sizeof(float), NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + + if (!skeleton->update_list.in_list()) { + skeleton_update_list.add(&skeleton->update_list); + } + + skeleton->instance_change_notify(); + } int RasterizerStorageGLES3::skeleton_get_bone_count(RID p_skeleton) const{ - return 0; + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND_V(!skeleton,0); + + return skeleton->size; } + void RasterizerStorageGLES3::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 * bones = skeleton->bones.ptr(); + bones[p_bone*12+ 0]=p_transform.basis.elements[0][0]; + bones[p_bone*12+ 1]=p_transform.basis.elements[0][1]; + bones[p_bone*12+ 2]=p_transform.basis.elements[0][2]; + bones[p_bone*12+ 3]=p_transform.origin.x; + bones[p_bone*12+ 4]=p_transform.basis.elements[1][0]; + bones[p_bone*12+ 5]=p_transform.basis.elements[1][1]; + bones[p_bone*12+ 6]=p_transform.basis.elements[1][2]; + bones[p_bone*12+ 7]=p_transform.origin.y; + bones[p_bone*12+ 8]=p_transform.basis.elements[2][0]; + bones[p_bone*12+ 9]=p_transform.basis.elements[2][1]; + bones[p_bone*12+10]=p_transform.basis.elements[2][2]; + bones[p_bone*12+11]=p_transform.origin.z; + + if (!skeleton->update_list.in_list()) { + skeleton_update_list.add(&skeleton->update_list); + } } + + Transform RasterizerStorageGLES3::skeleton_bone_get_transform(RID p_skeleton,int p_bone) const{ - return Transform(); + 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()); + + float * bones = skeleton->bones.ptr(); + Transform mtx; + mtx.basis.elements[0][0]=bones[p_bone*12+ 0]; + mtx.basis.elements[0][1]=bones[p_bone*12+ 1]; + mtx.basis.elements[0][2]=bones[p_bone*12+ 2]; + mtx.origin.x=bones[p_bone*12+ 3]; + mtx.basis.elements[1][0]=bones[p_bone*12+ 4]; + mtx.basis.elements[1][1]=bones[p_bone*12+ 5]; + mtx.basis.elements[1][2]=bones[p_bone*12+ 6]; + mtx.origin.y=bones[p_bone*12+ 7]; + mtx.basis.elements[2][0]=bones[p_bone*12+ 8]; + mtx.basis.elements[2][1]=bones[p_bone*12+ 9]; + mtx.basis.elements[2][2]=bones[p_bone*12+10]; + mtx.origin.z=bones[p_bone*12+11]; + + return mtx; } void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton,int p_bone, const Matrix32& 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 * bones = skeleton->bones.ptr(); + bones[p_bone*12+ 0]=p_transform.elements[0][0]; + bones[p_bone*12+ 1]=p_transform.elements[1][0]; + bones[p_bone*12+ 2]=0; + bones[p_bone*12+ 3]=p_transform.elements[2][0]; + bones[p_bone*12+ 4]=p_transform.elements[0][1]; + bones[p_bone*12+ 5]=p_transform.elements[1][1]; + bones[p_bone*12+ 6]=0; + bones[p_bone*12+ 7]=p_transform.elements[2][1]; + + if (!skeleton->update_list.in_list()) { + skeleton_update_list.add(&skeleton->update_list); + } } Matrix32 RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton,int p_bone) const{ - return Matrix32(); + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + + ERR_FAIL_COND_V(!skeleton,Matrix32()); + ERR_FAIL_INDEX_V(p_bone,skeleton->size,Matrix32()); + ERR_FAIL_COND_V(!skeleton->use_2d,Matrix32()); + + Matrix32 mtx; + + float * bones = skeleton->bones.ptr(); + mtx.elements[0][0]=bones[p_bone*12+ 0]; + mtx.elements[1][0]=bones[p_bone*12+ 1]; + mtx.elements[2][0]=bones[p_bone*12+ 3]; + mtx.elements[0][1]=bones[p_bone*12+ 4]; + mtx.elements[1][1]=bones[p_bone*12+ 5]; + mtx.elements[2][1]=bones[p_bone*12+ 7]; + + return mtx; +} + +void RasterizerStorageGLES3::update_dirty_skeletons() { + + while(skeleton_update_list.first()) { + + Skeleton *skeleton = skeleton_update_list.first()->self(); + if (skeleton->size) { + glBindBuffer(GL_UNIFORM_BUFFER, skeleton->ubo); + glBufferSubData(GL_UNIFORM_BUFFER,0,skeleton->bones.size()*sizeof(float),skeleton->bones.ptr()); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + skeleton->instance_change_notify(); + + skeleton_update_list.remove(skeleton_update_list.first()); + } + } /* Light API */ @@ -3795,7 +3966,12 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: ERR_FAIL_COND(!inst); } break; default: { - ERR_FAIL(); + if (skeleton_owner.owns(p_base)) { + inst=skeleton_owner.getornull(p_base); + } + if (!inst) { + ERR_FAIL(); + } } } @@ -3821,7 +3997,12 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce ERR_FAIL_COND(!inst); } break; default: { - ERR_FAIL(); + if (skeleton_owner.owns(p_base)) { + inst=skeleton_owner.getornull(p_base); + } + if (!inst) { + ERR_FAIL(); + } } } @@ -4378,6 +4559,17 @@ bool RasterizerStorageGLES3::free(RID p_rid){ material_owner.free(p_rid); memdelete(material); + } else if (skeleton_owner.owns(p_rid)) { + + // delete the texture + Skeleton *skeleton = skeleton_owner.get(p_rid); + if (skeleton->update_list.in_list()) { + skeleton_update_list.remove(&skeleton->update_list); + } + skeleton_allocate(p_rid,0,false); + skeleton_owner.free(p_rid); + memdelete(skeleton); + } else if (mesh_owner.owns(p_rid)) { // delete the texture diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b433bcd517b..b5eacacb4ee 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -465,6 +465,7 @@ public: struct Attrib { bool enabled; + bool integer; GLuint index; GLint size; GLenum type; @@ -632,6 +633,26 @@ public: /* SKELETON API */ + struct Skeleton : Instantiable { + int size; + bool use_2d; + Vector bones; //4x3 or 4x2 depending on what is needed + GLuint ubo; + SelfList update_list; + + Skeleton() : update_list(this) { + size=0; + use_2d=false; + ubo=0; + } + }; + + mutable RID_Owner skeleton_owner; + + SelfList::List skeleton_update_list; + + void update_dirty_skeletons(); + virtual RID skeleton_create(); virtual void skeleton_allocate(RID p_skeleton,int p_bones,bool p_2d_skeleton=false); virtual int skeleton_get_bone_count(RID p_skeleton) const; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index aa8b3cacdce..f3dade9e509 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -22,17 +22,27 @@ ARRAY_INDEX=8, layout(location=0) in highp vec4 vertex_attrib; layout(location=1) in vec3 normal_attrib; +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) layout(location=2) in vec4 tangent_attrib; +#endif + +#if defined(ENABLE_COLOR_INTERP) layout(location=3) in vec4 color_attrib; +#endif + +#if defined(ENABLE_UV_INTERP) layout(location=4) in vec2 uv_attrib; +#endif + +#if defined(ENABLE_UV2_INTERP) layout(location=5) in vec2 uv2_attrib; +#endif uniform float normal_mult; #ifdef USE_SKELETON -layout(location=6) mediump ivec4 bone_indices; // attrib:6 -layout(location=7) mediump vec4 bone_weights; // attrib:7 -uniform highp sampler2D skeleton_matrices; +layout(location=6) in ivec4 bone_indices; // attrib:6 +layout(location=7) in vec4 bone_weights; // attrib:7 #endif #ifdef USE_ATTRIBUTE_INSTANCING @@ -140,6 +150,15 @@ out highp float dp_clip; #endif +#ifdef USE_SKELETON + +layout(std140) uniform SkeletonData { //ubo:7 + + mat3x4 skeleton[MAX_SKELETON_BONES]; +}; + +#endif + void main() { highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0); @@ -152,23 +171,25 @@ void main() { float binormalf = tangent_attrib.a; #endif + #ifdef USE_SKELETON { //skeleton transform - highp mat4 m=mat4(texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.x; - m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.y; - m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.z; - m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.w; + highp mat3x4 m=skeleton[bone_indices.x]*bone_weights.x; + m+=skeleton[bone_indices.y]*bone_weights.y; + m+=skeleton[bone_indices.z]*bone_weights.z; + m+=skeleton[bone_indices.w]*bone_weights.w; - vertex = vertex_in * m; - normal = (vec4(normal,0.0) * m).xyz; + vertex.xyz = vertex * m; + + normal = vec4(normal,0.0) * m; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - tangent = (vec4(tangent,0.0) * m).xyz; + tangent.xyz = vec4(tangent.xyz,0.0) * mn; #endif } +#endif // USE_SKELETON1 -#endif #if !defined(SKIP_TRANSFORM_USED) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 953448db52c..267a87930a5 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1007,12 +1007,26 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi } break; case VS::ARRAY_BONES: { - if (p_compress_format&ARRAY_FLAG_USE_16_BIT_BONES) { - elem_size=sizeof(uint32_t); - } else { - elem_size=sizeof(uint16_t)*4; + DVector bones = p_arrays[VS::ARRAY_BONES]; + int max_bone=0; + + { + int bc = bones.size(); + DVector::Read r=bones.read(); + for(int j=0;j 255) { + p_compress_format|=ARRAY_FLAG_USE_16_BIT_BONES; + elem_size=sizeof(uint16_t)*4; + } else { + p_compress_format&=~ARRAY_FLAG_USE_16_BIT_BONES; + elem_size=sizeof(uint32_t); + } + + } break; case VS::ARRAY_INDEX: { @@ -1043,7 +1057,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi } uint32_t mask = (1<