浏览代码

Merge pull request #12052 from hi-ogawa/particle-material-conversion-plugin

Create ParticlesMaterialConversionPlugin
Rémi Verschelde 7 年之前
父节点
当前提交
7969565de7
共有 5 个文件被更改,包括 222 次插入167 次删除
  1. 4 0
      editor/editor_node.cpp
  2. 39 0
      editor/plugins/material_editor_plugin.cpp
  3. 8 0
      editor/plugins/material_editor_plugin.h
  4. 169 167
      scene/3d/particles.cpp
  5. 2 0
      scene/3d/particles.h

+ 4 - 0
editor/editor_node.cpp

@@ -5541,6 +5541,10 @@ EditorNode::EditorNode() {
 		Ref<SpatialMaterialConversionPlugin> spatial_mat_convert;
 		spatial_mat_convert.instance();
 		resource_conversion_plugins.push_back(spatial_mat_convert);
+
+		Ref<ParticlesMaterialConversionPlugin> particles_mat_convert;
+		particles_mat_convert.instance();
+		resource_conversion_plugins.push_back(particles_mat_convert);
 	}
 	circle_step_msec = OS::get_singleton()->get_ticks_msec();
 	circle_step_frame = Engine::get_singleton()->get_frames_drawn();

+ 39 - 0
editor/plugins/material_editor_plugin.cpp

@@ -32,6 +32,7 @@
 // Waiting for PropertyEditor rewrite (planned for 3.1) to be refactored.
 
 #include "material_editor_plugin.h"
+#include "scene/3d/particles.h"
 
 #if 0
 
@@ -456,3 +457,41 @@ Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_re
 	smat->set_render_priority(mat->get_render_priority());
 	return smat;
 }
+
+String ParticlesMaterialConversionPlugin::converts_to() const {
+
+	return "ShaderMaterial";
+}
+bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+
+	Ref<ParticlesMaterial> mat = p_resource;
+	return mat.is_valid();
+}
+Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) {
+
+	Ref<ParticlesMaterial> mat = p_resource;
+	ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+	Ref<ShaderMaterial> smat;
+	smat.instance();
+
+	Ref<Shader> shader;
+	shader.instance();
+
+	String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+	shader->set_code(code);
+
+	smat->set_shader(shader);
+
+	List<PropertyInfo> params;
+	VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+	for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
+		Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+		smat->set_shader_param(E->get().name, value);
+	}
+
+	smat->set_render_priority(mat->get_render_priority());
+	return smat;
+}

+ 8 - 0
editor/plugins/material_editor_plugin.h

@@ -111,4 +111,12 @@ public:
 	virtual Ref<Resource> convert(const Ref<Resource> &p_resource);
 };
 
+class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin {
+	GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin)
+public:
+	virtual String converts_to() const;
+	virtual bool handles(const Ref<Resource> &p_resource) const;
+	virtual Ref<Resource> convert(const Ref<Resource> &p_resource);
+};
+
 #endif // MATERIAL_EDITOR_PLUGIN_H

+ 169 - 167
scene/3d/particles.cpp

