跟诸子学游戏 unity3d Rendering Mode和Render Mode

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跟诸子学游戏 unity3d Rendering Mode和Render Mode相关的知识,希望对你有一定的参考价值。

参考技术A Rendering Mode:渲染模式,属于material材质的渲染模式.

Opaque :默认的,适用于没有透明区域的普通固体物体。

Cutout: 允许你创造一个透明的效果,在不透明和透明的区域之间有硬边。在这种模式下,没有半透明的区域,纹理要么是100%的不透明,要么是看不见的。这在使用透明度来创造材料的形状时很有用,比如叶子,或者有破洞和破布的布。

Transparent :适用于透明塑料或玻璃等透明材料。在这种模式下,材料本身将采用透明的值(基于纹理的阿尔法通道和颜色的alpha值),然而,反射和照明的高光仍然可以清晰地看到,就像真实透明的材料一样。

Fade :允许透明值完全淡出一个物体,包括任何高光或反射。如果你想让一个物体在或离开时动画化,这种模式是很有用的。它不适合呈现透明塑料或玻璃等逼真的透明材料,因为反射和高光也会褪色。

Render Mode :画布的渲染模式,创建Canvas之后可以看见.

Screen Space—Overlay:将UI渲染为摄像机视图顶部的2D图形(默认设置)会在摄像机照射范围内,永远在最前面看到.

Screen Space—Camera:也将UI渲染在摄像机视图顶部,但UI元素可以进行透视效果旋转,一直在摄像机前方,距离摄像机的距离不变,不管摄像机怎么移动.

World Space:将画布对象放置在场景中,就好像UI是3D场景中的一部分。画布不动,根据摄像机的距离远近是否看到物体大小缩放,以及景深程度

这3种模式区别很大,自己动手试试.

ps:水果忍者,需要利用到物理系统,Rigidbody和Mesh Collider,从下方向上抛投水果(3D空间中),给物体一个向上的力,使用Random(随机)位置,在一个范围内,随机向上抛投的力,达到随机生成水果并抛投的真实物理效果.

WebGL—实现使用FBO离屏渲染(亦同拷贝纹理)off-screen rendering的两种方式

1.离屏渲染使用场景:

1.游戏中的小地图;
2.画中画场景;
3.游戏中观战模式的多场景场合;
4.镜像场景——比如汽车游戏当中的倒车镜,采用的就是离屏渲染技术,在倒车镜上安装一个摄像机,把摄像机渲染的数据保存到FBO(Frame Buffer Object帧缓冲区),再从FBO提取生成纹理进行贴图到倒车镜;

2.与实时渲染的优缺点比较:

