diff options
author | Juan Linietsky <reduzio@gmail.com> | 2018-09-29 13:49:34 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2018-09-29 13:49:34 -0300 |
commit | 0de8309b2c38306a2c05f8f239fa423bc1b7899b (patch) | |
tree | 15874ca683f7d200ccf3e02d9d8f6298c95a81c6 | |
parent | 6cbdeedf57c7383827416da19b6026e3721f2812 (diff) |
Many fixes to GLES2 renderer, fixed compilation issues in GLES3 shaders.
-rw-r--r-- | drivers/gles2/rasterizer_scene_gles2.cpp | 106 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_scene_gles2.h | 5 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_storage_gles2.cpp | 9 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_storage_gles2.h | 16 | ||||
-rw-r--r-- | drivers/gles2/shader_compiler_gles2.cpp | 6 | ||||
-rw-r--r-- | drivers/gles2/shaders/scene.glsl | 12 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 7 | ||||
-rw-r--r-- | scene/resources/material.cpp | 8 |
8 files changed, 72 insertions, 97 deletions
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 06d355802a..0567aea7a6 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -913,6 +913,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G e->use_accum = false; e->light_index = RenderList::MAX_LIGHTS; e->use_accum_ptr = &e->use_accum; + e->instancing = (e->instance->base_type == VS::INSTANCE_MULTIMESH) ? 1 : 0; if (e->geometry->last_pass != render_pass) { e->geometry->last_pass = render_pass; @@ -1219,7 +1220,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste glDisableVertexAttribArray(i); switch (i) { case VS::ARRAY_NORMAL: { - glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); } break; case VS::ARRAY_COLOR: { glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -1230,7 +1231,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste } } - bool clear_skeleton_buffer = !storage->config.float_texture_supported; + //bool clear_skeleton_buffer = !storage->config.float_texture_supported; if (p_skeleton) { @@ -1342,29 +1343,18 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste //enable transform buffer and bind it glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 2); - glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - clear_skeleton_buffer = false; + //clear_skeleton_buffer = false; } } - if (clear_skeleton_buffer) { - // just to make sure - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); - } - } break; case VS::INSTANCE_MULTIMESH: { @@ -1384,7 +1374,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste glDisableVertexAttribArray(i); switch (i) { case VS::ARRAY_NORMAL: { - glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); } break; case VS::ARRAY_COLOR: { glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -1395,16 +1385,12 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste } } - if (!storage->config.float_texture_supported) { - // just to make sure, clear skeleton buffer too - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); - } + // prepare multimesh (disable) + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 0); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 1); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 2); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 3); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 4); } break; @@ -1430,7 +1416,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } else { glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); } - + /* if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { //clean up after skeleton glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); @@ -1443,7 +1429,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); } - +*/ } break; case VS::INSTANCE_MULTIMESH: { @@ -1464,53 +1450,33 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { // drawing + const float *base_buffer = multi_mesh->data.ptr(); + for (int i = 0; i < amount; i++) { - float *buffer = &multi_mesh->data.write[i * stride]; + const float *buffer = base_buffer + i * stride; { - // inline of multimesh_get_transform since it's such a pain - // to get a RID from here... - Transform transform; - - transform.basis.elements[0][0] = buffer[0]; - transform.basis.elements[0][1] = buffer[1]; - transform.basis.elements[0][2] = buffer[2]; - transform.origin.x = buffer[3]; - transform.basis.elements[1][0] = buffer[4]; - transform.basis.elements[1][1] = buffer[5]; - transform.basis.elements[1][2] = buffer[6]; - transform.origin.y = buffer[7]; - transform.basis.elements[2][0] = buffer[8]; - transform.basis.elements[2][1] = buffer[9]; - transform.basis.elements[2][2] = buffer[10]; - transform.origin.z = buffer[11]; - - float row[3][4] = { - { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, - { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, - { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, - }; - - glVertexAttrib4fv(VS::ARRAY_MAX + 0, row[0]); - glVertexAttrib4fv(VS::ARRAY_MAX + 1, row[1]); - glVertexAttrib4fv(VS::ARRAY_MAX + 2, row[2]); + + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); } if (multi_mesh->color_floats) { if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) { uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(VS::ARRAY_MAX + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); } else { - glVertexAttrib4fv(VS::ARRAY_MAX + 3, buffer + color_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); } } if (multi_mesh->custom_data_floats) { if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); - glVertexAttrib4f(VS::ARRAY_MAX + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); } else { - glVertexAttrib4fv(VS::ARRAY_MAX + 4, buffer + custom_data_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); } } @@ -2010,6 +1976,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, RasterizerStorageGLES2::Material *prev_material = NULL; RasterizerStorageGLES2::Geometry *prev_geometry = NULL; RasterizerStorageGLES2::Skeleton *prev_skeleton = NULL; + RasterizerStorageGLES2::GeometryOwner *prev_owner = NULL; Transform view_transform_inverse = p_view_transform.inverse(); CameraMatrix projection_inverse = p_projection.inverse(); @@ -2193,7 +2160,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } } - bool instancing = e->instancing; + bool instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH; if (instancing != prev_instancing) { @@ -2206,7 +2173,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (skeleton != prev_skeleton) { if (skeleton) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, skeleton != NULL); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true); state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); } else { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); @@ -2216,7 +2183,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, rebind = true; } - if (e->geometry != prev_geometry || skeleton != prev_skeleton) { + if (e->owner != prev_owner || e->geometry != prev_geometry || skeleton != prev_skeleton) { _setup_geometry(e, skeleton); } @@ -2225,7 +2192,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, shader_rebind = _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); } - if (i == 0 || shader_rebind) { //first time must rebindmakin + if (i == 0 || shader_rebind) { //first time must rebind if (p_shadow) { state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); @@ -2286,6 +2253,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _render_geometry(e); prev_geometry = e->geometry; + prev_owner = e->owner; prev_material = material; prev_skeleton = skeleton; prev_instancing = instancing; @@ -2297,8 +2265,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } _setup_light_type(NULL, NULL); //clear light stuff + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 9e3483fcd7..64790fcd0e 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -59,6 +59,11 @@ public: SHADOW_FILTER_PCF13, }; + enum { + INSTANCE_ATTRIB_BASE = 8, + INSTANCE_BONE_BASE = 13, + }; + ShadowFilterMode shadow_filter_mode; RID default_material; diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index bf51fcc027..0863e03b76 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -2624,10 +2624,10 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() { if (multimesh->mesh.is_valid()) { mesh_aabb = mesh_get_aabb(multimesh->mesh, RID()); - } else { - mesh_aabb.size += Vector3(0.001, 0.001, 0.001); } + mesh_aabb.size += Vector3(0.001, 0.001, 0.001); //in case mesh is empty in one of the sides + int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; int count = multimesh->data.size(); float *data = multimesh->data.ptrw(); @@ -3781,7 +3781,7 @@ void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, Rasterizer void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { - Instanciable *inst = NULL; + Instantiable *inst = NULL; switch (p_instance->base_type) { case VS::INSTANCE_MESH: { inst = mesh_owner.getornull(p_base); @@ -3827,7 +3827,7 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { - Instanciable *inst = NULL; + Instantiable *inst = NULL; switch (p_instance->base_type) { case VS::INSTANCE_MESH: { @@ -4542,6 +4542,7 @@ void RasterizerStorageGLES2::update_dirty_resources() { update_dirty_shaders(); update_dirty_materials(); update_dirty_skeletons(); + update_dirty_multimeshes(); } RasterizerStorageGLES2::RasterizerStorageGLES2() { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index da7e200c96..b42e2dfb1f 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -157,7 +157,7 @@ public: //////////////////////////////////DATA/////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// - struct Instanciable : public RID_Data { + struct Instantiable : public RID_Data { SelfList<RasterizerScene::InstanceBase>::List instance_list; _FORCE_INLINE_ void instance_change_notify() { @@ -187,15 +187,15 @@ public: } } - Instanciable() {} + Instantiable() {} - virtual ~Instanciable() {} + virtual ~Instantiable() {} }; - struct GeometryOwner : public Instanciable { + struct GeometryOwner : public Instantiable { }; - struct Geometry : public Instanciable { + struct Geometry : public Instantiable { enum Type { GEOMETRY_INVALID, @@ -893,7 +893,7 @@ public: /* Light API */ - struct Light : Instanciable { + struct Light : Instantiable { VS::LightType type; float param[VS::LIGHT_PARAM_MAX]; @@ -956,7 +956,7 @@ public: /* PROBE API */ - struct ReflectionProbe : Instanciable { + struct ReflectionProbe : Instantiable { VS::ReflectionProbeUpdateMode update_mode; float intensity; @@ -1046,7 +1046,7 @@ public: /* LIGHTMAP */ - struct LightmapCapture : public Instanciable { + struct LightmapCapture : public Instantiable { PoolVector<LightmapCaptureOctree> octree; AABB bounds; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index bedcfbb798..082c520480 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -643,11 +643,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener case SL::OP_MOD: { - code += "mod("; + code += "mod(float("; code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ", "; + code += "), float("; code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; + code += "))"; } break; default: { diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index b27bf0d12b..468804cc5a 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -43,9 +43,9 @@ attribute vec2 uv2_attrib; // attrib:5 #ifdef USE_SKELETON_SOFTWARE -attribute highp vec4 bone_transform_row_0; // attrib:8 -attribute highp vec4 bone_transform_row_1; // attrib:9 -attribute highp vec4 bone_transform_row_2; // attrib:10 +attribute highp vec4 bone_transform_row_0; // attrib:13 +attribute highp vec4 bone_transform_row_1; // attrib:14 +attribute highp vec4 bone_transform_row_2; // attrib:15 #else @@ -130,11 +130,6 @@ uniform highp float shadow_dual_paraboloid_render_side; #if defined(USE_SHADOW) && defined(USE_LIGHTING) -#ifdef LIGHT_MODE_DIRECTIONAL -uniform highp sampler2D light_directional_shadow; // texunit:-3 -uniform highp vec4 light_split_offsets; -#endif - uniform highp mat4 light_shadow_matrix; varying highp vec4 shadow_coord; @@ -306,6 +301,7 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); world_matrix = world_matrix * transpose(m); } + #endif vec3 normal = normal_attrib * normal_mult; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 7da20dfa00..bcaf4a57a8 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1136,8 +1136,9 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); return avg * (1.0 / 13.0); +#endif -#elif defined(SHADOW_MODE_PCF_5) +#ifdef SHADOW_MODE_PCF_5 float avg = textureProj(shadow, vec4(pos, depth, 1.0)); avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); @@ -1146,7 +1147,9 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); return avg * (1.0 / 5.0); -#else +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) return textureProj(shadow, vec4(pos, depth, 1.0)); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index c898aaff34..b671b1f874 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -610,11 +610,11 @@ void SpatialMaterial::_update_shader() { code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world;\n"; //handle animation - code += "\tint particle_total_frames = particles_anim_h_frames * particles_anim_v_frames;\n"; - code += "\tint particle_frame = int(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; - code += "\tif (particles_anim_loop) particle_frame=clamp(particle_frame,0,particle_total_frames-1); else particle_frame=abs(particle_frame)%particle_total_frames;\n"; + code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n"; + code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; + code += "\tif (particles_anim_loop) particle_frame=clamp(particle_frame,0.0,particle_total_frames-1.0); else particle_frame=mod(particle_frame,float(particle_total_frames));\n"; code += "\tUV /= vec2(float(particles_anim_h_frames),float(particles_anim_v_frames));\n"; - code += "\tUV += vec2(float(particle_frame % particles_anim_h_frames) / float(particles_anim_h_frames),float(particle_frame / particles_anim_h_frames) / float(particles_anim_v_frames));\n"; + code += "\tUV += vec2(mod(particle_frame,float(particles_anim_h_frames)) / float(particles_anim_h_frames),particle_frame / float(particles_anim_h_frames) / float(particles_anim_v_frames));\n"; } break; } |