D3Dshader,像素着色器实现多种形状放大镜(圆形、方形、三角形、梯形、六边形、心形、五角星形)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

之前实现了一系列不同形状的放大镜,参考了网上很多文章以及资料,完成后发上来分享一下。


提示:以下是本篇文章正文内容,下面案例可供参考

一、圆形放大镜

作为最基础的放大镜样式,实现起来也比较简单,在指定圆形区域的纹理乘以一个放大系数(小于零),直接上代码,在代码里注释。

    //int magnifying_Center_x; //镜头中心x坐标(-100到100)
    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
    //int magnifying_Radius; //(0到100)放大镜半径    
    //int magnifyingl_Times; //(0到10)放大倍率
    //v2TexSize为窗口大小 例如(1920,1080)
    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小
    
    float dist = distance(tex, center);//当前纹理点与放大镜中心的距离

    //圆内
        if (dist < radius)//当前纹理点在放大镜中时
        {       
            tex -= center;//将纹理坐标轴移动到以放大镜中心为原心的纹理坐标空间
        
            tex = tex * Times;//放大,即让当前纹理显示更靠进圆心的纹理区域
                       
            tex += center;//恢复成原来的纹理坐标空间
            
          }
    float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize); //拿到当前放大镜处理后的纹理        
    return outp;//输出

效果:在这里插入图片描述

三、矩形放大镜

根据圆心以及半径划定一个矩形区域
关键区域的代码如下:

	//int magnifying_Center_x; //镜头中心x坐标(-100到100)
    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
    //int magnifying_Radius; //(0到100)放大镜半径    
    //int magnifyingl_Times; //(0到10)放大倍率
    //v2TexSize为窗口大小 例如(1920,1080)
    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小
    
        //当前纹理在矩形区域内,矩形边长为radius 
        if ((tex.x < center.x + radius / 2) && (tex.x > center.x - radius / 2) && (tex.y < center.y + radius / 2) && (tex.y > center.y - radius / 2))
        {
            tex -= center;
            tex = tex * Times;
            tex += center;            
        }
    float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize); //拿到当前放大镜处理后的纹理        
    return outp;//输出   

效果如下:
在这里插入图片描述

四、三角形放大镜

关键区域的代码如下:

	    //int magnifying_Center_x; //镜头中心x坐标(-100到100)
	    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
	    //int magnifying_Radius; //(0到100)放大镜半径    
	    //int magnifyingl_Times; //(0到10)放大倍率
	    //v2TexSize为窗口大小 例如(1920,1080)
	    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
	    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
	    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
	    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小

        float g = sin(PI/3)*2;
        center.y += (g / 4) * radius;
        tex -= center;
         //a、b、c为三角形的三个顶点
        float2 a = float2(-radius / 2, 0);
        float2 b = float2(0, -radius * g/2);
        float2 c = float2(radius / 2, 0);
 
         
        if (inTriangle(a, b, c, tex))//tex是否在abc构成的三角形内
        {
            tex = tex * Times;
        }
        tex += center;
	    float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize); //拿到当前放大镜处理后的纹理        
	    return outp;//输出
        
        
         

inTriangle函数用以判断当前点tex是否在abc三点构成的三角形内,也就是说可以通过更改abc三个点的位置来更改三角形的形状,后续的五角星放大镜也用到了这个函数。其中用到了伪叉积的概念,伪叉积就不展开说了,可以百度,inTriangle函数如下所示:
参考文章链接:链接

bool inTriangle(float2 a, float2 b, float2 c, float2 tex)
{
    float2 AB = float2(b - a);
    float2 BC = float2(c - b);
    float2 CA = float2(a - c);
        
    float2 AP = float2(tex - a);
    float2 BP = float2(tex - b);
    float2 CP = float2(tex - c);
        
        
    bool Out_In1 = AB.x * AP.y - AB.y * AP.x > 0
        && BC.x * BP.y - BC.y * BP.x > 0
        && CA.x * CP.y - CA.y * CP.x > 0;
    bool Out_In2 = AB.x * AP.y - AB.y * AP.x < 0
        && BC.x * BP.y - BC.y * BP.x < 0
        && CA.x * CP.y - CA.y * CP.x < 0;
    return Out_In1 || Out_In2;
    
}

三角形马赛克效果如下:
在这里插入图片描述

五、梯形放大镜