离屏渲染:
1.在变化的场景下,因为离屏渲染需要创建一个新的缓冲区,且需要多次切换上下文环境,所以代价很高;
2.在稳定的场景下,离屏渲染可以采用一张纹理进行渲染,所以性能较当前屏渲染有较大提升。
从上述对比可以看出,在稳定场景下使用离屏渲染的优势较大。
(此处优缺点对比来源于高德地图技术博客:离屏渲染在车载导航中的应用

3.明确概念:

3.1 帧缓冲FBO(Frame Buffer Object);

在OpenGL渲染管线中,几何数据和纹理最终都是以2d像素绘制到屏幕上。最后一步的渲染目标在OpenGL渲染管线中被称为帧缓存(Frame Buffer Object即FBO)帧缓存是颜色缓存、深度缓存、模板缓存、累积缓存的集合。 默认情况下, OpenGL使用的帧缓存是由窗体系统创建和管理的。
下图展示了FBO和renderbuffer object与texture object之间的关系。从图中我们可以看出:多个renderbuffer object和texture object可以通过挂接点挂接到FBO上。需要主要的是FBO并没有实际存储数据的地方,它只是一个数据的壳,它只有挂接点,说白了就是两个缓冲区指针的集合

3.2 渲染缓冲RBO(Renderbuffer Object)
就像纹理图像一样,渲染缓冲区对象是实际的缓冲区,例如字节,整数,像素或其他的数组。但是,不能直接读取renderbuffer对象。这给它带来了一个额外的优势,那就是OpenGL可以进行一些内存优化,从而使其性能优于纹理,以便在屏幕外渲染到帧缓冲区。

3.3 FrameBuffer,RenderBuffer,Texture区别


**Color Attachment:**存储的是纹理图片颜色值,实质上纹理图片颜色值属于颜色附着点的一种
**Depth Attachment:**指向的是深度缓冲区和颜色缓冲区
**Stencil Attachment:**指向的是模版缓冲区
**RenderBuffer Objects :**渲染缓冲区对象,无论是纹理、图片、颜色、深度缓冲区、模版缓冲区都存在这个对象
FrameBuffer 上的附着点其实相当于内存地址,它并没有存储实质的内容,只是三个附着点或三个内存地址在FrameBuffer Objects例如color Attachment ,它仅仅是附着在FrameBuffer身上;
差异对比源自这里

3.4 FrameBuffer,RenderBuffer使用场景
Renderbuffer对象可以在屏幕外的渲染项目中使用,效率更高,但是重要的是要意识到何时使用renderbuffer对象以及何时使用纹理。一般规则是,如果永远不需要从特定缓冲区中采样数据,明智的做法是为该特定缓冲区使用renderbuffer对象。如果需要从特定的缓冲区(例如颜色或深度值)中采样数据,则应使用纹理附件。
源自这里

4.实现离屏渲染(亦同拷贝纹理)的两种思路

4.1 获取纹理再拷贝——将FBO的纹理拷贝到一张纹理当中;
实现效果:
左上角即为将FBO中颜色缓冲区的内容复制到纹理,进行再渲染的效果;

关键思路: 利用webgl的gl.copyTexSubImage2D()的函数,将FBO中颜色缓冲区的内容复制到纹理;

4.2 FBO拷贝——在webgl里面直接建立一个FBO,把绘制的结果直接存到FBO当中,然后在主的FBO中使用之前创建的FBO,实现离线渲染;
实现效果:

白色立方体为主FBO,白色立方体的贴图为自己创建FBO的动态纹理贴图,把自定义FBO的纹理贴到立方体上,再在主FBO上进行绘制。
思路如下:

参考上图:对FBO的几个缓冲区逐个进行RBO的填充依附;
1.自定义FBO的创建—对立方体进行木制纹理贴图;
新建帧缓冲区,对其的颜色缓冲区进行木制纹理贴图的填充,用模板缓冲区的深度缓冲区进行帧缓冲区深度缓冲区的链接,将绘制完成的帧缓冲对象以纹理的形式存放,以供下次主FBO中使用。
注意最后要取消几个缓冲区的绑定,使其恢复状态机,使用原生FBO;

function createFOB(width,height) 
            //新建帧缓冲对象
            var obj         =   webgl.createFramebuffer();
            //对帧缓冲对象进行绑定
            webgl.bindFramebuffer(webgl.FRAMEBUFFER, obj);
            //新建渲染缓冲区对象
            var depthObj    =   webgl.createRenderbuffer();
            //对渲染缓冲对象进行绑定
            webgl.bindRenderbuffer(webgl.RENDERBUFFER, depthObj);
            //创建并初始化渲染缓冲区对象的数据存储。
            webgl.renderbufferStorage(webgl.RENDERBUFFER, webgl.DEPTH_COMPONENT16, width, height);
            //渲染缓冲区对象作为帧缓冲区的深度缓冲区对象
            webgl.framebufferRenderbuffer(webgl.FRAMEBUFFER, webgl.DEPTH_ATTACHMENT, webgl.RENDERBUFFER, depthObj);
            //新建纹理对象
            textureDynamic = createDynamicTexture(width, height);
            //纹理对象作为帧缓冲区的颜色缓冲区对象
            webgl.framebufferTexture2D(webgl.FRAMEBUFFER, webgl.COLOR_ATTACHMENT0, webgl.TEXTURE_2D, textureDynamic, 0);
            //将绑定好的帧缓冲区,纹理,渲染缓冲区都取消绑定
            //恢复状态机,使用原生的FBO
            webgl.bindRenderbuffer(webgl.RENDERBUFFER, null);
            webgl.bindFramebuffer(webgl.FRAMEBUFFER, null);
            webgl.bindTexture(webgl.TEXTURE_2D, null);
            return obj;
        

2.使用自己创建的FBO,webgl.bindFramebuffer(webgl.FRAMEBUFFER, fbo);,接下来所有OpenGL绘制的数据将会保存至自己创建的FBO中;在此FBO中我主要进行“创建一个旋转立方体,对立方体进行木制纹理贴图”;

function renderToFBO() 
            //这里使用创建的FBO,接下来所有OpenGL绘制的数据将会保存至自己创建的FBO
            webgl.bindFramebuffer(webgl.FRAMEBUFFER, fbo);
            webgl.viewport(0, 0, texWidth, texHeigh);

            //! 设置重绘背景的颜色
            webgl.clearColor(1.0, 1.0, 1.0, 1.0);
            //! 执行绘制,即将背景清空成制定的颜色(clearColor)
            webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
            webgl.enable(webgl.DEPTH_TEST);
            //! 指定绘制所使用的顶点数据 从 该缓冲区中获取
            webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);

            var mvp = mat4.create();
            var matTrans = mat4.create();
            var matRot = mat4.create();
            var matScale = mat4.create();
            var matModel = mat4.create();
            var matAll = mat4.create();

            mat4.identity(matTrans);
            mat4.identity(matRot);
            mat4.identity(matModel);
            mat4.identity(matScale);
            mat4.identity(matAll);

            webgl.activeTexture(webgl.TEXTURE0);
            //将给定的textureHandle绑定到目标,即0号纹理;此为木制纹理
            webgl.bindTexture(webgl.TEXTURE_2D, textureHandle);
            //给片元着色器传递纹理
            webgl.uniform1i(uniformTexture, 0);

            mat4.translate(matTrans, [varTransX, 0.0, varTransZ]);
            mat4.rotate(matRot, degToRad(varRot), [1.0, 1.0, 1.0]);

            mat4.multiply(matTrans, matRot, matModel);

            mat4.scale(matScale, [varScale, 1, 1], matScale);

            mat4.multiply(matModel, matScale, matAll);

            mat4.multiply(projectMat, matAll, mvp);

            webgl.uniformMatrix4fv(uniformProj, false, mvp);

            webgl.enableVertexAttribArray(v3PositionIndex);
            webgl.enableVertexAttribArray(attrColor);
            webgl.enableVertexAttribArray(attrUV);

            webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 4 * 9, 0);
            webgl.vertexAttribPointer(attrUV, 2, webgl.FLOAT, false, 4 * 9, 4 * 3);
            webgl.vertexAttribPointer(attrColor, 4, webgl.FLOAT, false, 4 * 9, 4 * 5);

            webgl.drawArrays(webgl.TRIANGLES, 0, 36);
        

