unity基础学习之camera

认识一下基础配置:

ClearFlags:

在摄像机进行渲染前,对颜色缓冲及深度缓冲,进行不同控制操作,每个相机在渲染时会存储颜色和深度信息。屏幕的未绘制部分是空的,默认情况下会显示天空盒。当你使用多个相机时,每一个都将自己的颜色和深度信息存储在缓冲区中,还将积累大量的每个相机的渲染数据。当场景中的任何特定相机进行渲染时,你可以设定清除标记以清除缓冲区信息的不同集合。可以通过下面四个选项之一来完成:
Skybox :清除颜色缓冲和深度缓冲,没有物体遮挡的背景,用天空盒子填充。
Solid Color :清除颜色缓冲和深度缓冲,没有物体遮挡的背景,用 Camera 的另一个属性Background的颜色填充。
Depth Only:只清除深度缓存。
Don’t Clear:颜色缓冲和深度缓冲都不清除。

CullingMask:

这个相机可以绘制的Layer图层,这个每一个节点都会有这个属性,如下图所示
在这里插入图片描述

projection

投影的方式:可以为透视投影或者正交投影

field of view

相机张开的角度,相当于眼睛张开的角度

clipping planes

near:0.3,近裁切面深度值
far:1000,远裁切面深度值
这两个值将会决定视锥体的长度

viewRect

x:0.0
y:0.0;
W:1.0;
H:1.0;
这四个参数会决定相机投影到屏幕坐标系的具体位置和大小,按照现在这个设置,则完全覆盖屏幕,因为屏幕的大小就是(1.0,1.0),屏幕的坐标系原点就是(0.0,0.0);

Depth

这个值越大,说明这个相机所包含的内容越先被渲染

RenderTexture

渲染纹理
Unity中使用RenderTexture来接收FBO(可视化FBO),Game窗口是一个特殊的RenderTexture,它允许多个FBO叠加渲染,当Camera的RenderTarget都设置为null时表示输出到game窗口(没有摄像机的RenderTaget为null会显示没有摄像机进行渲染),设置不为null表示输出到某个RT

cpu------>上传纹理----->gpu renderbuffer–>当要渲染某个纹理时,会生成framebuffer–>
如果此时将framebuffer绑定到framebufferobject(fbo),则这个纹理就会被写入到渲染纹理中,摄像机如果渲染纹理设置为null,那么摄像机的渲染纹理默认指的是屏幕,如果是自己创建的渲染纹理,则会将结果输出到其中,类似于截图或者小地图的效果,

 //截图代码
 RenderTexture renderTexture = m_Camera.targetTexture;//拿到目标渲染纹理
 RenderTexture.active = renderTexture;
 Texture2D tex = new Texture2D(renderTexture.width, renderTexture.height);//新建纹理存储渲染纹理
 tex.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);//把渲染纹理的像素    给Texture2D,才能在项目里面使用
 tex.Apply();//记得应用一下,不然很蛋疼
 byte[] bytes = tex.EncodeToPNG();//拿到图片的byte
 File.WriteAllBytes(Application.dataPath + "/Resources/ScreenShort/" + _index.ToString() + ".png", bytes);//写入本地

RenderPath

渲染路径决定了光照在 shader 中是如何应用的,所以在计算光源时,需要在每个 Pass 块内指定它的渲染路径,Unity 才会为我们提供正确的光照信息

渲染路径:一般有以下四种
Legacy Vertex Lit:遗留的顶点照明渲染.光照效果最一般的,不支持阴影,一般用于配置较差的移动设备

Forward:前向渲染,能够很好的支持光照效果,不支持点光源和聚光灯的阴影,一般采用烘焙的方式来处理更多的阴影,前向渲染路径是我们最常用的一种渲染路径。在进行一次完整的前向渲染时,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:颜色缓冲区和深度缓冲区。
利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值

Pass {
    for(each primitive in this model){
        if(failed in depth test){
            //如果没有通过深度测试,说明该片元是不可见的
            discard;
            }else{
                //如果该片元可见
                //就进行光照计算
                float4 color = Shadering(materialInfo, pos, normal, lightDir, viewDir);
                //更新帧缓冲
                writeFrameBuffer(fragment,color);
                }          
        }    
    }

