Unity first-person visual portal production

introduction

Portals are used in many places in the game, just like Doraemon's arbitrary doors, go in from here, come out from there, let's implement it with Unity.
Here is a rendering first, please forgive me for not adding a beautiful door frame or special effects to the door, because there is no suitable material at hand, but this does not affect the function of any door, nor does it affect the principle of introducing it. In addition, there is no gif screenshot installed on the machine, so there is no animation, but the "energy fluctuation pattern" in the picture is with animation, please make up your own mind.
insert image description here
Here's another, portal, at least two.
insert image description here
Walk in from one end and come out from the other. The effect is still possible.
The principle and production method are introduced below:
the principle is this, use a camera to observe the image on the other side of the portal, and then render it on the plane of the portal at the local end, so that you can see the remote image in the portal at the local end The screen is gone.

1. Create a shader

Use ShaderGraph to make a Shader as shown in the figure below:
insert image description here
The principle of this shader is relatively simple. In fact, the most important thing is the bottom two nodes, and the top ones are all for the effect of energy fluctuations. Just connect the camera image, that is, a texture, to the BaseColor node. The most important thing is the UV node, which needs to use the screen space. Otherwise, the camera image will be compressed to the size of the door and deformed. Also note that this shader checks double-sided rendering, otherwise it will not be visible when you run behind the door.
Then use this Shader to make a material, right-click the ShaderGraph file just created, and select Create Material.

2. Create a door

Build a Quad plane as a portal. Assign the above material to it. Then create a camera and two empty objects under the door. The structure is as shown in the figure below:
insert image description here
Since another scene outside the door is to be displayed on the door, the image of the remote door camera is displayed on the local door material. In addition, it should be noted that, as mentioned in the above shader, the screen space must be used as the texture UV. There is another problem, that is, the texture size must match the screen size, at least the proportion must be the same, otherwise the picture on the door is to be deformed. This is actually very easy to solve. The texture can be dynamically created, and a texture can be dynamically created according to the screen size:

    // 获取门底下的相机组件
    Camera cam = m_ProtalCamera.GetComponent<Camera>();

    // 根据屏幕尺寸建一张纹理
    ProtalCameraTexture = new RenderTexture(Screen.width, Screen.height, 32)
    {
    
    
        name = "ProtalCameraTargetTexture"
    };

    // 将门下相机的渲染目标设置为该纹理
    cam.targetTexture = ProtalCameraTexture;
    // 设置相机不要观察门本身
    cam.cullingMask &= ~(1 << gameObject.layer);

Then it is to set the texture to the material of the door, also using code:

if( TargetDoor != null )
{
    
    
    // 获取到门的渲染组件
    MeshRenderer renderer = GetComponent<MeshRenderer>();
    foreach (var m in renderer.materials)
    {
    
    
        // 将本地门的材质纹理,设置为目标门摄像机的渲染纹理
        m.SetTexture("_MainTex", TargetDoor.ProtalCameraTexture);
    }
}

So, why are there two empty objects? Let me introduce the principle:
insert image description here
As shown in the figure above, since the orientation of the two ends of the portal is arbitrary, it is very important to know the relative position of the camera, otherwise the image angle at the door B seen by the door A will be incorrect. With the empty object above, all this becomes much simpler, and does not even require calculations, and does not require any mathematical knowledge.

    // 将主相机(角色)的世界坐标和朝向赋予A门表示主相机的空物体
    m_MainCameraPos.position = m_Camera.position; 
    m_MainCameraPos.rotation = m_Camera.rotation;

    // 将A门下表示主相机的空物体相对于A门的相对位置,赋予B门的相机,使得B门相机相对于B的相对位置与主相机相对于A门的相对位置相同
    TargetDoor.m_ProtalCamera.localPosition = m_MainCameraPos.localPosition;
    TargetDoor.m_ProtalCamera.localRotation = m_MainCameraPos.localRotation;

