Unity 3D

Unity 3D กับเทคนิคการทำ 360 Photo ด้วย Cube Map Real-Time Render

บางครั้งการ Render ภาพ 360 Photo จากโปรแกรม 3D ก็นานเกินไป ลองมาหาโซลูชันแบบ Real-Time Render บน Unity ดู

บางครั้งการ Render ภาพ 360 Photo จากโปรแกรม 3D ก็นานเกินไป ลองมาหาโซลูชันแบบ Real-Time Render บน Unity  3D สำหรับสร้างกราฟิกภาพ 360 แบบรวดเร็ว

ถ้ามีการรับงานทำกราฟิก 3D แบบ 360 สำหรับทำการตลาดบน Facebook หรือ Social Media แล้ว ถ้ามีกล้อง 360 Camera ก็ไม่มีปัญหา แต่ถ้าหากว่าลูกค้าต้องการ 3D Graphic ที่ Render ขึ้นมาเอง เราก็ต้องเปิด Maya, Blender, 3DsMax แล้วทำกราฟิก วางกล้อง ตั้งค่า ViewPort แล้วก็ Render ออกมาเป็น 360 Photo ซึ่งการ Render มันก็เสียเวลานานมาก แล้วถ้าเราทำทุกอย่างบน Unity แล้วใช้ข้อดีของการทำ Real-Time Render ดูเนี่ยมันจะโอเคไหม ก็ไปเจอโซลูชันมาจาก Blog ของ Unity Developer เข้าให้ เราก็เลยเอามาปรับใช้ให้ตรงกับงานเรา มาลองทำตามดูครับ

สร้าง Project Unity ขึ้นมาใหม่ สำหรับงานนี้:

สร้าง Project ให้เรียบร้อยด้วยความที่นี่เป็น  Sample สำหรับสอนทำกราฟิก ก็เลยอยากจะดาวน์โหลด Asset ตัวนี้มาใช้  https://assetstore.unity.com/packages/3d/environments/fantasy/make-your-fantasy-game-lite-8312

ดาวน์โหลดผ่าน Package Manager ละกัน ติดตั้ง Install และนำเข้า Import ให้เรียบร้อย

จัดฉากตามใจชอบเสร็จแล้ววางตำแหน่งกล้องของเราตำแหน่งตรงกลางของฉากที่เราจะใช้ ประหนึ่งว่าอยู่ตรงกลางสภาพแวดล้อม ตามตัวอย่างก็ได้ครับ

วางกล้องเป็นที่น่าพอใจแล้วต่อมาเราต้องสร้าง Render Texture  ใหม่ขึ้นมาตั้งชื่อว่า CubeMap360

ตั้งค่า Render Texture ตรง dimension เป็น Cube กำหนดขนาดเป็น 4098×4098 Pixels (ค่อนข้างใหญ่)

สร้าง Render Texture มาอีกตัว ตั้งชื่อว่า ResultRECT แต่ไม่ต้องปรับ Dimension ใช้แค่ 2D ปรับขนาดเป็น 4098×4098 pixels ให้เรียบร้อย

เมื่อพร้อมแล้วให้เราสร้าง GameObject เปล่าๆ ขึ้นมาตั้งชื่อว่า PanoramaCapture  สร้างไฟล์ C# ขึ้นมาว่า PanoramaCapture.cs

ประกาศ Using บน Header เรียกไลบรารี่การเขียนไฟล์

using System.IO;

ต่อจากนั้นประกาศ Global Variable ดังนี้:

public Camera MainCamera;
public RenderTexture cubeMap;
public RenderTexture resultRect;

ไปที่ Method ของ function ที่ Update() เขียนคำสั่งคลิกเมาส์ซ้าย ให้ทำการ ดึงภาพจาก MainCamera ไปเก็บใน CubeMap  เป็นรูปแบบ Panorama Sphere แล้วจึงเอา Panorama Sphere หรือเจ้า CubeMap ไปกางเขียนทับ Render Texture ที่เป็นภาพ 2D อย่าง ResultRect ที่เราสร้างไว้

if (Input.GetMouseButton(0)){
    MainCamera.RenderToCubemap(cubeMap);
    cubeMap.ConvertToEquirect(resultRect);
}

สร้างฟังก์ชันใหม่ขึ้นมาว่า   savePhoto() แล้วไปแทรกต่อใน Update() ดังนี้:

