Home>

### Unity Shader achieves book turning effect

I just use a texture here.Let's call it "turning the boards", haha.

Implementation process:

In fact, this effect is quite simple to achieve,Probably the idea is actuallyRotate all vertices around the z axis and make them a little radian with sine and cosine.

Let's start step by step to achieve this effect.

First open Unity to create a new project,Scene, and create a shader file named openbookeffect, delete the original redundant code.

first step,Let's make it rotate around the z-axis first

A rotation matrix is ​​used here,Multiply the vertices by the matrix,You can get the position after rotation.(Ps:I won't explain in detail how the rotation matrix is ​​derived here.Those interested can go to Baidu to find out.)

There are three types of rotation matrices:

1. Rotate around the x axis:

2. Rotate around the y-axis

3. Rotate around the z axis

Obviously, we need to use the thirdMatrix rotated around z axis. Below we use code to build a rotation matrix and rotate it by a certain angle:

properties
{
_maintex ("texture", 2d)="white" {}
//Rotation angle
_angle ("angle", range (0,180))=0
}
....
sampler2d _maintex;
//angle
float _angle;
v2f vert (appdata v)
{
v2f o;
float s;
float c;
//This method can calculate the sine and cosine of the angle
//rotation matrix
float4x4 rotatematrix={
c, s, 0,0,  -s, c, 0,0,  0, 0,1,0,  0, 0,0,1
};
//left vertex multiplied by rotation matrix
v.vertex=mul (rotatematrix, v.vertex);
//Convert model space to crop space
o.vertex=unityobjecttoclippos (v.vertex);
o.uv=v.uv;
return o;
}
....

Edit_angleto rotate the plane,As shown in the figure:

Through testing,This rotation is not the effect we want,The axis of rotation is now in the center,We want its axis of rotation to be on the far left,At this point, you need to put all vertices in theSpinBeforeLeft offset by 5 units,After the rotation is completedGo toOffset 5 units to the rightWe can achieve the effect we want,code show as below:

v2f vert (appdata v)
{
v2f o;
//Offset 5 units to the left before rotation
v.vertex-= float4 (5,0,0,0);
float s;
float c;
//This method can calculate the sine and cosine of the angle
//rotation matrix
float4x4 rotatematrix={
c, s, 0,0,   -s, c, 0,0,   0, 0,1,0,   0, 0,0,1
};
//left vertex multiplied by rotation matrix
v.vertex=mul (rotatematrix, v.vertex);
//Offset back after rotation
v.vertex +=float4 (5,0,0,0);
//Convert model space to crop space
o.vertex=unityobjecttoclippos (v.vertex);
o.uv=v.uv;
return o;
}

Now it looks a little like a book,But now the flip book effect is too blunt,In order to get close to the real flipbook effect,We need to passSine cosine functionModify theof a vertexy coordinateto reach aradian.

v2f vert (appdata v)
{
v2f o;
//Offset 5 units to the right before rotation
v.vertex-= float4 (5,0,0,0);
float s;
float c;
//This method can calculate the sine and cosine of the angle
//rotation matrix
float4x4 rotatematrix={
c, s, 0,0,  -s, c, 0,0,  0, 0,1,0,  0, 0,0,1
};
//Calculate the sine value of the y coordinate by the sine function according to the x coordinate, _wavelength controls the wavelength, The amplitude changes dynamically with the sine of the angle
v.vertex.y=sin (v.vertex.x * _wavelength) * s;
//left vertex multiplied by rotation matrix
v.vertex=mul (rotatematrix, v.vertex);
//Offset back after rotation
v.vertex +=float4 (5,0,0,0);
//Convert model space to crop space
o.vertex=unityobjecttoclippos (v.vertex);
o.uv=v.uv;
return o;
}

The effect is as follows:

Now look at the effect is not widened.It feels pretty good,But it's not over yet,If we look carefully, we will find that the process of "turning the book" is a bit unreal on the backShould not be the opposite of the texture,But another new texture,What should we do now?

it's actually really easy,Just need to render the front and back separately.One pass renders the front,A pass renders the back.

First we need to pass thecullThe instruction removes the side that does not need to be rendered.

The complete code is as follows:

{
properties
{
//front texture
_maintex ("texture", 2d)="white" {}
//Back texture
_sectex ("sectex", 2d)="white" {}
//Rotation angle
_angle ("angle", range (0,180))=0
//wavelength
_wavelength ("wavelength", range (-1,1))=0
}
{
pass
{
//Remove the back
cull back
cgprogram
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
struct appdata
{
float4 vertex:position;
float2 uv:texcoord0;
};
struct v2f
{
float2 uv:texcoord0;
float4 vertex:sv_position;
};
sampler2d _maintex;
float4 _maintex_st;
//angle
float _angle;
//wavelength
float _wavelength;
v2f vert (appdata v)
{
v2f o;
//Offset 5 units to the right before rotation
v.vertex-= float4 (5,0,0,0);
float s;
float c;
//This method can calculate the sine and cosine of the angle
//rotation matrix
float4x4 rotatematrix={
c, s, 0,0,          -s, c, 0,0,          0, 0,1,0,          0, 0,0,1
};
//Calculate the sine value of the y coordinate by the sine function according to the x coordinate, _wavelength controls the wavelength, The amplitude changes dynamically with the sine of the angle
v.vertex.y=sin (v.vertex.x * _wavelength) * s;
//left vertex multiplied by rotation matrix
v.vertex=mul (rotatematrix, v.vertex);
//Offset back after rotation
v.vertex +=float4 (5,0,0,0);
//Convert model space to crop space
o.vertex=unityobjecttoclippos (v.vertex);
o.uv=v.uv;
return o;
}
fixed4 frag (v2f i):sv_target
{
fixed4 col=tex2d (_maintex, i.uv);
return col;
}
endcg
}
pass
{
//Reject positive
cull front
cgprogram
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
struct appdata
{
float4 vertex:position;
float2 uv:texcoord0;
};
struct v2f
{
float2 uv:texcoord0;
float4 vertex:sv_position;
};
//angle
float _angle;
//wavelength
float _wavelength;
sampler2d _sectex;
float4 _sectex_st;
v2f vert (appdata v)
{
v2f o;
//Offset 5 units to the right before rotation
v.vertex-= float4 (5,0,0,0);
float s;
float c;
//This method can calculate the sine and cosine of the angle
//rotation matrix
float4x4 rotatematrix={
c, s, 0,0,          -s, c, 0,0,          0, 0,1,0,          0, 0,0,1
};
//Calculate the sine value of the y coordinate by the sine function according to the x coordinate
_wavelength controls the wavelength, The amplitude changes dynamically with the sine of the angle
v.vertex.y=sin (v.vertex.x * _wavelength) * s;
//left vertex multiplied by rotation matrix
v.vertex=mul (rotatematrix, v.vertex);
//Offset back after rotation
v.vertex +=float4 (5,0,0,0);
//Convert model space to crop space
o.vertex=unityobjecttoclippos (v.vertex);
o.uv=v.uv;
return o;
}
fixed4 frag (v2f i):sv_target
{
fixed4 col=tex2d (_sectex, i.uv);
return col;
}
endcg
}
}
}

final effect:

### Related articles

• Previous Python list comprehensions
• Next ADONET practical experience summary