@@ -585,298 +585,294 @@ void ParticlesMaterial::_update_shader() {
 	//need a random function
 	code += "\n\n";
 	code += "float rand_from_seed(inout uint seed) {\n";
-	code += "   int k;\n";
-	code += "   int s = int(seed);\n";
-	code += "   if (s == 0)\n";
+	code += "	int k;\n";
+	code += "	int s = int(seed);\n";
+	code += "	if (s == 0)\n";
 	code += "	s = 305420679;\n";
-	code += "   k = s / 127773;\n";
-	code += "   s = 16807 * (s - k * 127773) - 2836 * k;\n";
-	code += "   if (s < 0)\n";
-	code += "	s += 2147483647;\n";
-	code += "   seed = uint(s);\n";
-	code += "   return float(seed % uint(65536))/65535.0;\n";
+	code += "	k = s / 127773;\n";
+	code += "	s = 16807 * (s - k * 127773) - 2836 * k;\n";
+	code += "	if (s < 0)\n";
+	code += "		s += 2147483647;\n";
+	code += "	seed = uint(s);\n";
+	code += "	return float(seed % uint(65536))/65535.0;\n";
 	code += "}\n";
+	code += "\n";
+
 	//improve seed quality
 	code += "uint hash(uint x) {\n";
-	code += "   x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
-	code += "   x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
-	code += "   x = (x >> uint(16)) ^ x;\n";
-	code += "   return x;\n";
+	code += "	x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+	code += "	x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+	code += "	x = (x >> uint(16)) ^ x;\n";
+	code += "	return x;\n";
 	code += "}\n";
-	code += "void vertex() {\n\n";
 	code += "\n";
 
-	code += " uint base_number=NUMBER/uint(trail_divisor);\n";
-	code += " uint alt_seed=hash(base_number+uint(1)+RANDOM_SEED);\n";
-	code += " float angle_rand=rand_from_seed(alt_seed);\n";
-	code += " float scale_rand=rand_from_seed(alt_seed);\n";
-	code += " float hue_rot_rand=rand_from_seed(alt_seed);\n";
-	code += " float anim_offset_rand=rand_from_seed(alt_seed);\n";
-	code += "\n";
-	code += "\n";
-	code += "\n";
+	code += "void vertex() {\n";
+	code += "	uint base_number = NUMBER/uint(trail_divisor);\n";
+	code += "	uint alt_seed = hash(base_number+uint(1)+RANDOM_SEED);\n";
+	code += "	float angle_rand = rand_from_seed(alt_seed);\n";
+	code += "	float scale_rand = rand_from_seed(alt_seed);\n";
+	code += "	float hue_rot_rand = rand_from_seed(alt_seed);\n";
+	code += "	float anim_offset_rand = rand_from_seed(alt_seed);\n";
 	code += "\n";
+
 	if (emission_shape >= EMISSION_SHAPE_POINTS) {
-		code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
-		code += " ivec2 emission_tex_size = textureSize( emission_texture_points, 0 );\n";
-		code += " ivec2 emission_tex_ofs = ivec2( point % emission_tex_size.x, point / emission_tex_size.x );\n";
+		code += "	int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
+		code += "	ivec2 emission_tex_size = textureSize( emission_texture_points, 0 );\n";
+		code += "	ivec2 emission_tex_ofs = ivec2( point % emission_tex_size.x, point / emission_tex_size.x );\n";
 	}
-	code += " if (RESTART) {\n";
+	code += "	if (RESTART) {\n";
 
 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
-		code += "    float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(0.0,0.0),0.0).r;\n";
+		code += "		float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(0.0,0.0),0.0).r;\n";
 	else
-		code += "    float tex_linear_velocity = 0.0;\n";
+		code += "		float tex_linear_velocity = 0.0;\n";
 
 	if (tex_parameters[PARAM_ANGLE].is_valid())
-		code += "    float tex_angle = textureLod(angle_texture,vec2(0.0,0.0),0.0).r;\n";
+		code += "		float tex_angle = textureLod(angle_texture,vec2(0.0,0.0),0.0).r;\n";
 	else
-		code += "    float tex_angle = 0.0;\n";
+		code += "		float tex_angle = 0.0;\n";
 
 	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
-		code += "    float tex_anim_offset = textureLod(anim_offset_texture,vec2(0.0,0.0),0.0).r;\n";
+		code += "		float tex_anim_offset = textureLod(anim_offset_texture,vec2(0.0,0.0),0.0).r;\n";
 	else
-		code += "    float tex_anim_offset = 0.0;\n";
+		code += "		float tex_anim_offset = 0.0;\n";
 
 	if (flags[FLAG_DISABLE_Z]) {
 
-		code += "    float angle1 = (rand_from_seed(alt_seed)*2.0-1.0)*spread/180.0*3.1416;\n";
-		code += "    vec3 rot=vec3( cos(angle1), sin(angle1),0.0 );\n";
-		code += "    VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
+		code += "		float angle1 = (rand_from_seed(alt_seed)*2.0-1.0)*spread/180.0*3.1416;\n";
+		code += "		vec3 rot = vec3( cos(angle1), sin(angle1),0.0 );\n";
+		code += "		VELOCITY = (rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
 
 	} else {
 		//initiate velocity spread in 3D
-		code += "    float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
-		code += "    float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n";
-		code += "    vec3 rot_xz=vec3( sin(angle1), 0.0, cos(angle1) );\n";
-		code += "    vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n";
-		code += "    VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
+		code += "		float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
+		code += "		float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n";
+		code += "		vec3 rot_xz = vec3( sin(angle1), 0.0, cos(angle1) );\n";
+		code += "		vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n";
+		code += "		VELOCITY = (rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
 	}
 
-	code += "    float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
-	code += "    CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
-	code += "    CUSTOM.y=0.0;\n"; //phase
-	code += "    CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1)
+	code += "		float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
+	code += "		CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle
+	code += "		CUSTOM.y = 0.0;\n"; //phase
+	code += "		CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1)
 	switch (emission_shape) {
 		case EMISSION_SHAPE_POINT: {
 			//do none
 		} break;
 		case EMISSION_SHAPE_SPHERE: {
-			code += "    TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0 ))*emission_sphere_radius;\n";
+			code += "		TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0 ))*emission_sphere_radius;\n";
 		} break;
 		case EMISSION_SHAPE_BOX: {
-			code += "    TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0)*emission_box_extents;\n";
+			code += "		TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0)*emission_box_extents;\n";
 		} break;
 		case EMISSION_SHAPE_POINTS:
 		case EMISSION_SHAPE_DIRECTED_POINTS: {
-			code += "    TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs,0).xyz;\n";
+			code += "		TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs,0).xyz;\n";
 
 			if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
 				if (flags[FLAG_DISABLE_Z]) {
 
-					code += "    mat2 rotm;";
-					code += "    rotm[0]=texelFetch(emission_texture_normal, emission_tex_ofs,0).xy;\n";
-					code += "    rotm[1]=rotm[0].yx * vec2(1.0,-1.0);\n";
-					code += "    VELOCITY.xy = rotm * VELOCITY.xy;\n";
+					code += "		mat2 rotm;";
+					code += "		rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs,0).xy;\n";
+					code += "		rotm[1] = rotm[0].yx * vec2(1.0,-1.0);\n";
+					code += "		VELOCITY.xy = rotm * VELOCITY.xy;\n";
 				} else {
-					code += "    vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs,0).xyz;\n";
-					code += "    vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n";
-					code += "    vec3 tangent = normalize(cross(v0, normal));\n";
-					code += "    vec3 bitangent = normalize(cross(tangent, normal));\n";
-					code += "    VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n";
+					code += "		vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs,0).xyz;\n";
+					code += "		vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n";
+					code += "		vec3 tangent = normalize(cross(v0, normal));\n";
+					code += "		vec3 bitangent = normalize(cross(tangent, normal));\n";
+					code += "		VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n";
 				}
 			}
 		} break;
 	}
