Interpretation of the shader series written by CG in unity-circular corner rectangle shader in Unity

Source: Internet
Author: User

In the previous article, we learned the surface removal and cropping modes.

This article will use this knowledge to implement a simple, but very common example: make an image into a rounded rectangle.


Example 3: shader with rounded corners

Well, I admit that I had taken a lot of detours in this example. As I have already learned all about the Matrix, I used some stupid methods to calculate the rounded rectangle at the beginning.

We know that textcoord0 is an object-based coordinate system, and its range is in the first quadrant of the coordinate system. The value ranges from (0, 0))

Then we will regard each image as a rectangle of 1x1 size.

We need to erase four corners in a rectangle of the size of 1x1, which should be like this:


Take the upper left corner as an example. If we make an auxiliary circle to cut into this angle and the radius is 0.1, We will erase this circle by 3/4, the remaining area formed by the yellow arc and the angle is the area to be erased:


This principle is very simple, so we can erase the four corners to get a rounded rectangle with a radius of 10%.


The first detour I took was to calculate the region. Is it calculated using the four-circle equation or distance?


Since the equation for giving four circles is too complicated, I will directly give the algorithm for calculating the outer distance:



First, an inner rectangle is made based on four centers in the inside of the large rectangle. The side length of the heart is 0.8.

Second, ignore the points inside the inner rectangle. In this red rectangle, given the outer point P of any blue rectangle, as long as the distance between P and the blue rectangle can be obtained, the distance is greater than 0.1 (RADIUS ), in this case, the image is erased directly outside the rounded rectangle ,:


We can see that the distance from P1, P2, P3, to the blue rectangle is the distance from P1 <radius, 2 times radius of the root number> P2> radius, and the distance from P3 is equal to the radius.

So P2 is outside the rounded rectangle, P1 and P3 are inside or at the edge of the rounded rectangle, So we erase P2.

The distance between P3 is exactly the minimum distance from P3 to four straight lines.

Similarly, p1

The P2 distance cannot be calculated in this way, but it should be the minimum value of the distance from p2 to four vertices.



Based on this algorithm, you only need to calculate the distance from all the external points to the area of the blue rectangle, and then determine the size from the radius. If the value is greater than the radius, the rounded rectangle can be obtained.


At first, I came up with an extremely brainless method based on this idea:


Given any point of P, calculate the distance between P and four straight lines and four vertices, and then calculate the minimum value among the eight distances as the final distance to compare with the radius.


After excited writing the code, I knew I was wrong. After checking it for a long time, I realized that the minimum distance between the eight points, such as P3, is not the distance from the vertex, but the distance to the extended line of the two sides.


So the algorithm for finding the minimum value by the 8-distance eventually ended in failure.


Still have to be honest

So there are several situations.

There is actually only one type, but there are two types according to the normal logic:


Let's take a look at the external points of the green and purple regions.

1. When the external point is in the purple area, the distance should be the minimum distance from the point to the 4 Vertex

2. When the external point is in the green area, the distance should be the minimum distance from the point to the four straight lines

Based on this idea, we can judge any point (x, y) in the whole coordinate system:

1. If you still calculate the wool distance in the white or green area, it is definitely not discard ~~~~ (I did it before)


2. Calculate the distance from vertex 4 in the purple area, take the minimum value, and remove the part greater than 0.1.


Finally, we need to extract the 0.1 as a variable and cannot write it to death. This can be easily adjusted in inspector or set in script, that is, to define a float or rang attribute for our shader.


The final code is:


Shader "Custom/roundrect" {properties {// two content modes: image mode _ maintex ("base (RGB)", 2d) = "white" {} // solid color mode // _ maincolor ("color", color) = (,) // the radius of the rounded corner. The default value is 0.20.roundradius ("radius ", float) = 0.1} subshader {pass {cgprogram # pragma fragment frag # include "unitycg. cginc "// obtain the three attributes and pass the values to the CG code snippet sampler2d _ maintex; float _ roundradius; float4 _ maincolor; // The input struct of the fragment shader (omitted) struct fraginput {float2 texcoord: texcoord0 ;}; // fragment iterator Function float4 frag (fraginput input): Color {float4 c = tex2d (_ maintex, input. texcoord); // convert the image information into colors by coordinate conversion. // float4 c = _ maincolor; // solid color // X and Y, the interval is [0, 1] float x = input. texcoord. x; float y = input. texcoord. y; // float XT = 1-_ roundradius; float XB = _ roundradius; float yl = _ roundradius; float yr = 1-_ roundradius; // If (X, Y) is not in the rectangle composed of four straight lines (the white area) if (! (X <XT & x> XB & Y> yl & Y <yr) {// If (x. y) is not in the green region if (! (X <XT & x> xb) | (Y> yl & Y <yr) // it seems that the judgment is complicated due to poor mathematics, if you can directly write an inequality group in the purple region, you can simply {// calculate the coordinates of the four vertices float2 PLB = float2 (_ roundradius, _ roundradius ); float2 PLT = float2 (_ roundradius, 1-_ roundradius); float2 PRT = float2 (1-_ roundradius, 1-_ roundradius); float2 PRB = float2 (1-_ response, _ roundradius); // calculate the distance from X, Y to four vertices respectively float distlb = SQRT (POW (x-plb.x), 2) + POW (y-plb.y ), 2); float distlt = SQRT (POW (x-plt.x), 2) + POW (y-plt.y), 2); float distrt = SQRT (POW (x-prt.x ), 2) + POW (y-prt.y), 2); float distrb = SQRT (POW (x-prb.x), 2) + POW (y-prb.y), 2 )); // take the minimum float Dist = min (distlb, distlt) for the four distances; Dist = min (Dist, distrt); Dist = min (Dist, distrb ); // remove the IF (Dist> _ roundradius) discard;} return C;} endcg} fallback "diffuse "}


For the final running effect, the rounded rectangle is removed for images of different radius sizes.


When the radius is set to 0.25, we can get a circle, so our roundradius attribute can be set to 0.01 ~ Rang of 0.25


Because I am a Windows system, it seems a problem in Mac OS. I don't know if the problem of vertex coloring is omitted. I will fix it again after finding the cause.



If my blog is helpful to you or you have any questions, you are welcome to join the U3D communication QQ Group in Chongqing. I will give you a question: 68994667. You can also join the group to discuss the technology with us.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.