3.切换到OpenGL的主FBO(即原生FBO)中webgl.bindFramebuffer(webgl.FRAMEBUFFER, null);,用之前自己创建的FBO生成的纹理贴图textureDynamic进行白色立方体的贴图(总体概括为使用之前创建的FBO);

            //切换成OpenGL自己创建的FBO,即主FBO
            webgl.bindFramebuffer(webgl.FRAMEBUFFER, null);
            webgl.viewport(0, 0, texWidth, texHeigh);

            //! 设置重绘背景的颜色
            webgl.clearColor(0.0, 0.0, 0.0, 1.0);
            //! 执行绘制,即将背景清空成制定的颜色(clearColor)
            webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
            webgl.enable(webgl.DEPTH_TEST);
            //! 指定绘制所使用的顶点数据 从 该缓冲区中获取
            webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);

            var mvp = mat4.create();
            var matTrans = mat4.create();
            var matRot = mat4.create();
            var matScale = mat4.create();
            var matModel = mat4.create();
            var matAll = mat4.create();

            varRot += 1;

            mat4.identity(matTrans);
            mat4.identity(matRot);
            mat4.identity(matModel);
            mat4.identity(matScale);
            mat4.identity(matAll);

            webgl.activeTexture(webgl.TEXTURE0);
            //textureDynamic 已经把FBO的内容绘制到这个纹理上了
            //把自定义FBO的纹理贴到立方体上,再在主FBO上进行绘制
            webgl.bindTexture(webgl.TEXTURE_2D, textureDynamic);
            webgl.uniform1i(uniformTexture, 0);


            mat4.translate(matTrans, [varTransX, 0.0, varTransZ]);
            mat4.rotate(matRot, degToRad(varRot), [1.0, 1.0, 1.0]);

            mat4.multiply(matTrans, matRot, matModel);

            mat4.scale(matScale, [varScale, 1, 1], matScale);

            mat4.multiply(matModel, matScale, matAll);

            mat4.multiply(projectMat, matAll, mvp);

            webgl.uniformMatrix4fv(uniformProj, false, mvp);

            webgl.enableVertexAttribArray(v3PositionIndex);
            webgl.enableVertexAttribArray(attrColor);
            webgl.enableVertexAttribArray(attrUV);

            webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 4 * 9, 0);
            webgl.vertexAttribPointer(attrUV, 2, webgl.FLOAT, false, 4 * 9, 4 * 3);
            webgl.vertexAttribPointer(attrColor, 4, webgl.FLOAT, false, 4 * 9, 4 * 5);

            webgl.drawArrays(webgl.TRIANGLES, 0, 36);

以上是关于跟诸子学游戏 unity3d Rendering Mode和Render Mode的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D光照前置知识——Rendering Paths(渲染路径)及LightMode(光照模式)译解

unity3d Human skin real time rendering 真实模拟人皮实时渲染

渲染优化01

unity CommandBuffer学习

unity3d开发2d游戏中Assetbundle有啥作用

WebGL—实现使用FBO离屏渲染(亦同拷贝纹理)off-screen rendering的两种方式