-	code += "    VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n";
-	code += "    TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+	code += "		VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n";
+	code += "		TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
 	if (flags[FLAG_DISABLE_Z]) {
-		code += "    VELOCITY.z=0.0;\n";
-		code += "    TRANSFORM[3].z=0.0;\n";
+		code += "		VELOCITY.z = 0.0;\n";
+		code += "		TRANSFORM[3].z = 0.0;\n";
 	}
 
-	code += " } else {\n";
+	code += "	} else {\n";
 
-	code += "    CUSTOM.y+=DELTA/LIFETIME;\n";
+	code += "		CUSTOM.y += DELTA/LIFETIME;\n";
 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
-		code += "    float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_linear_velocity = 0.0;\n";
+		code += "		float tex_linear_velocity = 0.0;\n";
 
 	if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
-		code += "    float tex_orbit_velocity = textureLod(orbit_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_orbit_velocity = textureLod(orbit_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_orbit_velocity = 0.0;\n";
+		code += "		float tex_orbit_velocity = 0.0;\n";
 
 	if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
-		code += "    float tex_angular_velocity = textureLod(angular_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_angular_velocity = textureLod(angular_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_angular_velocity = 0.0;\n";
+		code += "		float tex_angular_velocity = 0.0;\n";
 
 	if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
-		code += "    float tex_linear_accel = textureLod(linear_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_linear_accel = textureLod(linear_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_linear_accel = 0.0;\n";
+		code += "		float tex_linear_accel = 0.0;\n";
 
 	if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
-		code += "    float tex_radial_accel = textureLod(radial_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_radial_accel = textureLod(radial_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_radial_accel = 0.0;\n";
+		code += "		float tex_radial_accel = 0.0;\n";
 
 	if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
-		code += "    float tex_tangent_accel = textureLod(tangent_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_tangent_accel = textureLod(tangent_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_tangent_accel = 0.0;\n";
+		code += "		float tex_tangent_accel = 0.0;\n";
 
 	if (tex_parameters[PARAM_DAMPING].is_valid())
-		code += "    float tex_damping = textureLod(damping_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_damping = textureLod(damping_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_damping = 0.0;\n";
+		code += "		float tex_damping = 0.0;\n";
 
 	if (tex_parameters[PARAM_ANGLE].is_valid())