Please see the comments in the above code, the text is a bit convoluted, but the reasoning is easier to understand.

3. Realize transmission

There are two empty objects built in the above steps, but only the purpose of one of them is mentioned so far, what is the other one for? Just imagine, when the character is teleported, the position relative to A when leaving from A should be the same as the relative position relative to B when he arrives at B. In this way, it will not appear abrupt, and the screen jump will be more normal. Then the remaining empty object is to solve this, the principle is exactly the same as the principle of the relative position of the camera above:

// 当角色进入门的碰撞范围,触发碰撞器
private void OnTriggerEnter(Collider other)
{
    
    
    // 将角色的世界位置和朝向赋予门记录目标位置的空物体
    m_TargetPos.position = other.transform.position;
    m_TargetPos.rotation = other.transform.rotation;

    // 使目标门用于记录角色位置的空物体相对于目标门的相对位置与源门的相同
    TargetDoor.m_TargetPos.localPosition = m_TargetPos.localPosition;
    TargetDoor.m_TargetPos.localRotation = m_TargetPos.localRotation;

    // 将角色传送过去
    other.transform.position = TargetDoor.m_TargetPos.position;
    other.transform.rotation = TargetDoor.m_TargetPos.rotation;
}

Fourth, improve

Isn't it simple, is it done? NO, there are still a few minor issues that need to be dealt with. Just imagine, if a character enters the trigger of door A, then door A will teleport him to door B, but once the character reaches door B, the trigger of door B will be triggered immediately, and then door B will teleport him to A, then, your players are passed back and forth by the two gates. . . How to solve this problem? Also, during the test, it was found that if your character controller uses the CharacterController component that comes with unity, then there will be a little problem, let's solve it together:

private void OnTriggerEnter(Collider other)
{
    
    
    // 加一个接受传送的变量,只有在接受传送时,角色才能被传过去。
    // 另外,顺便判断一下目标物体是否允许被传送(通过层来判断)
    if (bAcceptTrans && (((1 << other.gameObject.layer) & TransformTargetLayer) != 0))
    {
    
    
        // 暂时关闭目标门传送触发
        TargetDoor.bAcceptTrans = false;

        // 计算角色相对本地门的相对位置,保证传送到目标门后,与目标门的相对位置一致。
        m_TargetPos.position = other.transform.position;
        m_TargetPos.rotation = other.transform.rotation;
        TargetDoor.m_TargetPos.localPosition = m_TargetPos.localPosition;
        TargetDoor.m_TargetPos.localRotation = m_TargetPos.localRotation;

        // 如果是CharacterController组件控制的角色,先禁用一下,传送完了再打开
        // 如果你的代码不是用这个组件,可以删掉
        CharacterController cc = other.GetComponent<CharacterController>();
        if (cc != null)
            cc.enabled = false;
        other.transform.position = TargetDoor.m_TargetPos.position;
        other.transform.rotation = TargetDoor.m_TargetPos.rotation;
        if (cc != null)
            cc.enabled = true;
    }
}

5. More doors

Well, make the portal a prefab and place it in your game as you like. . A passes to B, B passes back to A, or A passes to B, B passes to C, C passes to D... You can keep doing this as long as you want. After placing it, just drag the target door to the Inspector panel. As shown in the figure below:
insert image description here
Transform Target Layer: The object layer that is allowed to be transferred, such as player layer, bullet layer...
Target Door: The target door of this door (to which door to transfer the object to be transferred, just drag the door here)
It is very simple to use. .

6. Can it be perfected?

This article is over here. It can already realize the basic function of the portal, but there is still a lot of room for optimization and improvement. For example, the shader can be written more coolly, and the effect and mechanism of enabling or disabling the portal can be added. , add some special effects at the moment of teleportation... If you want to continue to improve, then just let your imagination run wild.

7. Related downloads

Click here to download the executable demo
Click here to download the project source code

Guess you like

Origin blog.csdn.net/sdhexu/article/details/112073786