对于每个逐像素光源,都需要进行上面一次完整的渲染流程。如果一个物体在多个逐像素光源的影响区域内,那么该物体就需要执行多个Pass,每个Pass计算一个逐像素光源的光照结果,然后在帧缓冲中把这些光照结果混合起来得到最终的颜色值。假设,场景中有N个物体,每个物体受到M个光源的影响,那么就需要 N * M 个 Pass。可以看出,如果有大量逐像素光照,需要执行的Pass数目也会很大。所以 Unity 会限制每个物体的逐像素光照的数目

Deferred Lighting:延迟渲染,支持最佳的光照效果以及所有类型的光照投影,但是需要硬件支持, pro模式才有.
延迟渲染主要包含两个Pass。第一个Pass中,不进行任何光照计算,仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,就把它的相关信息存储到G缓冲区中。然后在第二个Pass中,利用G缓冲区的各个片元信息,如表面法线、视角方向、漫反射系数等,进行真正的光照计算。
延迟渲染过程用伪代码描述如下:

Pass 1 {    
    // 第一个Pass不进行真正的光照计算    
    // 仅仅把光照计算需要的信息存储到G缓冲中
     for (each primitive in this model) {
        for (each fragment covered by this primitive) {
            if (failed in depth test) {
                // 如果没有通过深度测试,说明该片元是不可见的
                discard;
            } else {
                // 如果该片元可见
                // 就把需要的信息存储到G缓冲中
                writeGBuffer(materialInfo, pos, normal, lightDir, viewDir);
            }
        }
    }
 } 
 
 Pass 2 {
    // 利用G缓冲中的信息进行真正的光照计算
    for (each pixel in the screen) {
        if (the pixel is valid) {
            // 如果该像素是有效的
            // 读取它对应的G缓冲中的信息
            readGBuffer(pixel, materialInfo, pos, normal, lightDir, viewDir);
            // 根据读取到的信息进行光照计算
            float4 color = Shading(materialInfo, pos, normal, lightDir, viewDir);
            // 更新帧缓冲
            writeFrameBuffer(pixel, color);
        }
    }
 }
 

可以看出,延迟渲染使用的Pass数目通常就是两个,这跟场景中包含的光源数目是没有关系的。换句话说,延迟渲染的效率不依 赖于场景的复杂度,而是和我们使用的屏幕空间的大小有关。这是因为,我们需要的信息都存储在缓冲区中,而这些缓冲区可以理解 成是一张张2D图像,我们的计算实际上就是在这些图像空间中进行的。

Unity中的延迟渲染

Unity有两种延迟渲染路径,一种是遗留的延迟渲染路径,即Unity 5之前使用的延迟渲染路径,而另一种是Unity5.x中使用的延迟渲 染路径。如果游戏中使用了大量的实时光照,那么我们可能希望选择延迟渲染路径,但这种路径需要一定的硬件支持。

对于延迟渲染路径来说,它最适合在场景中光源数目很多、如果使用前向渲染会造成性能瓶颈的情况下使用。而且,延迟渲染路 径中的每个光源都可以按逐像素的方式处理。但是,延迟渲染也有一些缺点。

不支持真正的抗锯齿(anti-aliasing)功能。

不能处理半透明物体

对显卡有一定要求。如果要使用延迟渲染的话,显卡必须支持MRT(Multiple Render Targets)、Shader Mode 3.0及以上、深度渲 染纹理以及双面的模板缓冲。

当使用延迟渲染时,Unity要求我们提供两个Pass。

(1)第一个Pass用于渲染G缓冲。在这个Pass中,我们会把物体的漫反射颜色、高光反射颜色、平滑度、法线、自发光和深度等 信息渲染到屏幕空间的G缓冲区中。对于每个物体来说,这个Pass仅会执行一次。

(2)第二个Pass用于计算真正的光照模型。这个Pass会使用上一个Pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。

默认的G缓冲区(注意,不同Unity版本的渲染纹理存储内容会有所不同)包含了以下几个渲染纹理(Render Texture,RT)。

RT0:格式是ARGB32,RGB通道用于存储漫反射颜色,A通道没有被使用。

RT1:格式是ARGB32,RGB通道用于存储高光反射颜色,A通道用于存储高光反射的指数部分。

