【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人

本文效果如下


文章目录

      • 一、前言
      • 二、光学三原色
      • 三、Unity制作红绿蓝色块
      • 四、克隆像素块
      • 五、显示图像
      • 六、测试
      • 七、屏幕后处理
      • 七、工程源码
      • 八、完毕

一、前言

嗨,大家好,我是新发。
最近我在尝试用Unity制作非游戏的场景,做一些数学、物理的仿真实验,比如上一篇文章我做了一个《蒲丰投针仿真实验》(点击查看),今天,我又要做另一个实验,模拟电视机光学三原色的原理来显示画面,话不多说,我们开始吧~

二、光学三原色

光学三原色分别为红、绿、蓝,这三个颜色通道色各分为256阶亮度,在0时最弱,而在255时最亮。也就是说,一共可以表现256 x 256 x 256 = 16777216种颜色。
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第1张图片
我们早期的彩色电视机显示器就是利用三原色的叠加来显示不同的色彩的,如果你用放大镜仔细观察电视机的屏幕,就会发现画面其实是由很多很多红绿蓝的小色块排列组合而成的,

三、Unity制作红绿蓝色块

创建一个Unity工程,在Hierarchy面板空白处右键鼠标,点击菜单3D Object / Quad,创建一个四边形,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第2张图片
如下:
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第3张图片
调整四边形的Scalex缩放为0.33
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第4张图片
如下,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第5张图片
为它创建一个材质球,shader使用Unlit/Color,颜色设置为红色,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第6张图片
把材质球赋值给四边形,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第7张图片
如下
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第8张图片
同理,制作蓝色和绿色,排在一起,如下:
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第9张图片
层级结构如下,一个block就等价于一个像素,一个像素包括rgb三个三原色,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第10张图片
可以分别对rgb进行调整,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第11张图片

四、克隆像素块

接下来我们只需要进行克隆,排列好,理论上就可以做成一个光学三原色显示器了,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第12张图片
写个函数来执行:

// 创建N个像素块,WIDTH是宽,HEIGHT是高
private IEnumerator CreateBlocks()
{
    int counter = 0;
    for (int j = HEIGHT; j >= 0; --j)
    {
        for (int i = 0; i < WIDTH; ++i)
        {
            CreateBlockItem(i, j, Color.white);
            ++counter;
            if (counter > 100)
            {
                counter = 0;
                yield return new WaitForSeconds(0.3f);
            }
        }
    }
}

// 创建一个像素块
private void CreateBlockItem(int i, int j, Color color)
{
    var obj = Instantiate(block);
    var trans = obj.transform;
    trans.SetParent(blockRoot, false);
    trans.localPosition = new Vector3(i, j, 0);
    trans.Find("r").GetComponent<MeshRenderer>().material.color = new Color(color.r, 0, 0);
    trans.Find("g").GetComponent<MeshRenderer>().material.color = new Color(0, color.g, 0);
    trans.Find("b").GetComponent<MeshRenderer>().material.color = new Color(0, 0, color.b);
}

比如创建一个宽100,高50的屏幕,效果如下:
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第13张图片

五、显示图像

我们找一张图片,比如海贼王的图片,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第14张图片

导入到Unity工程中,勾选图片可读,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第15张图片

我们可以看到图片的尺寸为1920x1080
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第16张图片

我们使用240x135的分辨率来显示,我们对图像进行采样,可以使用Texture2DGetPixel接口,

public Color GetPixel(int x, int y);

完整代码如下:

using System.Collections;
using UnityEngine;

public class BlockMgr : MonoBehaviour
{
    /// 
    /// 原图像
    /// 
    public Texture2D texture;
    /// 
    /// 三原色像素块
    /// 
    public GameObject block;
    /// 
    /// 像素块父节点
    /// 
    private Transform blockRoot;
    /// 
    /// 宽
    /// 
    private const int WIDTH = 240;
    /// 
    /// 高
    /// 
    private const int HEIGHT = 135;

    void Start()
    {
        blockRoot = block.transform.parent;
        StartCoroutine(CreateCreenBlocks());
    }

    private IEnumerator CreateCreenBlocks()
    {
        int counter = 0;
        var width = texture.width;
        var height = texture.height;
        for (int j = HEIGHT; j >= 0; --j)
        {
            for (int i = 0; i < WIDTH; ++i)
            {
                // 对原图像进行采样
                Color color = texture.GetPixel(width * i / WIDTH, height * j / HEIGHT);
                CreateBlockItem(i, j, color);
                ++counter;
                if (counter > 100)
                {
                    counter = 0;
                    yield return null;
                }
            }
        }
    }


    private void CreateBlockItem(int i, int j, Color color)
    {
        var obj = Instantiate(block);
        var trans = obj.transform;
        trans.SetParent(blockRoot, false);
        trans.localPosition = new Vector3(i, j, 0);
        trans.Find("r").GetComponent<MeshRenderer>().material.color = new Color(color.r, 0, 0);
        trans.Find("g").GetComponent<MeshRenderer>().material.color = new Color(0, color.g, 0);
        trans.Find("b").GetComponent<MeshRenderer>().material.color = new Color(0, 0, color.b);
    }
}

脚本挂在screen节点上,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第17张图片

六、测试

运行Unity,执行效果如下:

七、屏幕后处理

亮度有点暗,我们加上屏幕后处理,点击菜单Window / Package Manager
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第18张图片
搜索postprocessing,选中Post Processing,点击Install,安装后处理插件。
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第19张图片
添加一个后处理层postprocessing
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第20张图片
Main CameraLayer改为postprocessing
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第21张图片
Main Camera添加Post-process Layer组件,并设置Volume Layerpostprocessing层,
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第22张图片
Main Camera添加Post-process Volume组件,勾选Is Global,创建一个Profile配置文件,添加Bloom泛光效果,如下:
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第23张图片
最终效果,

七、工程源码

本文工程已上传到CODE CHINA,刚兴趣的同学可自行下载学习,地址:https://codechina.csdn.net/linxinfa/UnityTVScreenSimulation
注:我使用的Unity版本为Unity 2020.1.14f1c1 (64-bit)
【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人_第24张图片

八、完毕

好了,今天就到这里吧。

我是林新发:https://blog.csdn.net/linxinfa
原创不易,若转载请注明出处,感谢大家~
喜欢我的可以点赞、关注、收藏,如果有什么技术上的疑问,欢迎留言或私信,我们下期见~

你可能感兴趣的:(Unity3D,unity,三原色,电视机,光学,仿真)