精华内容
下载资源
问答
  • 16,color_FFFFFF,t_70) 图2:使用StencilOutline.shader 3,使用stencil buffer进行多边形填充 代码 说明 效果 4,用stencil buffer进行反射区域限定 代码 说明 效果 5,阴影体shadow volume阴影渲染 说明 代码 效果 1,...

    本文示例项目Github连接:https://github.com/liu-if-else/UnityStencilBufferUses

    最近有两次被人问到stencil buffer的用法,回答的含糊其辞,这两天研究了下它并总结出此文。

     
    1,Stencil buffer在OpenGL/Unity 渲染管线中的角色

    为什么叫stencil 模板

    stencil是印刷工业中的版面模子,模子上抠出需要的图案,然后将模子盖在要被印刷的材质上,对洞涂或喷绘颜色。

    如果将屏幕上所有像素想象成一串连续的0组成的矩形,那么stencil buffer的作用就是将某些0变为1,2,3 … 255,在每个pass中可以决定只渲染某个特定stencil值的像素并抛弃对其他非该值像素的操作,就像一块模板一样扣住了所有像素,并只对当前stencil值的洞洞进行喷绘。

    stencil与depth

    stencil buffer与depth buffer一样,都是缓冲区,存在于显存内的某一片区域中。据wikipedia上解释,目前的显卡架构中,stencil buffer与depth buffer是在一起的,比如在depth/stencil缓冲区某个32位的区域中,有24位记录着像素A的depth数据,紧接着8位记录着像素A的stencil数据。也许就是由于它们连接如此紧密,在stencil test中可以获取到Z test的结果。在Unity中新建一个RenderTexture也可以通过设定深度值的位数来选择开启/关闭stencil buffer。

    stencil测试在管线中的位置与它的写入与读取

    在OpenGL渲染管线中,在片段着色器fragment shader之后,Blending混融之前有三个测试操作环节: scissor test(unity好像用不了),Stencil Test和Z-Test。
    在Stencil Test环节,可通过使用关键字Comp读stencil值并与Ref值进行比较,通过Keep,Zero,Incr…对stencil进行写入,所有关键字说明请看Unity官网

                Stencil {
                	//当前像素stencil值与0进行比较
                    Ref 0           //0-255
                    //测试条件:测试是否相等
                    Comp Equal     //default:always
                    //如果测试通过对此stencil值进行的写入操作:保持当前stencil值
                    Pass keep       //default:keep
                    //如果测试失败对此stencil值进行的写入操作:保持当前stencil值
                    Fail keep       //default:keep
                    //如果深度测试失败对此stencil值进行的写入操作:循环递增
                    ZFail IncrWrap  //default:keep
                }
    

     
     
    2,使用Stencil buffer进行描边

    代码

    Shader "Unlit/StentilOutline"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    	}
    	SubShader
    	{
    		Tags { "RenderType"="Opaque" }
    		LOD 100
            Stencil {
                 Ref 0          //0-255
                 Comp Equal     //default:always
                 Pass IncrSat   //default:keep
                 Fail keep      //default:keep
                 ZFail keep     //default:keep
            }
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			// make fog work
    			#pragma multi_compile_fog
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				UNITY_FOG_COORDS(1)
    				float4 vertex : SV_POSITION;
    			};
    
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    				UNITY_TRANSFER_FOG(o,o.vertex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    				// sample the texture
    				fixed4 col = tex2D(_MainTex, i.uv);
    				// apply fog
    				UNITY_APPLY_FOG(i.fogCoord, col);
    			    //return fixed4(1,1,0,1);
                    return col;
    			}
    			ENDCG
    		}
    
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                
                #include "UnityCG.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float4 normal: NORMAL;
                    float2 uv : TEXCOORD0;
                };
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    UNITY_FOG_COORDS(1)
                    float4 vertex : SV_POSITION;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
                
                v2f vert (appdata v)
                {
                    v2f o;
                    o.vertex=v.vertex+normalize(v.normal)*0.01f;
                    o.vertex = UnityObjectToClipPos(o.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    UNITY_TRANSFER_FOG(o,o.vertex);
                    return o;
                }
                
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return fixed4(1,1,1,1);
                }
                ENDCG
            }
    	}
    }
    
    

    说明

            Stencil {
                 Ref 0          //0-255
                 Comp Equal     //default:always
                 Pass IncrSat   //default:keep
                 Fail keep      //default:keep
                 ZFail keep     //default:keep
            }
    

    buffer的值在当前帧结束前是不清除的,所以它可以跨越不同的shader与pass。Stencil结构写在Subshader中,那么下面的所有pass中的stencil test都按此运行。理想环境下,第一个pass渲染前屏幕上所有像素的stencil值都是0,在该pass的fragment shader结束后,所有进行了渲染的像素都通过了Ref 0和Comp Equal的测试,并执行Pass IncrSat将stencil值加1。

    ...
                    o.vertex=v.vertex+normalize(v.normal)*0.01f;
    ...
    

    第二个pass中,将顶点进行进行了放大。进行同样的stencil测试,上一个pass渲染过的像素stencil值已经变为1,无法通过Ref 0+Comp Equal测试,那么现在只会在放大后的既是stencil值仍然为0的区域进行渲染。

    ...
                    return fixed4(1,1,1,1);
    ...
    

    对第二个pass通过测试的像素给予描边颜色。

    效果

    图1:使用StencilPerPassOutline.shader
    图1:使用StencilPerPassOutline.shader
    图2:使用StencilOutline.shader
    图2:使用StencilOutline.shader
     
     
    3,使用stencil buffer进行多边形填充

    这个效果与Unity官网中介绍stencil的第一个example shader类似,通过stencil值对几何体交叉区域进行判定与渲染。

    代码

    Shader "Unlit/PolygonsBeta"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
    
            CGINCLUDE
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
    
            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };
    
            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            ENDCG
    
            Pass
            {
                Stencil {
                    Ref 0           //0-255
                    Comp always     //default:always
                    Pass IncrWrap       //default:keep
                    Fail keep       //default:keep
                    ZFail IncrWrap  //default:keep
                }
    
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
    
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return fixed4(0,0,0,0);
                }
                ENDCG
            }
            
            Pass
            {
                Stencil {
                    Ref 2           //0-255
                    Comp Equal     //default:always
                    Pass keep       //default:keep
                    Fail keep       //default:keep
                    ZFail keep  //default:keep
                }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                
                #include "UnityCG.cginc"
    
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return fixed4(0.2,0.2,0.2,1);
                }
                ENDCG
            }
    
            Pass
            {
                Stencil {
                    Ref 3          //0-255
                    Comp equal     //default:always
                    Pass keep   //default:keep
                    Fail keep      //default:keep
                    ZFail keep  //default:keep
                }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                
                #include "UnityCG.cginc"
    
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return fixed4(0.6,0.6,0.6,1);
                }
                ENDCG
            }
    
            Pass
            {
                Stencil {
                    Ref 4          //0-255
                    Comp equal     //default:always
                    Pass keep   //default:keep
                    Fail keep      //default:keep
                    ZFail keep  //default:keep
                }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                
                #include "UnityCG.cginc"
    
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return fixed4(1,1,1,1);
                }
                ENDCG
            }
        }
    }
    

    说明

    第一个pass渲染一个几何体,不论任何情况都通过测试并对它所覆盖的像素区域stencil值加1,后三个pass分别只对stencil值为2,3,4的区域进行渲染。

    效果

    图3:使用PolygonsBeta.shader
    图3:使用PolygonsBeta.shader

    图4:使用polygons.shader
    图4:使用polygons.shader

    上图是结合此shader与以前文章里的阿基米德螺旋线算法放飞想象力的结果-_-。感觉用这招做Logo潜力好大…

     
     
    4,用stencil buffer进行反射区域限定

    此用法主要是辅助一个反射shader,可以比较简单的模拟出一个镜面效果。

    代码

    Shader "Unlit/TwoPassReflection"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    	}
    	SubShader
    	{
    		Tags { "RenderType"="Opaque" "Queue"="Geometry" }
    		LOD 100
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			// make fog work
    			#pragma multi_compile_fog
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				UNITY_FOG_COORDS(1)
    				float4 vertex : SV_POSITION;
    			};
    
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    				UNITY_TRANSFER_FOG(o,o.vertex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    				// sample the texture
    				fixed4 col = tex2D(_MainTex, i.uv);
    				// apply fog
    				UNITY_APPLY_FOG(i.fogCoord, col);
    				return col;
    			}
    			ENDCG
    		}
    
            Pass
            {
                Stencil {
                    Ref 1          //0-255
                    Comp Equal     //default:always
                    Pass keep   //default:keep
                    Fail keep      //default:keep
                    ZFail keep     //default:keep
                }
                ZTest Always
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                
                #include "UnityCG.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                    float4 normal: NORMAL;
                };
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    UNITY_FOG_COORDS(1)
                    float4 vertex : SV_POSITION;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
                
                v2f vert (appdata v)
                {
                    v2f o;
                    v.vertex.xyz=reflect(v.vertex.xyz,float3(-1.0f,0.0f,0.0f));
                    v.vertex.xyz=reflect(v.vertex.xyz,float3(0.0f,1.0f,0.0f));
                    v.vertex.x+=1.5f;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    UNITY_TRANSFER_FOG(o,o.vertex);
                    return o;
                }
                
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return col;
                }
                ENDCG
            }
    	}
    }
    
    Shader "Unlit/Mirror"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    	}
    	SubShader
    	{
    		Tags { "RenderType"="Opaque" "Queue"="Geometry-1" }
    		LOD 100
    
            Stencil {
                Ref 0          //0-255
                Comp always     //default:always
                Pass IncrSat   //default:keep
                Fail keep      //default:keep
                ZFail keep     //default:keep
            }
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			// make fog work
    			#pragma multi_compile_fog
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				UNITY_FOG_COORDS(1)
    				float4 vertex : SV_POSITION;
    			};
    
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    				UNITY_TRANSFER_FOG(o,o.vertex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    				// sample the texture
    				fixed4 col = tex2D(_MainTex, i.uv);
    				// apply fog
    				UNITY_APPLY_FOG(i.fogCoord, col);
    				return fixed4(0.2f,0.2f,0.2f,1.0f);
    			}
    			ENDCG
    		}
    	}
    }
    

    说明

    在TwoPassReflection.shader中,第一个pass正常渲染模型,第二个pass对顶点进行了一个简单的反射,并将ZTest设为always,然后将一个quad放入本体和倒影之间,它的效果是这样的:
    图5:使用TwoPassReflection.shader(无stencil测试)
    图5:使用TwoPassReflection.shader,无mirror.shader

    倒影超出了想要的范围。解决这一问题,在quad上使用mirror.shader将quad覆盖的像素stencil值改为1,并在TwoPassReflection第二个pass中约定只在stencil值为1的区域中渲染。

    效果

    图5:quad使用mirror.shader
    图6:quad使用mirror.shader

    这里有个前提是mirror必须在倒影之前渲染以先将反射区域的stencil值标记好。

     
     
    5,阴影体shadow volume阴影渲染

    说明

    shadow volume阴影体算法是将‘遮光体’遮挡光源后产生的阴影实例为一个几何体,对在该阴影几何体的渲染过程中找出应该渲染阴影效果的像素。
    图6:圆柱阴影体
    图7:圆柱阴影体

    检测手段有几种,本案例shader采用的是Depth Fail,也叫Carmack’s reverse方法的思路。它的思想与步骤如下:

    1,在一般物体渲染后,渲染阴影体,第一个pass cull front,渲染内侧,在stencil测试阶段如果发现深度测试失败,说明该像素在阴影体内部表面或阴影体外部表面与视角之间有发生遮挡,将该像素stencil值加1。

    2,第二个pass cull back,渲染外侧,如果有深度测试失败,则说明该像素在阴影体外部表面与视角之间有发生遮挡,将该像素stencil值减1。

    3,经过两个pass的stencil操作,只有在阴影体内部的物体且它遮挡住阴影体内部表面的部分的stencil值为1。对阴影体内stencil值为1的像素进行渲染。

    本文中的shader只为展示stencil buffer在此技术中的角色,缺乏正确的阴影体网格或它的动态生成手段,粗暴的用Unity默认几何体中的圆柱体模拟一个阴影体,并且算法中也没有考虑被阴影覆盖的物体自身的阴影体的问题以及其他细节问题。

    代码

    Shader "Unlit/SV_DepthFailBeta"
    {
        Properties
        {
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" "Queue"="Geometry+1"}  //在渲染所有阴影体内物体后再渲染阴影体
            LOD 100
            
            CGINCLUDE       //三个pass内着色器内容相同
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
            };
    
            struct v2f
            {
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };
    
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return fixed4(0.3,0.3,0.3,1);           //影子颜色
            }
            ENDCG
    
            Pass
            {
                Cull Front          //阴影体内侧像素Z测试失败,stencil值加1
                Stencil {           
                    Ref 0           //0-255
                    Comp always     //default:always
                    Pass keep       //default:keep
                    Fail keep       //default:keep
                    ZFail IncrWrap  //default:keep
                }
    
                ColorMask 0         //关闭color buffer写入
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                ENDCG
            }
            
            Pass
            {
                Cull Back           //阴影体外侧像素Z测试失败,stencil值减1
                Stencil {
                    Ref 0           //0-255
                    Comp always     //default:always
                    Pass keep       //default:keep
                    Fail keep       //default:keep
                    ZFail DecrWrap  //default:keep
                }
                ColorMask 0         //关闭color buffer写入
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                ENDCG
            }
    
            Pass
            {
                Cull Back          //经过前两个pass,stencil值为1的值为在此阴影体内被阴影覆盖的像素
                Stencil {
                    Ref 1          //0-255
                    Comp equal     //default:always
                    Pass keep   //default:keep
                    Fail keep      //default:keep
                    ZFail keep  //default:keep
                }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                ENDCG
            }
        }
    }
    

    效果

    图7:使用SV_DepthFailBeta.shader
    图8:使用SV_DepthFailBeta.shader


    参考:

    Shadow Volume–Depth Fail, wikipedia:
    https://en.wikipedia.org/wiki/Shadow_volume#Depth_fail

    Creating Reflections and Shadows Using Stencil, BuffersMark J. Kilgard:
    https://www2.cs.duke.edu/courses/spring15/cps124/classwork/14_buffers/stencil.pdf

    Stencil Shadow Volume, OGL:
    http://ogldev.atspace.co.uk/www/tutorial40/tutorial40.html

    ShaderLab: Stencil, Unity:
    https://docs.unity3d.com/Manual/SL-Stencil.html

    Simon F’s answer to topic of ‘Uses for Stencil Buffer’ :
    https://computergraphics.stackexchange.com/questions/5046/uses-for-stencil-buffer


    本文示例项目Github连接:
    https://github.com/liu-if-else/UnityStencilBufferUses


    本文英文版:
    https://liu-if-else.github.io/stencil-buffer’s-uses-in-unity3d/


    维护日志:
    2020-8-16:review

    展开全文
  • 限定鼠标区域LimitCursorPos限定鼠标区域LimitCursorPos限定鼠标区域LimitCursorPos
  • 限定鼠标活动区域

    2012-10-09 08:15:46
    限定鼠标在一个应用程序内活动,此例是限定鼠标在窗口化魔兽的窗口内,如需该变,只需将代码中窗口名称改为你想限定的程序名称即可。此外还包含最小化程序到系统区的代码
  • 内容索引:VC/C++源码,系统相关,鼠标 VC++编程实现限定鼠标的移动区域,将鼠标限制在一定的区域内滑动,是不是编写游戏的时候要用到?这里要注意一下,如果点击限制的话,那么释放按钮你是不是很难点击到,要做好...
  • 提出一种局部限定搜索区域的特征匹配算法,将空间约束与局部描述符结合起来。该算法在ASIFT算法基础之上,针对在特征匹配阶段直接去除一对多、多对一的特征点的缺陷做出了改进。由于这些被去掉的特征点中有很多是...
  • 摘要:VB源码,系统相关,鼠标区域限制  VB版鼠标移动区域限定与释放实例源程序,程序代码部分包括自定义Release过程、自定义RestrictToControl过程、自定义CenterOnControl过程、自定义RestrictToForm过程、...
  • js限定区域范围拖拉拽 需要在范围内拖拉拽,之前看来许多资料觉得都不是特别满足要求,今天自己写了一个,通过监听鼠标按下、鼠标抬起、鼠标移动事件来控制 代码如下 <!DOCTYPE html> <html lang="en">...

    js限定区域范围拖拉拽


    需要在范围内拖拉拽,之前看来许多资料觉得都不是特别满足要求,今天自己写了一个,通过监听鼠标按下、鼠标抬起、鼠标移动事件来控制

    代码如下

    <!DOCTYPE html>
    
    <html lang="en">
    
      <head>
    
        <meta charset="UTF-8" />
    
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
        <title>Document</title>
    
        <style>
    
          #drag {
    
            background: aqua;
    
            width: 200px;
    
            height: 200px;
    
            position: absolute;
    
            -moz-user-select: none;
    
            -khtml-user-select: none;
    
            user-select: none;
    
          }
    
          #parent {
    
            position: relative;
    
            background: #cde4dc;
    
            height: 80vh;
    
            overflow: hidden;
    
          }
    
        </style>
    
      </head>
    
      <body>
    
        <section id="parent">
    
          <div id="drag"><div>这是一个测试</div></div>
    
        </section>
    
        <script type="text/javascript">
    
          //自执行函数,需要拖拽的元素需要设置position:absolute,父元素position:relative
    
          //有传父亲节点、若无则默认body为父节点
    
          ((parent, children, mouseType) => {
    
            if (!children) return;
    
            let childrenDiv = document.querySelector(children);
    
            childrenDiv.style.position = 'absolute';
    
            let parentDiv = parent
    
              ? document.querySelector(parent)
    
              : document.querySelector('body');
    
            let isDown = false;
    
            let x,
    
              y,
    
              l,
    
              t = 0;
    
            childrenDiv.onmousedown = function (e) {
    
              x = e.clientX;
    
              y = e.clientY;
    
              // 获取左部和底部的偏移量
    
              l = childrenDiv.offsetLeft;
    
              t = childrenDiv.offsetTop;
    
              isDown = true;
    
              childrenDiv.style.cursor = mouseType || 'move';
    
            };
    
            // 鼠标移动
    
            window.onmousemove = function (e) {
    
              if (!isDown) {
    
                return;
    
              }
    
              //获取移动后的x和y坐标
    
              let nx = e.clientX;
    
              let ny = e.clientY;
    
              //获取父元素的宽高
    
              let parentWidth = parentDiv.clientWidth;
    
              let parentHeight = parentDiv.clientHeight;
    
              //获取子元素的宽高
    
              let childrenWidth = childrenDiv.clientWidth;
    
              let childrenHight = childrenDiv.clientHeight;
    
              // 计算移动后的左偏移量和顶部偏移量
    
              let nLeft = nx - (x - l);
    
              let nTop = ny - (y - t);
    
              let nRight = nLeft + childrenWidth;
    
              let nBottom = nTop + childrenHight;
    
              nLeft = nLeft <= 0 ? 0 : nLeft; //判断左边距离是否越界
    
              nTop = nTop <= 0 ? 0 : nTop; //判断上边距离是否越界
    
              //判断右边距离大于父元素宽度
    
              if (nRight >= parentWidth) {
    
                nLeft = parentWidth - childrenHight;
    
              }
    
              // 判断下边界是否越界
    
              if (nBottom >= parentHeight) nTop = parentHeight - childrenHight;
    
              childrenDiv.style.left = nLeft + 'px';
    
              childrenDiv.style.top = nTop + 'px';
    
            };
    
            // 鼠标抬起事件
    
            document.onmouseup = function (e) {
    
              //鼠标抬起
    
              isDown = false;
    
              childrenDiv.style.cursor = 'default';
    
            };
    
          })('#parent', '#drag', 'move');
    
        </script>
    
      </body>
    
    </html>
    

    在这里插入图片描述

    展开全文
  • VC6 限定鼠标区域

    2010-03-31 11:19:47
    一个简单的程序,实现了对鼠标移动区域的控制。初学者都能看懂!!!
  • MFC限定区域画图

    千次阅读 2010-08-30 22:21:00
     //在该区域内画图有效  rgn.CreateRectRgn(292,45,519,376);   pDC->SelectClipRgn(&rgn);  int oldMode; //还原画笔模式  oldMode = pDC->GetROP2();   pDC->SetROP2(R2_NOT); //异或笔模式 ...

    代码有点冗长,不知哪位高手可修改下。

    -------------------------鼠标移动---------------------------

    void CGDIDlg::OnMouseMove(UINT nFlags, CPoint point)
    {
     // TODO: Add your message handler code here and/or call default
     if (GetCapture() != this)
      return;
     CDC *pDC = GetDC();
     CRgn rgn;                                //在该区域内画图有效
     rgn.CreateRectRgn(292,45,519,376);    
     pDC->SelectClipRgn(&rgn);

     int oldMode;                             //还原画笔模式
     oldMode = pDC->GetROP2();    


     pDC->SetROP2(R2_NOT);                //异或笔模式

     pDC->MoveTo(m_Pre);  //删除之前的线
     pDC->LineTo(m_Old);
     
     pDC->MoveTo(m_Pre); //画新线
     pDC->LineTo(point);

     pDC->SetROP2(oldMode);   //还原原来的模式
     
     m_Old = point;

      ReleaseDC(pDC);

    }

    -------------------------------左按钮按下----------------------------------------

    void CGDIDlg::OnLButtonDown(UINT nFlags, CPoint point)
    {
     // TODO: Add your message handler code here and/or call default
     UpdateData();
     CDC *pDC = GetDC();
     CRgn rgn;
     rgn.CreateRectRgn(292,45,519,376);                     //画图区域设定
     pDC->SelectClipRgn(&rgn);

     Pensty = m_combo.GetCurSel();
     newPen.CreatePen(Pensty, m_width, RGB(m_RGB_x, m_RGB_y, m_RGB_z));
     m_Pre = point;
     m_Old = point;
     SetCapture();
     CDialog::OnRButtonDown(nFlags, point);
    }

     

    ----------------------------左按钮松开-----------------------------------------

    void CGDIDlg::OnLButtonUp(UINT nFlags, CPoint point)
    {

      if (GetCapture() != this)
             return;
       CPen *pPenOld;
       CDC *pDC=GetDC();
       CRgn rgn;
       rgn.CreateRectRgn(292,45,519,376);
       pDC->SelectClipRgn(&rgn);
      
       pPenOld=pDC->SelectObject(&newPen);  

      
     if(m_choice == 1)
      {
       pDC->Rectangle(m_Pre.x ,m_Pre.y, point.x, point.y);  //矩形
      }
      else if(m_choice == 2)         //圆
      {
       int oldMode = pDC->GetROP2();
       pDC->SetROP2(R2_NOT);   
       
       pDC->MoveTo(m_Pre);  //删除之前的线
       pDC->LineTo(m_Old);
      
       pDC->SetROP2(oldMode);
       pDC->Ellipse(m_Pre.x,m_Pre.y, point.x, point.y);

       
      }
      else
      {
        pDC->MoveTo(m_Pre);   
           pDC->LineTo(point);
      }
          ReleaseDC(pDC);
       newPen.DeleteObject(); 
       ReleaseCapture();
     // CDialog::OnLButtonUp(nFlags, point);
    }

     

    展开全文
  • new限定区域分配内存

    2017-07-12 17:38:40
    这说明我们可以通过new的这种语法对已经存在的内存区域上构造数据。而且我们可以发现new不仅仅可以在堆中分配内存,而且可以使用静态存储区中的内存。但是这样p1指向的内存会产生泄露,所以修改代码: #include ...
    #include <iostream>
    #include<stdio.h>
    #include <new>//需要添加该头文件
    
    using namespace std;
    cons    t int ARRLEN = 100;
    int static_buf[ARRLEN];//静态区
    const int N = 5;
    int main()
    {
        int *p1,*p2;
    
        cout<<"static_buf address:"<<static_buf<<endl;
    for(int j = 0; j < 3; j++)
    {
        cout<<"\n\n\n";
        p1 = new int[N];
        p2 = new (static_buf)int[N];//指定区域分配内存
        for(int i = 0; i < N; i++)
        {
            p1[i] = p2[i] = i;
            cout<<"p1-->"<<&p1[i]<<"   value:"<<p1[i]<<"  ";
            cout<<"p2-->"<<&p2[i]<<"   value:"<<p2[i]<<endl;//打印出每个元素的地址和值
        }
    }
    return 0;
    }
    

    运行结果为:
    这里写图片描述

    可见,经过三次循环后p2指向的数组的地址并没有改变,而且该地址就是在静态存储器中分配的static_buf的地址。这说明我们可以通过new的这种语法对已经存在的内存区域上构造数据。而且我们可以发现new不仅仅可以在堆中分配内存,而且可以使用静态存储区中的内存。但是这样p1指向的内存会产生泄露,所以修改代码:

    #include <iostream>
    #include<stdio.h>
    #include <new>//需要添加该头文件
    
    using namespace std;
    const int ARRLEN = 100;
    int static_buf[ARRLEN];//静态区
    const int N = 5;
    int main()
    {
        int *p1,*p2;
    
        cout<<"   static_buf address:"<<static_buf<<endl;
        for(int j = 0; j < 3; j++)
        {
            cout<<"\n\n\n";
            p1 = new int[N];
            p2 = new (static_buf)int[N];//指定区域分配内存
            for(int i = 0; i < N; i++)
            {
                p1[i] = p2[i] = i;
                cout<<"   p1-->"<<&p1[i]<<"   value:"<<p1[i]<<"  ";
                cout<<"   p2-->"<<&p2[i]<<"   value:"<<p2[i]<<endl;//打印出每个元素的地址和值
            }
    
            delete []p1;
        }
        return 0;
    }
    

    运行结果为:
    这里写图片描述

    可见,现在每次delete掉p1,再次new后,数组的内存地址是一样的。
    所以我们应该可以根据这个区别来判断是否发生了内存泄露。如果程序请求分配一块堆内存,应该是根据堆的内存指针来决定所分配内存的地址的,如果这块内存已经delete掉了,那么第二次分配的内存地址应该和第一次的地址一样(假设中间没有任何内存操作,不考虑其他程序干扰)。
     
    总结一下:
    1.p1存在栈中,存储的地址指向堆。
    p1需要手动释放。
     
    p2存在栈中,存储的地址指向静态区。
    p2自动释放。避免了内存泄露,牺牲了内存访问的独立性(第二次new的时候,第一次new产生的数据的没了)。
     
    2.由于p2的这种特性,所以本例中的static_buf一般在工程应用中作为一个缓冲区。

    展开全文
  • 鼠标移动区域限定与释放,VB6.0实例源代码,程序代码部分包括自定义Release过程、自定义RestrictToControl过程、自定义CenterOnControl过程、自定义RestrictToForm过程、自定义CenterOnForm过程、自定义...
  • 光刻限定区域制备硅纳米线,于航,端木庆铎,基于金属辅助化学刻蚀机理,在光刻限定区域制备硅纳米线,实验过程中通过调整刻蚀时间来控制硅纳米线长度,通过扫描电子显微镜
  • 今天用 EasyTouch 写了个旋转模型的 限定区域位置的 先记录一下 怕以后忘记了 //初始化 protected override void OnInit(object data)//添加注册 { base.OnInit(data); EasyTouch.SetEnabled(true); EasyTouch.On_...
  • C++ new限定区域分配内存

    千次阅读 2015-05-10 18:57:18
    C++中从指定区域分配内存: #include using namespace std; const int buf(1024); char buffer[buf]={0}; //开辟静态区域 //p1,p3作为指针变量在栈区,存储的地址指向堆区 //手动释放内存 //p2,p4作为指针变量...
  • 本文实例讲述了php实现在限定区域里自动调整字体大小的类。分享给大家供大家参考。具体如下: 这里的php类imagefittext.class.php实现在限定区域里自动调整字体大小的功能。 <?php // Image Fit Text Class ...
  • VC++ 编程实现 限定鼠标的移动区域 源码 VC++编程实现限定鼠标的移动区域,将鼠标限制在一定的区域内滑动,是不是编写游戏的时候要用到?这里要注意一下,如果点击限制的话,那么释放按钮你是不是很难点击到,要做好...
  • 锁定鼠标,锁死鼠标,或将鼠标限制在一定区域内.
  • 将iPad限定于某一APP或区域使用方法

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,245
精华内容 498
关键字:

区域限定