• 多材质(Shader)实现


    最近在cocos creator上打算写个U3D中shader功能的插件(能在属性面板调整shader属性)。

    对其中一个功能有点疑惑,就是U3D中一个渲染物体上可以挂多个材质,后来查询了下,一个物体上挂多个材质的时候,每个材质负责渲染对应的子mesh,但如果一个object只有一个mesh时,

    那么挂载在其下的所有材质都会作用在这个mesh上,达到了混合的作用。(实际上,Unity并不建议将多个材质作用于同一个mesh上,官方建议的做法是通过多个shader pass解决多种shader效果需求)

    但是在OpenGl渲染中,每次渲染只能用一个shader,而每个物体也只能挂一个shader被渲染。

    因此不能直接给一个物体挂多个着色器,当初我第一时刻想到的,就是shader文件混合,比如将两个着色器的main函数里的内容混合在一起,然后分别将计算结果加起来赋予到output。

    今天偶然逛到一个网站,是一个类似ShaderToy的网站,能在线编辑Shder并演示(说白了就是Webgl),不过这个网站除了能在线写glsl代码,还有一个比较好玩的功能,就是可视化编辑shader

    这个功能很简单,就是可以将多个代码实现的shader作为节点,组合成一个新的shader,当然,目前版本比较简单,只提供加减乘除等基础操作。

    仔细一想,这个功能不就跟我想要的shader混合一样么?仔细做了个试验,发现他的混合实现果然是跟我想的一样。

    首先,我在这个网站写了两个非常简单的着色器:

    Shader 1:

    Shader 2:

    组合Shader:

    将这个组合Shader导出后,查看它的Shader文件:

    // 片段着色器
    precision highp float; precision highp int; uniform vec3 color; vec4 Simple_Shader_11475135391321_521_main() { vec4 Simple_Shader_11475135391321_521_gl_FragColor = vec4(0.0); Simple_Shader_11475135391321_521_gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4); return Simple_Shader_11475135391321_521_gl_FragColor *= 1.0; } vec4 Simple_Shader_21475135525837_573_main() { vec4 Simple_Shader_21475135525837_573_gl_FragColor = vec4(0.0); Simple_Shader_21475135525837_573_gl_FragColor = vec4(color, 1.0); return Simple_Shader_21475135525837_573_gl_FragColor *= 1.0; } void main() { gl_FragColor = (Simple_Shader_11475135391321_521_main() + Simple_Shader_21475135525837_573_main()); } // 顶点着色器 precision highp float; precision highp int; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; attribute vec3 position; vec4 Simple_Shader_11475135391321_521_main() { vec4 Simple_Shader_11475135391321_521_gl_Position = vec4(0.0); Simple_Shader_11475135391321_521_gl_Position = vec4(position, 1.0); return Simple_Shader_11475135391321_521_gl_Position *= 1.0; } vec4 Simple_Shader_21475135525837_573_main() { vec4 Simple_Shader_21475135525837_573_gl_Position = vec4(0.0); Simple_Shader_21475135525837_573_gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); return Simple_Shader_21475135525837_573_gl_Position *= 1.0; } void main() { gl_Position = Simple_Shader_11475135391321_521_main() + Simple_Shader_21475135525837_573_main(); }

    果然不出所料,拿顶点着色器来说,首先提取两个着色器的变量并放在一起,并剔除重复的,然后将两个shader各自的main提取为一个子函数,并将之前的gl_Position替换为renturn,然后在main中将这个两个函数的返回值加起来,达到混合的目的,当然,他还加入了缩放因子控制混合比例。

    非常简单粗暴。

    而且这种做法,还能将drawcall控制为一个,unity我不知道他的实现原理,不过就目前来看,添加多个着色器,会导致dc相应增加,应该不是用这种做法。

  • 相关阅读:
    面条代码 vs. 馄沌代码
    GraphQL 到底怎么用?看看这个例子就知道了
    程序员难逃二八法则,如何晋升为头部 20% 玩家?
    正则匹配负正数和负小数
    js、Jquery处理自动计算的输入框事件
    mobile easyui兼容实体数据(tree插件为例)
    framework7中一行的字如果过多就省略号显示的CSS写法
    PHP获取系统时间不对的解决办法(转载)
    BZOJ 3156: 防御准备
    P4098 [HEOI2013]ALO
  • 原文地址:https://www.cnblogs.com/jeason1997/p/5920471.html
Copyright © 2020-2023  润新知