if (Input.GetMouseButton(0)){
   MainCamera.RenderToCubemap(cubeMap);
   cubeMap.ConvertToEquirect(resultRect);
   savePhoto(resultRect);
}

ดังนั้นเราต้องไป Implement ส่วนของฟังก์ชัน savePhoto() คือ:

public void savePhoto(RenderTexture rt){
        Texture2D texture2D = new Texture2D(rt.width, rt.height);
        RenderTexture.active = rt;
        texture2D.ReadPixels(new Rect(0,0,rt.width,rt.height),0,0);
        RenderTexture.active = null;
        byte[] bytes = texture2D.EncodeToJPG();
        string pathImage = Application.dataPath + "/Result" + ".jpg";
        File.WriteAllBytes(pathImage, bytes);
}

รับค่า ResultRECT ที่เป็น Render Texture ขนาดความกว้างและยาว ไปทำการเข้ารหัส JPG ผ่าน EncodeToJPG ที่เรียกจาก System.IO แล้วเขียนภาพใหม่วางที่ Path ของ Assets โดยมีชื่อ Result.jpg นั่นเอง ดังนั้นภาพรวมของ PanoramaCapture.cs จะเป็นดังนี้

using System.Collections;
using System.IO;
using System.Collections.Generic;
using UnityEngine;

public class PanoramaCapture : MonoBehaviour
{
    public Camera MainCamera;
    public RenderTexture cubeMap;
    public RenderTexture resultRect;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButton(0)){
            MainCamera.RenderToCubemap(cubeMap);
            cubeMap.ConvertToEquirect(resultRect);
            savePhoto(resultRect);
        }
    }

    public void savePhoto(RenderTexture rt){
        Texture2D texture2D = new Texture2D(rt.width, rt.height);
        RenderTexture.active = rt;
        texture2D.ReadPixels(new Rect(0,0,rt.width,rt.height),0,0);
        RenderTexture.active = null;
        byte[] bytes = texture2D.EncodeToJPG();
        string pathImage = Application.dataPath + "/Result" + ".jpg";
        File.WriteAllBytes(pathImage, bytes);
    }
}

ลาก ทุกสิ่งไปยัง component ที่อยู่ใน C# ตามภาพ

เวลาทดสอบให้ทำผ่าน Editor โดยการกด Play แล้วไปที่ Game Scene หลังจากนั้นคลิกเมาส์แค่นั้นครับ แล้วจึงรอดูผลลัพธ์ (จะมีการประมวลผลนานนิดนึง)

ไฟล์ภาพให้ ไปที่ Path ในเครื่องคอม ใน Folder ของ Project เรานั้นแหละ มันชื่อ Result.jpg  ใน Assets

การแปลง Exif ก็ใช้ Python หรือโปรแกรมพวกแก้ไข Meta Data ของ Exif รูปภาพครับ

เช่น:  https://pypi.org/project/exif/

แก้ไข Exif ตามค่าแบบนี้:

-xmp:ProjectionType=equirectangular
-xmp:CroppedAreaLeftPixels=0
-xmp:CroppedAreaTopPixels=0
-xmp:CroppedAreaImageWidthPixels=4098
-xmp:CroppedAreaImageHeightPixels=2048
-xmp:FullPanoWidthPixels=4098
-xmp:FullPanoHeightPixels=2049
-xmp:UsePanoramaViewer=true

ลองเอาไปโพสบน Facebook ดูหน่อยละกัน

รบกวนใครที่เอาไปทำ Tutorial บน YouTube ฝากอ้างอิง Link ที่คำอธิบายหรือ Video ให้หน่อยก็ดีนะครับ

Asst. Prof. Banyapon Poolsawas

อาจารย์ประจำสาขาวิชาการออกแบบเชิงโต้ตอบ และการพัฒนาเกม วิทยาลัยครีเอทีฟดีไซน์ & เอ็นเตอร์เทนเมนต์เทคโนโลยี มหาวิทยาลัยธุรกิจบัณฑิตย์ ผู้ก่อตั้ง บริษัท Daydev Co., Ltd, (เดย์เดฟ จำกัด)

Related Articles

Back to top button

Adblock Detected

เราตรวจพบว่าคุณใช้ Adblock บนบราวเซอร์ของคุณ,กรุณาปิดระบบ Adblock ก่อนเข้าอ่าน Content ของเรานะครับ, ถือว่าช่วยเหลือกัน