RT2:格式是ARGB2101010,RGB通道用于存储法线,A通道没有被使用。

RT3:格式是ARGB32(非HDR)或ARGBHalf(HDR),用于存储自发光+lightmap+反射探针(reflection probes)。

深度缓冲和模板缓冲。
当在第二个Pass中计算光照时,默认情况下仅可以使用Unity内置的Standard光照模型。如果我们想要使用其他的光照模型,就需要 替换掉原有的Internal-DeferredShading.shader文件。

Legacy Deferred :(遗留的延迟渲染)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity可以通过Android的Camera2 API来访问USB摄像头。 首先,在Unity中创建一个Android插件,该插件将使用Android的Camera2 API来访问USB摄像头。然后,在Unity中调用该插件以获取从USB摄像头获取的视频数据。 以下是一个简单的Unity Android插件示例,可以用于访问USB摄像头: ```java public class USBCameraPlugin { private static CameraDevice camera; private static CaptureRequest.Builder previewBuilder; private static SurfaceTexture surfaceTexture; private static Surface previewSurface; private static HandlerThread handlerThread; private static Handler handler; private static Semaphore cameraOpenCloseLock = new Semaphore(1); public static void startCamera(int textureId) { // Open the camera CameraManager manager = (CameraManager) UnityPlayer.currentActivity.getSystemService(Context.CAMERA_SERVICE); String[] cameraIds = null; try { cameraIds = manager.getCameraIdList(); } catch (CameraAccessException e) { e.printStackTrace(); } if (cameraIds == null || cameraIds.length == 0) { return; } String cameraId = cameraIds[0]; try { if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { throw new RuntimeException("Time out waiting to lock camera opening."); } manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice cameraDevice) { cameraOpenCloseLock.release(); camera = cameraDevice; startPreview(textureId); } @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { cameraOpenCloseLock.release(); cameraDevice.close(); camera = null; } @Override public void onError(@NonNull CameraDevice cameraDevice, int error) { cameraOpenCloseLock.release(); cameraDevice.close(); camera = null; } }, handler); } catch (InterruptedException e) { throw new RuntimeException("Interrupted while trying to lock camera opening.", e); } catch (CameraAccessException e) { e.printStackTrace(); } } public static void stopCamera() { if (camera != null) { camera.close(); camera = null; } } private static void startPreview(int textureId) { if (camera == null) { return; } try { // Create a surface texture to receive camera data surfaceTexture = new SurfaceTexture(textureId); surfaceTexture.setDefaultBufferSize(1920, 1080); previewSurface = new Surface(surfaceTexture); // Build the preview request previewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); previewBuilder.addTarget(previewSurface); // Create a handler thread to handle camera events handlerThread = new HandlerThread("CameraBackground"); handlerThread.start(); handler = new Handler(handlerThread.getLooper()); // Start the preview camera.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { try { cameraCaptureSession.setRepeatingRequest(previewBuilder.build(), null, handler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { stopCamera(); } }, handler); } catch (CameraAccessException e) { e.printStackTrace(); } } } ``` 然后,在Unity中调用该插件以访问USB摄像头。以下是一个简单的C#脚本示例,可以用于在Unity中调用Android插件并从USB摄像头获取视频数据: ```csharp public class USBCamera : MonoBehaviour { private AndroidJavaObject plugin; private Texture2D texture; private byte[] data; private int width = 1920; private int height = 1080; void Start () { // Create the Android plugin object plugin = new AndroidJavaObject("com.example.usbcamera.USBCameraPlugin"); // Set the texture to display camera data texture = new Texture2D(width, height, TextureFormat.RGBA32, false); GetComponent<Renderer>().material.mainTexture = texture; // Call the Android plugin to start the camera plugin.Call("startCamera", texture.GetNativeTexturePtr().ToInt32()); } void OnDestroy() { // Call the Android plugin to stop the camera plugin.Call("stopCamera"); } void Update () { // Update the texture with the latest camera data if (data == null) { data = new byte[width * height * 4]; } texture.LoadRawTextureData(data); texture.Apply(); } private void OnApplicationQuit() { // Call the Android plugin to stop the camera plugin.Call("stopCamera"); } } ``` 这样,你就可以在Unity中通过Android插件访问USB摄像头并获取视频数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值