跟之前的操作类似,求出梯形的区域,在区域内的纹理进行放大操作。

	    //int magnifying_Center_x; //镜头中心x坐标(-100到100)
	    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
	    //int magnifying_Radius; //(0到100)放大镜半径    
	    //int magnifyingl_Times; //(0到10)放大倍率
	    //v2TexSize为窗口大小 例如(1920,1080)
	    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
	    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
	    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
	    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小
	    
        //以梯形底边中心为原点,求出另外两条直线的公式
        float a = 1.732; //根号三  另外两条边的公式 1:y=-ax-(a/2)*R  2: y=ax-(a/2)*R 
        center.y += (a / 4) * radius;
        if (tex.y < center.y && tex.y > center.y - (a / 2) * radius)//将范围限定在梯形上下两边中
        {
            tex -= center;
        	//梯形内
            if ((tex.y > (-1 * a * tex.x - a * radius)) && (tex.y > ( a * tex.x - a * radius)))
            {
            
                tex = tex * Times;
            }
        }
        tex += center;
	    float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize); //拿到当前放大镜处理后的纹理        
	    return outp;//输出
 

在这里插入图片描述

六、六边形放大镜

六边形区域可由上下两边+剩下四个斜边构成:

        //int magnifying_Center_x; //镜头中心x坐标(-100到100)
	    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
	    //int magnifying_Radius; //(0到100)放大镜半径    
	    //int magnifyingl_Times; //(0到10)放大倍率
	    //v2TexSize为窗口大小 例如(1920,1080)
	    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
	    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
	    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
	    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小
	    
        //以六边形中点为原点,求出另外四条直线的公式
        //1.732=根号三  另外四条边的公式 1:y=-ax-a*R  2: y=ax-2*R 3:y=a*x+a*R ,4:y=-a*x+a*R
        float a = sin(PI/3)*2;
       
        if ((tex.y < center.y + radius / 2) && (tex.y > center.y - radius / 2))//将范围限定上下
        {    
            tex -= center;
            radius *=0.6;
            if ((tex.y > (-1. * a * tex.x - a * radius)) && (tex.y > (a * tex.x - a * radius)) && (tex.y < (a * tex.x + a * radius)) && (tex.y < (-1.*a * tex.x + a * radius)))
            {
            
                tex = tex * Times;         
            }
            tex += center;  
        }
	    float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize); //拿到当前放大镜处理后的纹理        
	    return outp;//输出

在这里插入图片描述
当然,也可以按照之前画三角形的方法实现,六边形就是由六个三角形构成的。

七、心形放大镜

心形放大镜的核心在于构建出一个心形区域。

         //int magnifying_Center_x; //镜头中心x坐标(-100到100)
	    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
	    //int magnifying_Radius; //(0到100)放大镜半径    
	    //int magnifyingl_Times; //(0到10)放大倍率
	    //v2TexSize为窗口大小 例如(1920,1080)
	    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
	    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
	    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
	    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小
	    
        //爱心公式((x*x+y*y-1)^3)=x^2*y^3
        tex -= center; //以中心为原点        
        if (inHeart(tex,  radius) != 0)
        {
            tex *= Times;
        } 
        tex += center;
        float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize);
float inHeart(float2 tex, float size)//用于判断当前点是否在心性内部
{
    if (size == 0.)
    {
        return 0;
    }
    tex /= size;
    
    
    float s = tex.x * tex.x - tex.y * -tex.y - 1;
    //爱心公式((x*x+y*y-1)^3)=x^2*y^3
    float f1 = s * s * s;
    float f2 = tex.x * tex.x * tex.y * tex.y * tex.y * -1;
    return step(f1, f2);

}

效果:
在这里插入图片描述

八、五角星形放大镜