-		code += "    float tex_angle = textureLod(angle_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_angle = textureLod(angle_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_angle = 0.0;\n";
+		code += "		float tex_angle = 0.0;\n";
 
 	if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
-		code += "    float tex_anim_speed = textureLod(anim_speed_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_anim_speed = textureLod(anim_speed_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_anim_speed = 0.0;\n";
+		code += "		float tex_anim_speed = 0.0;\n";
 
 	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
-		code += "    float tex_anim_offset = textureLod(anim_offset_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "		float tex_anim_offset = textureLod(anim_offset_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += "    float tex_anim_offset = 0.0;\n";
+		code += "		float tex_anim_offset = 0.0;\n";
 
-	code += "    vec3 force = gravity; \n";
-	code += "    vec3 pos = TRANSFORM[3].xyz; \n";
+	code += "		vec3 force = gravity; \n";
+	code += "		vec3 pos = TRANSFORM[3].xyz; \n";
 	if (flags[FLAG_DISABLE_Z]) {
-		code += "    pos.z=0.0; \n";
+		code += "		pos.z = 0.0; \n";
 	}
-	code += "    //apply linear acceleration\n";
-	code += "    force+= length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random) : vec3(0.0);\n";
-	code += "    //apply radial acceleration\n";
-	code += "    vec3 org = vec3(0.0);\n";
-	code += "    // if (!p_system->local_coordinates)\n";
-	code += "    //org=p_transform.origin;\n";
-	code += "    vec3 diff = pos-org;\n";
-	code += "    force+=length(diff) > 0.0 ? normalize(diff) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random) : vec3(0.0);\n";
-	code += "    //apply tangential acceleration;\n";
+	code += "		//apply linear acceleration\n";
+	code += "		force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random) : vec3(0.0);\n";
+	code += "		//apply radial acceleration\n";
+	code += "		vec3 org = vec3(0.0);\n";
+	code += "		vec3 diff = pos-org;\n";
+	code += "		force += length(diff) > 0.0 ? normalize(diff) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random) : vec3(0.0);\n";
+	code += "		//apply tangential acceleration;\n";
 	if (flags[FLAG_DISABLE_Z]) {
-		code += "    force+=length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0,1.0)),0.0) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random)) : vec3(0.0);\n";
+		code += "		force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0,1.0)),0.0) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random)) : vec3(0.0);\n";
 
 	} else {
-		code += "    vec3 crossDiff = cross(normalize(diff),normalize(gravity));\n";
-		code += "    force+=length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random)) : vec3(0.0);\n";
+		code += "		vec3 crossDiff = cross(normalize(diff),normalize(gravity));\n";
+		code += "		force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random)) : vec3(0.0);\n";
 	}
-	code += "    //apply attractor forces\n";
-	code += "    VELOCITY+=force * DELTA;\n";
+	code += "		//apply attractor forces\n";
+	code += "		VELOCITY += force * DELTA;\n";
 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
-		code += "    VELOCITY=normalize(VELOCITY)*tex_linear_velocity;\n";
+		code += "		VELOCITY = normalize(VELOCITY)*tex_linear_velocity;\n";
 	}
-	code += "    if (damping+tex_damping>0.0) {\n";
-	code += "    \n";
-	code += "    	float v = length(VELOCITY);\n";
-	code += "    	float damp = (damping+tex_damping)*mix(1.0,rand_from_seed(alt_seed),damping_random);\n";
-	code += "    	v -= damp * DELTA;\n";
-	code += "    	if (v<0.0) {\n";
-	code += "    		VELOCITY=vec3(0.0);\n";
-	code += "    	} else {\n";
-	code += "    		VELOCITY=normalize(VELOCITY) * v;\n";
-	code += "	}\n";
-	code += "    }\n";
-	code += "    float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
-	code += "    base_angle+=CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n";
-	code += "    CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
-	code += "    CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
+	code += "		if (damping + tex_damping > 0.0) {\n";
+	code += "		\n";
+	code += "			float v = length(VELOCITY);\n";
+	code += "			float damp = (damping+tex_damping)*mix(1.0,rand_from_seed(alt_seed),damping_random);\n";
+	code += "			v -= damp * DELTA;\n";
+	code += "			if (v < 0.0) {\n";
+	code += "				VELOCITY = vec3(0.0);\n";
+	code += "			} else {\n";
+	code += "				VELOCITY = normalize(VELOCITY) * v;\n";
+	code += "			}\n";
+	code += "		}\n";
+	code += "		float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
+	code += "		base_angle += CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n";
+	code += "		CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle
+	code += "		CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
 	if (flags[FLAG_ANIM_LOOP]) {
-		code += "    CUSTOM.z=mod(CUSTOM.z,1.0);\n"; //loop
+		code += "		CUSTOM.z = mod(CUSTOM.z,1.0);\n"; //loop
 
 	} else {
-		code += "    CUSTOM.z=clamp(CUSTOM.z,0.0,1.0);\n"; //0 to 1 only
+		code += "		CUSTOM.z = clamp(CUSTOM.z,0.0,1.0);\n"; //0 to 1 only
 	}
