diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-10-14 01:01:25 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-10-14 01:01:25 -0300 |
commit | a84ba9c853f972f8e666b17f3e0f875b7282e6c1 (patch) | |
tree | 70a5d44acbecc93011333d13dd51b1786d42eae3 | |
parent | 13a848e332092b40956739a08fa0dac3357db950 (diff) |
Collada
-=-=-=-
-Fixed some DAE import & export bugs
-Changed Collada exporter to use the mesh loops API
-Added tangent export to Collada exporter
-Added triangulation option to Collada exporter
-Changed a little how normalmaps are handled in shader. Not sure if it's working properly, be careful.
-Fixed some strange bug with kinematic bodies #776
-Fix release compilaiton issues #782
25 files changed, 349 insertions, 184 deletions
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index d9771dadf2..d596aad4b9 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -4419,7 +4419,7 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const { enablers.push_back("#define ENABLE_UV_INTERP\n"); if (fragment_flags.use_uv2_interp || vertex_flags.use_uv2_interp) enablers.push_back("#define ENABLE_UV2_INTERP\n"); - if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp) + if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp || fragment_flags.uses_normalmap) enablers.push_back("#define ENABLE_TANGENT_INTERP\n"); if (fragment_flags.use_var1_interp || vertex_flags.use_var1_interp) enablers.push_back("#define ENABLE_VAR1_INTERP\n"); @@ -4434,6 +4434,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const { if (fragment_flags.uses_discard) { enablers.push_back("#define ENABLE_DISCARD\n"); } + if (fragment_flags.uses_normalmap) { + enablers.push_back("#define ENABLE_NORMALMAP\n"); + } if (light_flags.uses_light) { enablers.push_back("#define USE_LIGHT_SHADER_CODE\n"); } diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index ada9efa4b3..5457a869af 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -176,6 +176,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a if (vnode->name==vname_discard) { uses_discard=true; } + if (vnode->name==vname_normalmap) { + uses_normalmap=true; + } if (vnode->name==vname_screen_uv) { uses_screen_uv=true; } @@ -546,6 +549,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT uses_screen_uv=false; uses_light=false; uses_time=false; + uses_normalmap=false; vertex_code_writes_vertex=false; uniforms=r_uniforms; flags=&r_flags; @@ -555,6 +559,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT r_flags.use_tangent_interp=false; r_flags.use_var1_interp=false; r_flags.use_var2_interp=false; + r_flags.uses_normalmap=false; String error; int errline,errcol; @@ -576,8 +581,10 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT r_flags.uses_screen_uv=uses_screen_uv; r_flags.uses_light=uses_light; r_flags.uses_time=uses_time; + r_flags.uses_normalmap=uses_normalmap; r_code_line=code; r_globals_line=global_code; + return OK; } @@ -670,6 +677,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { mode_replace_table[1]["NORMAL"]="normal"; mode_replace_table[1]["TANGENT"]="tangent"; mode_replace_table[1]["BINORMAL"]="binormal"; + mode_replace_table[1]["NORMALMAP"]="normalmap"; mode_replace_table[1]["VAR1"]="var1_interp"; mode_replace_table[1]["VAR2"]="var2_interp"; mode_replace_table[1]["UV"]="uv"; @@ -728,5 +736,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { vname_vertex="VERTEX"; vname_light="LIGHT"; vname_time="TIME"; + vname_normalmap="NORMALMAP"; } diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 3dfdd81c0d..5012414c8b 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -50,6 +50,7 @@ private: bool uses_discard; bool uses_time; bool uses_screen_uv; + bool uses_normalmap; bool vertex_code_writes_vertex; Flags *flags; @@ -66,6 +67,7 @@ private: StringName vname_vertex; StringName vname_light; StringName vname_time; + StringName vname_normalmap; Map<StringName,ShaderLanguage::Uniform> *uniforms; @@ -87,6 +89,7 @@ public: bool uses_alpha; bool uses_texscreen; bool uses_texpos; + bool uses_normalmap; bool vertex_code_writes_vertex; bool uses_discard; bool uses_screen_uv; diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl index 63ff4a5f47..bf82822378 100644 --- a/drivers/gles2/shaders/material.glsl +++ b/drivers/gles2/shaders/material.glsl @@ -819,6 +819,10 @@ void main() { vec4 color = color_interp; #endif +#if defined(ENABLE_NORMALMAP) + + vec3 normalmap = vec3(0.0); +#endif @@ -833,6 +837,11 @@ FRAGMENT_SHADER_CODE } +#if defined(ENABLE_NORMALMAP) + + normal = normalize( tangent_interp * normalmap.x + binormal_interp * normalmap.y + normal_interp * normalmap.z ) * side; +#endif + #if defined(ENABLE_DISCARD) if (discard_) { //easy to eliminate dead code diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 7678cb980c..22dbd157b7 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -925,6 +925,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { normal=rest_info.normal; collider=rest_info.collider_id; collider_vel=rest_info.linear_velocity; + collider_shape=rest_info.shape; } } @@ -1013,6 +1014,12 @@ ObjectID KinematicBody2D::get_collider() const { return collider; } + +int KinematicBody2D::get_collider_shape() const { + + ERR_FAIL_COND_V(!colliding,0); + return collider_shape; +} void KinematicBody2D::set_collide_with_static_bodies(bool p_enable) { collide_static=p_enable; @@ -1076,6 +1083,7 @@ void KinematicBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody2D::get_collision_normal); ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody2D::get_collider_velocity); ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::_get_collider); + ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape); ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody2D::set_collide_with_static_bodies); @@ -1112,6 +1120,8 @@ KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KI colliding=false; collider=0; + collider_shape=0; + margin=0.08; } KinematicBody2D::~KinematicBody2D() { diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index b2625c3d97..2771aa6aa4 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -254,7 +254,7 @@ class KinematicBody2D : public PhysicsBody2D { Vector2 normal; Vector2 collider_vel; ObjectID collider; - + int collider_shape; Variant _get_collider() const; @@ -273,6 +273,7 @@ public: Vector2 get_collision_normal() const; Vector2 get_collider_velocity() const; ObjectID get_collider() const; + int get_collider_shape() const; void set_collide_with_static_bodies(bool p_enable); bool can_collide_with_static_bodies() const; diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 7713a262ef..6cf50450ac 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -435,15 +435,20 @@ void Light::_update_visibility() { if (!is_inside_scene()) return; + + +#ifdef TOOLS_ENABLED bool editor_ok=true; if (editor_only) { - if (!get_scene()->is_editor_hint()) { editor_ok=false; } else { editor_ok = (get_scene()->get_edited_scene_root() && (this==get_scene()->get_edited_scene_root() || get_owner()==get_scene()->get_edited_scene_root())); } } +#else + bool editor_ok=false; +#endif VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible() && enabled && editor_ok); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 831e1c95c2..15ec60514a 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -967,6 +967,7 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { normal=rest.normal; collider=rest.collider_id; collider_vel=rest.linear_velocity; + collider_shape=rest.shape; } } @@ -1055,7 +1056,12 @@ ObjectID KinematicBody::get_collider() const { ERR_FAIL_COND_V(!colliding,0); return collider; } +int KinematicBody::get_collider_shape() const { + ERR_FAIL_COND_V(!colliding,-1); + return collider_shape; + +} void KinematicBody::set_collide_with_static_bodies(bool p_enable) { collide_static=p_enable; @@ -1119,6 +1125,7 @@ void KinematicBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody::get_collision_normal); ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody::get_collider_velocity); ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody::_get_collider); + ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody::get_collider_shape); ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody::set_collide_with_static_bodies); @@ -1155,6 +1162,7 @@ KinematicBody::KinematicBody() : PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC) colliding=false; collider=0; margin=0.001; + collider_shape=0; } KinematicBody::~KinematicBody() { diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 951aaf4da3..1615fdd1d4 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -266,6 +266,7 @@ class KinematicBody : public PhysicsBody { Vector3 normal; Vector3 collider_vel; ObjectID collider; + int collider_shape; Variant _get_collider() const; @@ -291,6 +292,7 @@ public: Vector3 get_collision_normal() const; Vector3 get_collider_velocity() const; ObjectID get_collider() const; + int get_collider_shape() const; void set_collide_with_static_bodies(bool p_enable); bool can_collide_with_static_bodies() const; diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index cbaa76e0ca..c51974167d 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -1085,7 +1085,9 @@ SceneMainLoop::SceneMainLoop() { root->set_physics_object_picking(GLOBAL_DEF("physics/enable_object_picking",true)); +#ifdef TOOLS_ENABLED edited_scene_root=NULL; +#endif ADD_SIGNAL( MethodInfo("idle_frame")); ADD_SIGNAL( MethodInfo("fixed_frame")); diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index deef9d5876..8e80f868c6 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -37,9 +37,10 @@ void Timer::_notification(int p_what) { case NOTIFICATION_READY: { if (autostart) { - if (get_scene()->is_editor_hint() && get_scene()->get_edited_scene_root() && (get_scene()->get_edited_scene_root()==this || get_scene()->get_edited_scene_root()->is_a_parent_of(this))) +#ifdef TOOLS_ENABLED + if (get_scene()->is_editor_hint() && get_scene()->get_edited_scene_root() && (get_scene()->get_edited_scene_root()==this || get_scene()->get_edited_scene_root()->is_a_parent_of(this))) break; - start(); +#endif start(); } } break; case NOTIFICATION_PROCESS: { diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index c6e492fcb3..3aeccdc551 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -29,6 +29,7 @@ #include "mesh.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" +#include "surface_tool.h" static const char*_array_name[]={ "vertex_array", @@ -648,6 +649,30 @@ void Mesh::center_geometry() { } +void Mesh::regen_normalmaps() { + + + Vector< Ref<SurfaceTool> > surfs; + for(int i=0;i<get_surface_count();i++) { + + Ref<SurfaceTool> st = memnew( SurfaceTool ); + st->create_from(Ref<Mesh>(this),i); + surfs.push_back(st); + } + + while (get_surface_count()) { + surface_remove(0); + } + + for(int i=0;i<surfs.size();i++) { + + surfs[i]->generate_tangents(); + surfs[i]->commit(Ref<Mesh>(this)); + } +} + + + Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) @@ -740,6 +765,8 @@ void Mesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("surface_get_name","surf_idx"),&Mesh::surface_get_name); ObjectTypeDB::bind_method(_MD("center_geometry"),&Mesh::center_geometry); ObjectTypeDB::set_method_flags(get_type_static(),_SCS("center_geometry"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::bind_method(_MD("regen_normalmaps"),&Mesh::regen_normalmaps); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("regen_normalmaps"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); ObjectTypeDB::bind_method(_MD("set_custom_aabb","aabb"),&Mesh::set_custom_aabb); ObjectTypeDB::bind_method(_MD("get_custom_aabb"),&Mesh::get_custom_aabb); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 5243163a4d..d6ab6a1198 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -167,6 +167,7 @@ public: Ref<Shape> create_convex_shape() const; void center_geometry(); + void regen_normalmaps(); DVector<Face3> get_faces() const; Ref<TriangleMesh> generate_triangle_mesh() const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 2856101674..dd39205932 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -105,7 +105,7 @@ void SurfaceTool::add_vertex( const Vector3& p_vertex) { vtx.weights=last_weights; vtx.bones=last_bones; vtx.tangent=last_tangent.normal; - vtx.binormal=last_tangent.normal.cross(last_normal).normalized() * last_tangent.d; + vtx.binormal=last_normal.cross(last_tangent.normal).normalized() * last_tangent.d; vertex_array.push_back(vtx); first=false; format|=Mesh::ARRAY_FORMAT_VERTEX; @@ -299,7 +299,9 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) { w[idx+0]=v.tangent.x; w[idx+1]=v.tangent.y; w[idx+2]=v.tangent.z; - float d = v.binormal.dot(v.normal.cross(v.tangent)); + + //float d = v.tangent.dot(v.binormal,v.normal); + float d = v.binormal.dot( v.normal.cross(v.tangent)); w[idx+3]=d<0 ? -1 : 1; } @@ -565,6 +567,7 @@ void SurfaceTool::create_from(const Ref<Mesh>& p_existing, int p_surface) { clear(); primitive=p_existing->surface_get_primitive_type(p_surface); _create_list(p_existing,p_surface,&vertex_array,&index_array,format); + material=p_existing->surface_get_material(p_surface); } @@ -611,165 +614,96 @@ void SurfaceTool::append_from(const Ref<Mesh>& p_existing, int p_surface,const T } +//mikktspace callbacks +int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext * pContext) { -void SurfaceTool::generate_tangents() { - - ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV)); - ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL)); - - - if (index_array.size()) { - - Vector<List<Vertex>::Element*> vtx; - vtx.resize(vertex_array.size()); - int idx=0; - for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) { - vtx[idx++]=E; - E->get().binormal=Vector3(); - E->get().tangent=Vector3(); - } - - for (List<int>::Element *E=index_array.front();E;) { - - int i[3]; - i[0]=E->get(); - E=E->next(); - ERR_FAIL_COND(!E); - i[1]=E->get(); - E=E->next(); - ERR_FAIL_COND(!E); - i[2]=E->get(); - E=E->next(); - ERR_FAIL_COND(!E); - - - Vector3 v1 = vtx[ i[0] ]->get().vertex; - Vector3 v2 = vtx[ i[1] ]->get().vertex; - Vector3 v3 = vtx[ i[2] ]->get().vertex; - - Vector2 w1 = vtx[ i[0] ]->get().uv; - Vector2 w2 = vtx[ i[1] ]->get().uv; - Vector2 w3 = vtx[ i[2] ]->get().uv; - - - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - float z1 = v2.z - v1.z; - float z2 = v3.z - v1.z; - - float s1 = w2.x - w1.x; - float s2 = w3.x - w1.x; - float t1 = w2.y - w1.y; - float t2 = w3.y - w1.y; - - float r = (s1 * t2 - s2 * t1); - - Vector3 binormal,tangent; - - if (r==0) { - binormal=Vector3(0,0,0); - tangent=Vector3(0,0,0); - } else { - tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, - (t2 * z1 - t1 * z2) * r); - binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, - (s1 * z2 - s2 * z1) * r); - } - - tangent.normalize(); - binormal.normalize(); - Vector3 normal=Plane( v1, v2, v3 ).normal; - - Vector3 tangentp = tangent - normal * normal.dot( tangent ); - Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal)); - - tangentp.normalize(); - binormalp.normalize(); + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + return varr.size()/3; +} +int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace){ + return 3; //always 3 +} +void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert){ - for (int j=0;j<3;j++) { - vtx[ i[j] ]->get().binormal+=binormalp; - vtx[ i[j] ]->get().tangent+=tangentp; + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vector3 v = varr[iFace*3+iVert]->get().vertex; + fvPosOut[0]=v.x; + fvPosOut[1]=v.y; + fvPosOut[2]=v.z; - } - } - for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) { - E->get().binormal.normalize(); - E->get().tangent.normalize(); - } +} +void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert){ - } else { + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vector3 v = varr[iFace*3+iVert]->get().normal; + fvNormOut[0]=v.x; + fvNormOut[1]=v.y; + fvNormOut[2]=v.z; - for (List<Vertex>::Element *E=vertex_array.front();E;) { +} +void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert){ - List< Vertex >::Element *v[3]; - v[0]=E; - v[1]=v[0]->next(); - ERR_FAIL_COND(!v[1]); - v[2]=v[1]->next(); - ERR_FAIL_COND(!v[2]); - E=v[2]->next(); + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vector2 v = varr[iFace*3+iVert]->get().uv; + fvTexcOut[0]=v.x; + //fvTexcOut[1]=v.y; + fvTexcOut[1]=1.0-v.y; - Vector3 v1 = v[0]->get().vertex; - Vector3 v2 = v[1]->get().vertex; - Vector3 v3 = v[2]->get().vertex; +} +void SurfaceTool::mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){ - Vector2 w1 = v[0]->get().uv; - Vector2 w2 = v[1]->get().uv; - Vector2 w3 = v[2]->get().uv; + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vertex &vtx = varr[iFace*3+iVert]->get(); + vtx.tangent = Vector3(fvTangent[0],fvTangent[1],fvTangent[2]); + vtx.binormal = vtx.normal.cross(vtx.tangent) * fSign; +} - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - float z1 = v2.z - v1.z; - float z2 = v3.z - v1.z; - float s1 = w2.x - w1.x; - float s2 = w3.x - w1.x; - float t1 = w2.y - w1.y; - float t2 = w3.y - w1.y; +void SurfaceTool::generate_tangents() { - float r = (s1 * t2 - s2 * t1); + ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV)); + ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL)); - Vector3 binormal,tangent; + bool indexed = index_array.size()>0; + if (indexed) + deindex(); - if (r==0) { - binormal=Vector3(0,0,0); - tangent=Vector3(0,0,0); - } else { - tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, - (t2 * z1 - t1 * z2) * r); - binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, - (s1 * z2 - s2 * z1) * r); - } - tangent.normalize(); - binormal.normalize(); - Vector3 normal=Plane( v1, v2, v3 ).normal; + SMikkTSpaceInterface mkif; + mkif.m_getNormal=mikktGetNormal; + mkif.m_getNumFaces=mikktGetNumFaces; + mkif.m_getNumVerticesOfFace=mikktGetNumVerticesOfFace; + mkif.m_getPosition=mikktGetPosition; + mkif.m_getTexCoord=mikktGetTexCoord; + mkif.m_setTSpaceBasic=mikktSetTSpaceBasic; + mkif.m_setTSpace=NULL; - Vector3 tangentp = tangent - normal * normal.dot( tangent ); - Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal)); + SMikkTSpaceContext msc; + msc.m_pInterface=&mkif; - tangentp.normalize(); - binormalp.normalize(); + Vector<List<Vertex>::Element*> vtx; + vtx.resize(vertex_array.size()); + int idx=0; + for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) { + vtx[idx++]=E; + E->get().binormal=Vector3(); + E->get().tangent=Vector3(); + } + msc.m_pUserData=&vtx; + bool res = genTangSpaceDefault(&msc); - for (int j=0;j<3;j++) { - v[j]->get().binormal=binormalp; - v[j]->get().tangent=tangentp; + ERR_FAIL_COND(!res); + format|=Mesh::ARRAY_FORMAT_TANGENT; - } - } - } + if (indexed) + index(); - format|=Mesh::ARRAY_FORMAT_TANGENT; } diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index fe82d3a4ce..fc5940145b 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -30,7 +30,7 @@ #define SURFACE_TOOL_H #include "scene/resources/mesh.h" - +#include "mikktspace.h" class SurfaceTool : public Reference { @@ -82,6 +82,14 @@ private: void _create_list(const Ref<Mesh>& p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index,int &lformat); + + //mikktspace callbacks + static int mikktGetNumFaces(const SMikkTSpaceContext * pContext); + static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace); + static void mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + static void mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + static void mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + static void mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); protected: static void _bind_methods(); diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 73441882fb..725a440b59 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -185,6 +185,7 @@ float BodySW::get_param(PhysicsServer::BodyParameter p_param) const { void BodySW::set_mode(PhysicsServer::BodyMode p_mode) { + PhysicsServer::BodyMode prev=mode; mode=p_mode; switch(p_mode) { @@ -199,6 +200,10 @@ void BodySW::set_mode(PhysicsServer::BodyMode p_mode) { set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC && contacts.size()); linear_velocity=Vector3(); angular_velocity=Vector3(); + if (mode==PhysicsServer::BODY_MODE_KINEMATIC && prev!=mode) { + first_time_kinematic=true; + } + } break; case PhysicsServer::BODY_MODE_RIGID: { @@ -238,6 +243,11 @@ void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant& p_varian new_transform=p_variant; //wakeup_neighbours(); set_active(true); + if (first_time_kinematic) { + _set_transform(p_variant); + _set_inv_transform(get_transform().affine_inverse()); + first_time_kinematic=false; + } } else if (mode==PhysicsServer::BODY_MODE_STATIC) { _set_transform(p_variant); @@ -669,6 +679,7 @@ BodySW::BodySW() : CollisionObjectSW(TYPE_BODY), active_list(this), inertia_upda island_step=0; island_next=NULL; island_list_next=NULL; + first_time_kinematic=false; _set_static(false); density=0; contact_count=0; diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index f152c4754a..ee3c76e455 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -74,6 +74,7 @@ class BodySW : public CollisionObjectSW { bool continuous_cd; bool can_sleep; + bool first_time_kinematic; void _update_inertia(); virtual void _shapes_changed(); Transform new_transform; diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index e90faa3efb..fbad19f6be 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -176,6 +176,7 @@ float Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const { void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) { + Physics2DServer::BodyMode prev=mode; mode=p_mode; switch(p_mode) { @@ -189,6 +190,9 @@ void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) { set_active(p_mode==Physics2DServer::BODY_MODE_KINEMATIC && contacts.size()); linear_velocity=Vector2(); angular_velocity=0; + if (mode==Physics2DServer::BODY_MODE_KINEMATIC && prev!=mode) { + first_time_kinematic=true; + } } break; case Physics2DServer::BODY_MODE_RIGID: { @@ -226,9 +230,15 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant& p_va if (mode==Physics2DServer::BODY_MODE_KINEMATIC) { - new_transform=p_variant; + + new_transform=p_variant; //wakeup_neighbours(); set_active(true); + if (first_time_kinematic) { + _set_transform(p_variant); + _set_inv_transform(get_transform().affine_inverse()); + first_time_kinematic=false; + } } else if (mode==Physics2DServer::BODY_MODE_STATIC) { _set_transform(p_variant); _set_inv_transform(get_transform().affine_inverse()); @@ -591,6 +601,7 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti island_next=NULL; island_list_next=NULL; _set_static(false); + first_time_kinematic=false; density=0; contact_count=0; diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index cf4d5c92f2..7bf17023ac 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -72,6 +72,7 @@ class Body2DSW : public CollisionObject2DSW { bool omit_force_integration; bool active; bool can_sleep; + bool first_time_kinematic; void _update_inertia(); virtual void _shapes_changed(); Matrix32 new_transform; diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp index 643968796b..64247c1f2a 100644 --- a/servers/visual/rasterizer.cpp +++ b/servers/visual/rasterizer.cpp @@ -98,11 +98,10 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) { } if (p_key.use_xy_normalmap) { scode+="vec2 ywnormal=tex( fmp_normal_tex,"+uv_str+").wy * vec2(2.0,2.0) - vec2(1.0,1.0);\n"; - scode+="vec3 normal=vec3(ywnormal,sqrt(1 - (ywnormal.x * ywnormal.x) - (ywnormal.y * ywnormal.y) ));\n"; + scode+="NORMALMAP=vec3(ywnormal,sqrt(1 - (ywnormal.x * ywnormal.x) - (ywnormal.y * ywnormal.y) ));\n"; } else { - scode+="vec3 normal=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n"; + scode+="NORMALMAP=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n"; } - scode+="NORMAL = mix( NORMAL,mat3(TANGENT,BINORMAL,NORMAL) * normal, fmp_normal);\n"; code+=scode; } diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 14d35e89b1..49420b51c0 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -1042,6 +1042,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::fragment_builtins_defs[]={ { "NORMAL", TYPE_VEC3}, { "TANGENT", TYPE_VEC3}, { "BINORMAL", TYPE_VEC3}, + { "NORMALMAP", TYPE_VEC3}, { "UV", TYPE_VEC2}, { "UV2", TYPE_VEC2}, { "COLOR", TYPE_VEC4}, diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index ffd90cc8a3..405f8a01e8 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -749,7 +749,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co Vector3 tangent =Vector3(tangent_src->array[tangent_pos+0],tangent_src->array[tangent_pos+1],tangent_src->array[tangent_pos+2]); vertex.tangent.normal=tangent; - vertex.tangent.d= vertex.normal.cross(tangent).dot(binormal) > 0 ? -1 : 1; + vertex.tangent.d= vertex.normal.cross(tangent).dot(binormal) > 0 ? 1 : -1; } } @@ -784,6 +784,8 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co vertex.vertex.z = -vertex.vertex.z; SWAP( vertex.normal.z, vertex.normal.y ); vertex.normal.z = -vertex.normal.z; + SWAP( vertex.tangent.normal.z, vertex.tangent.normal.y ); + vertex.tangent.normal.z = -vertex.tangent.normal.z; } diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 8f3f4dea8e..e5f33b3d41 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -2468,7 +2468,7 @@ void SpatialEditor::set_state(const Dictionary& p_state) { } if (d.has("default_srgb")) { - bool use = d["default_light"]; + bool use = d["default_srgb"]; viewport_environment->set_enable_fx(Environment::FX_SRGB,use); view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB), use ); diff --git a/tools/export/blender25/io_scene_dae/__init__.py b/tools/export/blender25/io_scene_dae/__init__.py index d0d286211e..b3e3f70cf0 100644 --- a/tools/export/blender25/io_scene_dae/__init__.py +++ b/tools/export/blender25/io_scene_dae/__init__.py @@ -83,6 +83,17 @@ class ExportDAE(bpy.types.Operator, ExportHelper): description="Apply modifiers to mesh objects (on a copy!).", default=True, ) + use_tangent_arrays = BoolProperty( + name="Tangent Arrays", + description="Export Tangent and Binormal arrays (for normalmapping).", + default=False, + ) + use_triangles = BoolProperty( + name="Triangulate", + description="Export Triangles instead of Polygons.", + default=False, + ) + use_copy_images = BoolProperty( name="Copy Images", description="Copy Images (create images/ subfolder)", @@ -118,6 +129,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper): description="Remove double keyframes", default=True, ) + anim_optimize_precision = FloatProperty( name="Precision", description=("Tolerence for comparing double keyframes " @@ -126,6 +138,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper): soft_min=1, soft_max=16, default=6.0, ) + use_metadata = BoolProperty( name="Use Metadata", default=True, diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py index cc5865080b..74376eff01 100644 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ b/tools/export/blender25/io_scene_dae/export_dae.py @@ -43,6 +43,7 @@ import time import math # math.pi import shutil import bpy +import bmesh from mathutils import Vector, Matrix #according to collada spec, order matters @@ -125,6 +126,12 @@ class DaeExporter: tup = (self.vertex.x,self.vertex.y,self.vertex.z,self.normal.x,self.normal.y,self.normal.z) for t in self.uv: tup = tup + (t.x,t.y) + if (self.color!=None): + tup = tup + (self.color.x,self.color.y,self.color.z) + if (self.tangent!=None): + tup = tup + (self.tangent.x,self.tangent.y,self.tangent.z) + if (self.bitangent!=None): + tup = tup + (self.bitangent.x,self.bitangent.y,self.bitangent.z) #for t in self.bones: # tup = tup + (t) #for t in self.weights: @@ -135,7 +142,9 @@ class DaeExporter: def __init__(self): self.vertex = Vector( (0.0,0.0,0.0) ) self.normal = Vector( (0.0,0.0,0.0) ) - self.color = Vector( (0.0,0.0,0.0) ) + self.tangent = None + self.bitangent = None + self.color = None self.uv = [] self.uv2 = Vector( (0.0,0.0) ) self.bones=[] @@ -442,10 +451,18 @@ class DaeExporter: self.mesh_cache[node.data]=meshdata return meshdata - if (len(node.modifiers) and self.config["use_mesh_modifiers"]): - mesh=node.to_mesh(self.scene,True,"RENDER") #is this allright? - else: - mesh=node.data + apply_modifiers = len(node.modifiers) and self.config["use_mesh_modifiers"] + + mesh=node.to_mesh(self.scene,apply_modifiers,"RENDER") #is this allright? + + triangulate=self.config["use_triangles"] + if (triangulate): + bm = bmesh.new() + bm.from_mesh(mesh) + bmesh.ops.triangulate(bm, faces=bm.faces) + bm.to_mesh(mesh) + bm.free() + mesh.update(calc_tessface=True) vertices=[] @@ -462,20 +479,22 @@ class DaeExporter: has_uv=False has_uv2=False has_weights=armature!=None - has_colors=False + has_tangents=self.config["use_tangent_arrays"] # could detect.. + has_colors=len(mesh.vertex_colors) mat_assign=[] uv_layer_count=len(mesh.uv_textures) + mesh.calc_tangents() + - for fi in range(len(mesh.tessfaces)): - f=mesh.tessfaces[fi] + for fi in range(len(mesh.polygons)): + f=mesh.polygons[fi] if (not (f.material_index in surface_indices)): surface_indices[f.material_index]=[] print("Type: "+str(type(f.material_index))) print("IDX: "+str(f.material_index)+"/"+str(len(mesh.materials))) - try: #Bizarre blender behavior i don't understand, so catching exception mat = mesh.materials[f.material_index] @@ -489,35 +508,42 @@ class DaeExporter: indices = surface_indices[f.material_index] vi=[] - #make triangles always + #vertices always 3 + """ if (len(f.vertices)==3): vi.append(0) vi.append(1) vi.append(2) elif (len(f.vertices)==4): + #todo, should use shortest path vi.append(0) vi.append(1) vi.append(2) vi.append(0) vi.append(2) vi.append(3) + """ - for x in vi: - mv = mesh.vertices[f.vertices[x]] + for lt in range(f.loop_total): + loop_index = f.loop_start + lt + ml = mesh.loops[loop_index] + mv = mesh.vertices[ml.vertex_index] v = self.Vertex() v.vertex = Vector( mv.co ) - for xt in mesh.tessface_uv_textures: - d = xt.data[fi] - uvsrc = [d.uv1,d.uv2,d.uv3,d.uv4] - v.uv.append( Vector( uvsrc[x] ) ) + for xt in mesh.uv_layers: + v.uv.append( Vector( xt.data[loop_index].uv ) ) + if (has_colors): + v.color = Vector( mesh.vertex_colors[0].data[loop_index].color ) + + v.normal = Vector( ml.normal ) + + if (has_tangents): + v.tangent = Vector( ml.tangent ) + v.bitangent = Vector( ml.bitangent ) - if (f.use_smooth): - v.normal=Vector( mv.normal ) - else: - v.normal=Vector( f.normal ) # if (armature): # v.vertex = node.matrix_world * v.vertex @@ -531,6 +557,7 @@ class DaeExporter: continue; name = node.vertex_groups[vg.group].name if (name in si["bone_index"]): + #could still put the weight as 0.0001 maybe if (vg.weight>0.001): #blender has a lot of zero weight stuff v.bones.append(si["bone_index"][name]) v.weights.append(vg.weight) @@ -546,7 +573,11 @@ class DaeExporter: vertices.append(v) vertex_map[tup]=idx - indices.append(idx) + vi.append(idx) + + if (len(vi)>2): + #only triangles and above + indices.append(vi) meshid = self.new_id("mesh") @@ -586,6 +617,37 @@ class DaeExporter: self.writel(S_GEOM,4,'</technique_common>') self.writel(S_GEOM,3,'</source>') + if (has_tangents): + self.writel(S_GEOM,3,'<source id="'+meshid+'-tangents">') + float_values="" + for v in vertices: + float_values+=" "+str(v.tangent.x)+" "+str(v.tangent.y)+" "+str(v.tangent.z) + self.writel(S_GEOM,4,'<float_array id="'+meshid+'-tangents-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>') + self.writel(S_GEOM,4,'<technique_common>') + self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-tangents-array" count="'+str(len(vertices))+'" stride="3">') + self.writel(S_GEOM,5,'<param name="X" type="float"/>') + self.writel(S_GEOM,5,'<param name="Y" type="float"/>') + self.writel(S_GEOM,5,'<param name="Z" type="float"/>') + self.writel(S_GEOM,4,'</accessor>') + self.writel(S_GEOM,4,'</technique_common>') + self.writel(S_GEOM,3,'</source>') + + self.writel(S_GEOM,3,'<source id="'+meshid+'-bitangents">') + float_values="" + for v in vertices: + float_values+=" "+str(v.bitangent.x)+" "+str(v.bitangent.y)+" "+str(v.bitangent.z) + self.writel(S_GEOM,4,'<float_array id="'+meshid+'-bitangents-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>') + self.writel(S_GEOM,4,'<technique_common>') + self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-bitangents-array" count="'+str(len(vertices))+'" stride="3">') + self.writel(S_GEOM,5,'<param name="X" type="float"/>') + self.writel(S_GEOM,5,'<param name="Y" type="float"/>') + self.writel(S_GEOM,5,'<param name="Z" type="float"/>') + self.writel(S_GEOM,4,'</accessor>') + self.writel(S_GEOM,4,'</technique_common>') + self.writel(S_GEOM,3,'</source>') + + + # UV Arrays for uvi in range(uv_layer_count): @@ -608,36 +670,75 @@ class DaeExporter: self.writel(S_GEOM,4,'</technique_common>') self.writel(S_GEOM,3,'</source>') + # Color Arrays + + if (has_colors): + self.writel(S_GEOM,3,'<source id="'+meshid+'-colors">') + float_values="" + for v in vertices: + float_values+=" "+str(v.color.x)+" "+str(v.color.y)+" "+str(v.color.z) + self.writel(S_GEOM,4,'<float_array id="'+meshid+'-colors-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>') + self.writel(S_GEOM,4,'<technique_common>') + self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-colors-array" count="'+str(len(vertices))+'" stride="3">') + self.writel(S_GEOM,5,'<param name="X" type="float"/>') + self.writel(S_GEOM,5,'<param name="Y" type="float"/>') + self.writel(S_GEOM,5,'<param name="Z" type="float"/>') + self.writel(S_GEOM,4,'</accessor>') + self.writel(S_GEOM,4,'</technique_common>') + self.writel(S_GEOM,3,'</source>') + # Triangle Lists self.writel(S_GEOM,3,'<vertices id="'+meshid+'-vertices">') self.writel(S_GEOM,4,'<input semantic="POSITION" source="#'+meshid+'-positions"/>') self.writel(S_GEOM,3,'</vertices>') + prim_type="" + if (triangulate): + prim_type="triangles" + else: + prim_type="polygons" + + for m in surface_indices: indices = surface_indices[m] mat = materials[m] + if (mat!=None): matref = self.new_id("trimat") - self.writel(S_GEOM,3,'<triangles count="'+str(int(len(indices)/3))+'" material="'+matref+'">') # todo material + self.writel(S_GEOM,3,'<'+prim_type+' count="'+str(int(len(indices)))+'" material="'+matref+'">') # todo material mat_assign.append( (mat,matref) ) else: - self.writel(S_GEOM,3,'<triangles count="'+str(int(len(indices)/3))+'">') # todo material + self.writel(S_GEOM,3,'<'+prim_type+' count="'+str(int(len(indices)))+'">') # todo material + + self.writel(S_GEOM,4,'<input semantic="VERTEX" source="#'+meshid+'-vertices" offset="0"/>') - self.writel(S_GEOM,4,'<input semantic="NORMAL" source="#'+meshid+'-normals" offset="1"/>') - extra_indices=0 + self.writel(S_GEOM,4,'<input semantic="NORMAL" source="#'+meshid+'-normals" offset="0"/>') + for uvi in range(uv_layer_count): - self.writel(S_GEOM,4,'<input semantic="TEXCOORD" source="#'+meshid+'-texcoord-'+str(uvi)+'" offset="'+str(2+uvi)+'" set="'+str(uvi)+'"/>') - extra_indices+=1 + self.writel(S_GEOM,4,'<input semantic="TEXCOORD" source="#'+meshid+'-texcoord-'+str(uvi)+'" offset="0" set="'+str(uvi)+'"/>') + + if (has_colors): + self.writel(S_GEOM,4,'<input semantic="COLOR" source="#'+meshid+'-colors" offset="0"/>') + if (has_tangents): + self.writel(S_GEOM,4,'<input semantic="TEXTANGENT" source="#'+meshid+'-tangents" offset="0"/>') + self.writel(S_GEOM,4,'<input semantic="TEXBINORMAL" source="#'+meshid+'-bitangents" offset="0"/>') + + if (triangulate): + int_values="<p>" + for p in indices: + for i in p: + int_values+=" "+str(i) + int_values+=" </p>" + self.writel(S_GEOM,4,int_values) + else: + for p in indices: + int_values="<p>" + for i in p: + int_values+=" "+str(i) + int_values+=" </p>" + self.writel(S_GEOM,4,int_values) - int_values="<p>" - for i in range(len(indices)): - int_values+=" "+str(indices[i]) # vertex index - int_values+=" "+str(indices[i]) # normal index - for e in range(extra_indices): - int_values+=" "+str(indices[i]) # normal index - int_values+="</p>" - self.writel(S_GEOM,4,int_values) - self.writel(S_GEOM,3,'</triangles>') + self.writel(S_GEOM,3,'</'+prim_type+'>') self.writel(S_GEOM,2,'</mesh>') @@ -1355,6 +1456,8 @@ class DaeExporter: self.writel(S_ANIM_CLIPS,0,'</library_animation_clips>') for s in self.skeletons: + if (s.animation_data==None): + continue if s in cached_actions: s.animation_data.action = bpy.data.actions[cached_actions[s]] else: |