五角星是由十个三角形构成的,首先求出这十个三角形的各点的坐标,再判断当前点是否在这十个三角形内。
参考的文章:链接
代码:

   		//int magnifying_Center_x; //镜头中心x坐标(-100到100)
	    //int magnifying_Center_y; //镜头中心y坐标(-100到100)
	    //int magnifying_Radius; //(0到100)放大镜半径    
	    //int magnifyingl_Times; //(0到10)放大倍率
	    //v2TexSize为窗口大小 例如(1920,1080)
	    float2 center = float2(0.5 + magnifying_Center_x / 200, 0.5-magnifying_Center_y / 200) * v2TexSize;//计算出放大镜中心点
	    float radius = magnifying_Radius / 100 * v2TexSize.y;//一般情况下窗口都是呈现长方形的,选取短边作为半径扩展系数
	    float Times = (1 - magnifyingl_Times / 10);//计算出放大的倍率,Times 越小,放大程度越大
	    tex *= v2TexSize;//将范围(0-1)的纹理恢复至窗口大小
   		
		float R = radius;//外五角半径
        float r = radius * sin(PI/10.) / cos(PI/5.);//内五角半径
        float2 PointO[5];//外五角
        float2 PointI[5];//内五角
        
        tex -= center;        
   
        for (int i = 0; i < 5; i++)
        {
            PointO[i] = float2(R * cos(0.5 * PI + i * 0.4 * PI), -R * sin(0.5 * PI + i * 0.4 * PI));
 			PointI[i] = float2(r * cos(0.7 * PI + i * 0.4 * PI), -r * sin(0.7 * PI + i * 0.4 * PI));
            if (inTriangle(float2(0, 0), PointO[i], PointI[i], tex))
            {
                tex *= Times;
            }
            
        }
        if (inTriangle(float2(0, 0), PointO[0], PointI[4], tex))
        {
            tex *= Times;
        }
        
        for (int j = 1;j < 5; j++)
        {
            if (inTriangle(float2(0, 0), PointO[j], PointI[j-1], tex))
            {
                tex *= Times;
            }
        }
       tex += center;
	    float4 outp = g_Tex.Sample(g_SamLinear, tex / v2TexSize); //拿到当前放大镜处理后的纹理        
	    return outp;//输出
        

效果:
在这里插入图片描述

总结

分享了使用HLSL实现七种不同形状放大镜的实现方法,其中有些方法肯定存在不足之处,欢迎指出,谢谢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用Java计算圆形三角形交集面积的示例代码: ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); // 输入圆坐标和半径 System.out.print("请输入圆坐标和半径(如x y r):"); double x = input.nextDouble(); double y = input.nextDouble(); double r = input.nextDouble(); // 输入三角形三个顶点坐标 System.out.print("请输入三角形三个顶点坐标(如x1 y1 x2 y2 x3 y3):"); double x1 = input.nextDouble(); double y1 = input.nextDouble(); double x2 = input.nextDouble(); double y2 = input.nextDouble(); double x3 = input.nextDouble(); double y3 = input.nextDouble(); // 计算圆三角形三个顶点的距离 double d1 = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); double d2 = Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); double d3 = Math.sqrt((x - x3) * (x - x3) + (y - y3) * (y - y3)); // 判断圆是否在三角形内 double p = (d1 + d2 + d3) / 2; double area = Math.sqrt(p * (p - d1) * (p - d2) * (p - d3)); boolean flag = false; if (area == 0) { flag = true; } // 计算圆形三角形交集面积 double s1 = Math.PI * r * r; // 圆形面积 double s2 = 0; // 三角形面积 if (!flag) { double a = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); double b = Math.sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3)); double c = Math.sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1)); double p2 = (a + b + c) / 2; s2 = Math.sqrt(p2 * (p2 - a) * (p2 - b) * (p2 - c)); // 三角形面积 } double s3 = 0; // 交集面积 if (r >= d1 && r >= d2 && r >= d3) { // 圆包含三角形 s3 = s2; } else if (r <= d1 && r <= d2 && r <= d3) { // 三角形包含圆 s3 = s1; } else { // 圆和三角形相交 double cos1 = (d2 * d2 + d3 * d3 - d1 * d1) / (2 * d2 * d3); double cos2 = (d1 * d1 + d3 * d3 - d2 * d2) / (2 * d1 * d3); double cos3 = (d1 * d1 + d2 * d2 - d3 * d3) / (2 * d1 * d2); double angle1 = Math.acos(cos1); double angle2 = Math.acos(cos2); double angle3 = Math.acos(cos3); double s4 = r * r * angle1 / 2; // 圆三角形第一个顶点所在的圆弧面积 double s5 = r * r * angle2 / 2; // 圆三角形第二个顶点所在的圆弧面积 double s6 = r * r * angle3 / 2; // 圆三角形第三个顶点所在的圆弧面积 s3 = s4 + s5 + s6 - s2; // 交集面积 } System.out.println("圆形面积:" + s1); System.out.println("三角形面积:" + s2); System.out.println("交集面积:" + s3); } } ``` 在运行程序时,按照提示输入圆坐标、半径和三角形三个顶点的坐标,即可计算出圆形面积、三角形面积和交集面积。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值