-	code += "  }\n";
+	code += "	}\n";
 	//apply color
 	//apply hue rotation
 	if (tex_parameters[PARAM_SCALE].is_valid())
-		code += " float tex_scale = textureLod(scale_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "	float tex_scale = textureLod(scale_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += " float tex_scale = 1.0;\n";
+		code += "	float tex_scale = 1.0;\n";
 
 	if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
-		code += " float tex_hue_variation = textureLod(hue_variation_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+		code += "	float tex_hue_variation = textureLod(hue_variation_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
 	else
-		code += " float tex_hue_variation = 0.0;\n";
-
-	code += "  float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
-	code += "  float hue_rot_c = cos(hue_rot_angle);\n";
-	code += "  float hue_rot_s = sin(hue_rot_angle);\n";
-	code += "  mat4 hue_rot_mat =	mat4( vec4(0.299,  0.587,  0.114, 0.0),\n";
-	code += "			    	 vec4(0.299,  0.587,  0.114, 0.0),\n";
-	code += "			    	 vec4(0.299,  0.587,  0.114, 0.0),\n";
-	code += "				 vec4(0.000,  0.000,  0.000, 1.0)) +\n";
-	code += "	\n";
-	code += "			mat4(	 vec4(0.701, -0.587, -0.114, 0.0),\n";
-	code += "				vec4(-0.299,  0.413, -0.114, 0.0),\n";
-	code += "				vec4(-0.300, -0.588,  0.886, 0.0),\n";
-	code += "			 	 vec4(0.000,  0.000,  0.000, 0.0)) * hue_rot_c +\n";
-	code += "\n";
-	code += "			mat4(	 vec4(0.168,  0.330, -0.497, 0.0),\n";
-	code += "				vec4(-0.328,  0.035,  0.292, 0.0),\n";
-	code += "				 vec4(1.250, -1.050, -0.203, 0.0),\n";
-	code += "				 vec4(0.000,  0.000,  0.000, 0.0)) * hue_rot_s;\n";
+		code += "	float tex_hue_variation = 0.0;\n";
+
+	code += "	float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
+	code += "	float hue_rot_c = cos(hue_rot_angle);\n";
+	code += "	float hue_rot_s = sin(hue_rot_angle);\n";
+	code += "	mat4 hue_rot_mat = mat4( vec4(0.299,  0.587,  0.114, 0.0),\n";
+	code += "			vec4(0.299,  0.587,  0.114, 0.0),\n";
+	code += "			vec4(0.299,  0.587,  0.114, 0.0),\n";
+	code += "			vec4(0.000,  0.000,  0.000, 1.0)) +\n";
+	code += "		mat4( vec4(0.701, -0.587, -0.114, 0.0),\n";
+	code += "			vec4(-0.299,  0.413, -0.114, 0.0),\n";
+	code += "			vec4(-0.300, -0.588,  0.886, 0.0),\n";
+	code += "			vec4(0.000,  0.000,  0.000, 0.0)) * hue_rot_c +\n";
+	code += "		mat4( vec4(0.168,  0.330, -0.497, 0.0),\n";
+	code += "			vec4(-0.328,  0.035,  0.292, 0.0),\n";
+	code += "			vec4(1.250, -1.050, -0.203, 0.0),\n";
+	code += "			vec4(0.000,  0.000,  0.000, 0.0)) * hue_rot_s;\n";
 	if (color_ramp.is_valid()) {
-		code += " COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n";
+		code += "	COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n";
 	} else {
-		code += " COLOR = color_value * hue_rot_mat;\n";
+		code += "	COLOR = color_value * hue_rot_mat;\n";
 	}
 	if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) {
-		code += " COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n";
+		code += "	COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n";
 	}
 	if (trail_color_modifier.is_valid()) {
-		code += "if (trail_divisor>1) { COLOR*=textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n";
+		code += "	if (trail_divisor > 1) { COLOR *= textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n";
 	}
 	code += "\n";
 
 	if (flags[FLAG_DISABLE_Z]) {
 
-		code += " TRANSFORM[0]=vec4(cos(CUSTOM.x),-sin(CUSTOM.x),0.0,0.0);\n";
-		code += " TRANSFORM[1]=vec4(sin(CUSTOM.x),cos(CUSTOM.x),0.0,0.0);\n";
-		code += " TRANSFORM[2]=vec4(0.0,0.0,1.0,0.0);\n";
+		code += "	TRANSFORM[0] = vec4(cos(CUSTOM.x),-sin(CUSTOM.x),0.0,0.0);\n";
+		code += "	TRANSFORM[1] = vec4(sin(CUSTOM.x),cos(CUSTOM.x),0.0,0.0);\n";
+		code += "	TRANSFORM[2] = vec4(0.0,0.0,1.0,0.0);\n";
 
 	} else {
 		//orient particle Y towards velocity
 		if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
-			code += " if (length(VELOCITY)>0.0) {TRANSFORM[1].xyz=normalize(VELOCITY);} else {TRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);}\n";
-			code += " if (TRANSFORM[1].xyz==normalize(TRANSFORM[0].xyz)) {\n";
-			code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
-			code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
-			code += " } else {\n";
-			code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
-			code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
-			code += " }\n";
+			code += "	if (length(VELOCITY) > 0.0) { TRANSFORM[1].xyz = normalize(VELOCITY); } else { TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz); }\n";
+			code += "	if (TRANSFORM[1].xyz == normalize(TRANSFORM[0].xyz)) {\n";
+			code += "		TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
+			code += "		TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
+			code += "	} else {\n";
+			code += "		TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
+			code += "		TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
+			code += "	}\n";
 		} else {
-			code += "\tTRANSFORM[0].xyz=normalize(TRANSFORM[0].xyz);\n";
-			code += "\tTRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);\n";
-			code += "\tTRANSFORM[2].xyz=normalize(TRANSFORM[2].xyz);\n";
+			code += "	TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);\n";
+			code += "	TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n";
+			code += "	TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n";
 		}
 		//turn particle by rotation in Y
 		if (flags[FLAG_ROTATE_Y]) {
-			code += "\tTRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n";
+			code += "	TRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n";
 		}
 	}
 	//scale by scale
