瀏覽代碼

-New mask mode for lights, makes using masks MUCH easier.

Juan Linietsky 9 年之前
父節點
當前提交
428984ec0c

+ 4 - 2
drivers/gles2/rasterizer_gles2.cpp

@@ -9540,7 +9540,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 		canvas_opacity = ci->final_opacity;
 		canvas_opacity = ci->final_opacity;
 
 
 
 
-		if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT)))
+		if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT) && !ci->light_masked ))
 			_canvas_item_render_commands<false>(ci,current_clip,reclip);
 			_canvas_item_render_commands<false>(ci,current_clip,reclip);
 
 
 		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && !unshaded) {
 		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && !unshaded) {
@@ -9572,7 +9572,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 								glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 								glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 								glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 								glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 							} break;
 							} break;
-							case VS::CANVAS_LIGHT_MODE_MIX: {
+							case VS::CANVAS_LIGHT_MODE_MIX:
+							case VS::CANVAS_LIGHT_MODE_MASK: {
 								glBlendEquation(GL_FUNC_ADD);
 								glBlendEquation(GL_FUNC_ADD);
 								glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 								glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 
@@ -9620,6 +9621,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,Color(light->color.r*light->energy,light->color.g*light->energy,light->color.b*light->energy,light->color.a));
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,Color(light->color.r*light->energy,light->color.g*light->energy,light->color.b*light->energy,light->color.a));
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse());
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse());
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA,light->mode==VS::CANVAS_LIGHT_MODE_MASK?1.0:0.0);
 
 
 					if (has_shadow) {
 					if (has_shadow) {
 
 

+ 13 - 10
drivers/gles2/shaders/canvas.glsl

@@ -155,6 +155,7 @@ uniform vec4 light_color;
 uniform vec4 light_shadow_color;
 uniform vec4 light_shadow_color;
 uniform float light_height;
 uniform float light_height;
 varying vec4 light_uv_interp;
 varying vec4 light_uv_interp;
+uniform float light_outside_alpha;
 
 
 #if defined(NORMAL_USED)
 #if defined(NORMAL_USED)
 varying vec4 local_rot;
 varying vec4 local_rot;
@@ -247,22 +248,27 @@ FRAGMENT_SHADER_CODE
 	vec4 shadow_color=vec4(0.0,0.0,0.0,0.0);
 	vec4 shadow_color=vec4(0.0,0.0,0.0,0.0);
 #endif
 #endif
 
 
+	if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
+		color.a*=light_outside_alpha; //invisible
+
+	} else {
+
 #if defined(USE_LIGHT_SHADER_CODE)
 #if defined(USE_LIGHT_SHADER_CODE)
 //light is written by the light shader
 //light is written by the light shader
-{
-	vec4 light_out=light*color;
+		{
+			vec4 light_out=light*color;
 LIGHT_SHADER_CODE
 LIGHT_SHADER_CODE
-	color=light_out;
-}
+			color=light_out;
+		}
 
 
 #else
 #else
 
 
 #if defined(NORMAL_USED)
 #if defined(NORMAL_USED)
-	vec3 light_normal = normalize(vec3(light_vec,-light_height));
-	light*=max(dot(-light_normal,normal),0.0);
+		vec3 light_normal = normalize(vec3(light_vec,-light_height));
+		light*=max(dot(-light_normal,normal),0.0);
 #endif
 #endif
 
 
-	color*=light;
+		color*=light;
 /*
 /*
 #ifdef USE_NORMAL
 #ifdef USE_NORMAL
 	color.xy=local_rot.xy;//normal.xy;
 	color.xy=local_rot.xy;//normal.xy;
@@ -273,9 +279,6 @@ LIGHT_SHADER_CODE
 //light shader code
 //light shader code
 #endif
 #endif
 
 
-	if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
-		color.a=0.0; //invisible
-	} else {
 
 
 #ifdef USE_SHADOWS
 #ifdef USE_SHADOWS
 
 

+ 2 - 1
scene/2d/light_2d.cpp

@@ -333,7 +333,7 @@ void Light2D::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"scale",PROPERTY_HINT_RANGE,"0.01,4096,0.01"),_SCS("set_texture_scale"),_SCS("get_texture_scale"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"scale",PROPERTY_HINT_RANGE,"0.01,4096,0.01"),_SCS("set_texture_scale"),_SCS("get_texture_scale"));
 	ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
 	ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy"),_SCS("set_energy"),_SCS("get_energy"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy"),_SCS("set_energy"),_SCS("get_energy"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix"),_SCS("set_mode"),_SCS("get_mode"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix,Mask"),_SCS("set_mode"),_SCS("get_mode"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height"));
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
@@ -349,6 +349,7 @@ void Light2D::_bind_methods() {
 	BIND_CONSTANT( MODE_ADD );
 	BIND_CONSTANT( MODE_ADD );
 	BIND_CONSTANT( MODE_SUB );
 	BIND_CONSTANT( MODE_SUB );
 	BIND_CONSTANT( MODE_MIX );
 	BIND_CONSTANT( MODE_MIX );
+	BIND_CONSTANT( MODE_MASK );
 
 
 
 
 }
 }

+ 1 - 0
scene/2d/light_2d.h

@@ -11,6 +11,7 @@ public:
 		MODE_ADD,
 		MODE_ADD,
 		MODE_SUB,
 		MODE_SUB,
 		MODE_MIX,
 		MODE_MIX,
+		MODE_MASK,
 	};
 	};
 
 
 private:
 private:

+ 5 - 2
servers/visual/rasterizer.h

@@ -610,6 +610,7 @@ public:
 		CanvasLight *shadows_next_ptr;
 		CanvasLight *shadows_next_ptr;
 		CanvasLight *filter_next_ptr;
 		CanvasLight *filter_next_ptr;
 		CanvasLight *next_ptr;
 		CanvasLight *next_ptr;
+		CanvasLight *mask_next_ptr;
 
 
 		CanvasLight() {
 		CanvasLight() {
 			enabled=true;			
 			enabled=true;			
@@ -627,6 +628,7 @@ public:
 			mode=VS::CANVAS_LIGHT_MODE_ADD;
 			mode=VS::CANVAS_LIGHT_MODE_ADD;
 			texture_cache=NULL;
 			texture_cache=NULL;
 			next_ptr=NULL;
 			next_ptr=NULL;
+			mask_next_ptr=NULL;
 			filter_next_ptr=NULL;
 			filter_next_ptr=NULL;
 			shadow_buffer_size=2048;
 			shadow_buffer_size=2048;
 			shadow_esm_mult=80;
 			shadow_esm_mult=80;
@@ -792,6 +794,7 @@ public:
 		CanvasItem* material_owner;
 		CanvasItem* material_owner;
 		ViewportRender *vp_render;
 		ViewportRender *vp_render;
 		bool distance_field;
 		bool distance_field;
+		bool light_masked;
 
 
 		Rect2 global_rect_cache;
 		Rect2 global_rect_cache;
 
 
@@ -918,8 +921,8 @@ public:
 			return rect;
 			return rect;
 		}
 		}
 
 
-		void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL;  material_owner=NULL;}
-		CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; copy_back_buffer=NULL; distance_field=false; }
+		void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL;  material_owner=NULL; light_masked=false; }
+		CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; copy_back_buffer=NULL; distance_field=false; light_masked=false; }
 		virtual ~CanvasItem() { clear(); if (copy_back_buffer) memdelete(copy_back_buffer); }
 		virtual ~CanvasItem() { clear(); if (copy_back_buffer) memdelete(copy_back_buffer); }
 	};
 	};
 
 

+ 42 - 2
servers/visual/visual_server_raster.cpp

@@ -6777,6 +6777,7 @@ void VisualServerRaster::_render_canvas_item_viewport(VisualServer* p_self,void
 
 
 }
 }
 
 
+
 void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_material_owner) {
 void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_material_owner) {
 
 
 	CanvasItem *ci = p_canvas_item;
 	CanvasItem *ci = p_canvas_item;
@@ -6878,6 +6879,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 		ci->final_opacity=opacity * ci->self_opacity;
 		ci->final_opacity=opacity * ci->self_opacity;
 		ci->global_rect_cache=global_rect;
 		ci->global_rect_cache=global_rect;
 		ci->global_rect_cache.pos-=p_clip_rect.pos;
 		ci->global_rect_cache.pos-=p_clip_rect.pos;
+		ci->light_masked=false;
 
 
 		int zidx = p_z-CANVAS_ITEM_Z_MIN;
 		int zidx = p_z-CANVAS_ITEM_Z_MIN;
 
 
@@ -6905,7 +6907,34 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 
 
 }
 }
 
 
-void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights) {
+void VisualServerRaster::_light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights) {
+
+	if (!p_masked_lights)
+		return;
+
+	Rasterizer::CanvasItem *ci=p_canvas_item;
+
+	while(ci) {
+
+		Rasterizer::CanvasLight *light=p_masked_lights;
+		while(light) {
+
+			if (ci->light_mask&light->item_mask && p_z>=light->z_min && p_z<=light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache,light->rect_cache)) {
+				ci->light_masked=true;
+			}
+
+			light=light->mask_next_ptr;
+		}
+
+		ci=ci->next;
+	}
+
+
+
+
+}
+
+void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights,Rasterizer::CanvasLight *p_masked_lights) {
 
 
 	rasterizer->canvas_begin();
 	rasterizer->canvas_begin();
 
 
@@ -6938,6 +6967,11 @@ void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_trans
 		for(int i=0;i<z_range;i++) {
 		for(int i=0;i<z_range;i++) {
 			if (!z_list[i])
 			if (!z_list[i])
 				continue;
 				continue;
+
+			if (p_masked_lights) {
+				_light_mask_canvas_items(CANVAS_ITEM_Z_MIN+i,z_list[i],p_masked_lights);
+			}
+
 			rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights);
 			rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights);
 		}
 		}
 	} else {
 	} else {
@@ -7072,6 +7106,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 		Rect2 clip_rect(0,0,viewport_rect.width,viewport_rect.height);
 		Rect2 clip_rect(0,0,viewport_rect.width,viewport_rect.height);
 		Rasterizer::CanvasLight *lights=NULL;
 		Rasterizer::CanvasLight *lights=NULL;
 		Rasterizer::CanvasLight *lights_with_shadow=NULL;
 		Rasterizer::CanvasLight *lights_with_shadow=NULL;
+		Rasterizer::CanvasLight *lights_with_mask=NULL;
 		Rect2 shadow_rect;
 		Rect2 shadow_rect;
 
 
 		int light_count=0;
 		int light_count=0;
@@ -7119,9 +7154,14 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 							cl->radius_cache=cl->rect_cache.size.length();
 							cl->radius_cache=cl->rect_cache.size.length();
 
 
 						}
 						}
+						if (cl->mode==CANVAS_LIGHT_MODE_MASK) {
+							cl->mask_next_ptr=lights_with_mask;
+							lights_with_mask=cl;
+						}
 
 
 						light_count++;
 						light_count++;
 					}
 					}
+
 				}
 				}
 			}
 			}
 
 
@@ -7190,7 +7230,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 				ptr=ptr->filter_next_ptr;
 				ptr=ptr->filter_next_ptr;
 			}
 			}
 
 
-			_render_canvas( E->get()->canvas,xform,canvas_lights );
+			_render_canvas( E->get()->canvas,xform,canvas_lights,lights_with_mask );
 			i++;
 			i++;
 
 
 			if (scenario_draw_canvas_bg && E->key().layer>=scenario_canvas_max_layer) {
 			if (scenario_draw_canvas_bg && E->key().layer>=scenario_canvas_max_layer) {

+ 3 - 1
servers/visual/visual_server_raster.h

@@ -633,7 +633,9 @@ class VisualServerRaster : public VisualServer {
 	static void _render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect);
 	static void _render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect);
 	void _render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights);
 	void _render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights);
 	void _render_canvas_item(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, float p_opacity, int p_z, Rasterizer::CanvasItem **z_list, Rasterizer::CanvasItem **z_last_list, CanvasItem *p_canvas_clip, CanvasItem *p_material_owner);
 	void _render_canvas_item(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, float p_opacity, int p_z, Rasterizer::CanvasItem **z_list, Rasterizer::CanvasItem **z_last_list, CanvasItem *p_canvas_clip, CanvasItem *p_material_owner);
-	void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights);
+	void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights, Rasterizer::CanvasLight *p_masked_lights);
+	void _light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights);
+
 	Vector<Vector3> _camera_generate_endpoints(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
 	Vector<Vector3> _camera_generate_endpoints(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
 	Vector<Plane> _camera_generate_orthogonal_planes(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
 	Vector<Plane> _camera_generate_orthogonal_planes(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
 
 

+ 1 - 0
servers/visual_server.h

@@ -1041,6 +1041,7 @@ public:
 		CANVAS_LIGHT_MODE_ADD,
 		CANVAS_LIGHT_MODE_ADD,
 		CANVAS_LIGHT_MODE_SUB,
 		CANVAS_LIGHT_MODE_SUB,
 		CANVAS_LIGHT_MODE_MIX,
 		CANVAS_LIGHT_MODE_MIX,
+		CANVAS_LIGHT_MODE_MASK,
 	};
 	};
 
 
 	virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode)=0;
 	virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode)=0;