-	code += " float base_scale=mix(scale*tex_scale,1.0,scale_random*scale_rand);\n";
+	code += "	float base_scale = mix(scale*tex_scale,1.0,scale_random*scale_rand);\n";
 	if (trail_size_modifier.is_valid()) {
-		code += "if (trail_divisor>1) { base_scale*=textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n";
+		code += "	if (trail_divisor > 1) { base_scale *= textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n";
 	}
 
-	code += " TRANSFORM[0].xyz*=base_scale;\n";
-	code += " TRANSFORM[1].xyz*=base_scale;\n";
-	code += " TRANSFORM[2].xyz*=base_scale;\n";
+	code += "	TRANSFORM[0].xyz *= base_scale;\n";
+	code += "	TRANSFORM[1].xyz *= base_scale;\n";
+	code += "	TRANSFORM[2].xyz *= base_scale;\n";
 	if (flags[FLAG_DISABLE_Z]) {
-		code += " VELOCITY.z=0.0;\n";
-		code += " TRANSFORM[3].z=0.0;\n";
+		code += "	VELOCITY.z = 0.0;\n";
+		code += "	TRANSFORM[3].z = 0.0;\n";
 	}
 	code += "}\n";
 	code += "\n";
@@ -1325,6 +1321,12 @@ Vector3 ParticlesMaterial::get_gravity() const {
 	return gravity;
 }
 
+RID ParticlesMaterial::get_shader_rid() const {
+
+	ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
+	return shader_map[current_key].shader;
+}
+
 void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
 
 	if (property.name == "color" && color_ramp.is_valid()) {

+ 2 - 0
scene/3d/particles.h

@@ -388,6 +388,8 @@ public:
 	static void finish_shaders();
 	static void flush_changes();
 
+	RID get_shader_rid() const;
+
 	ParticlesMaterial();
 	~ParticlesMaterial();
 };