日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CocosCreator2.1.0渲染流程与shader

發(fā)布時間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CocosCreator2.1.0渲染流程与shader 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

CocosCreator2.1.0版本正式支持導(dǎo)入3D模型

對于2.5D游戲的開發(fā)來說有著重要意義

自己此前在寫捕魚游戲時了解過自定義shader

并實現(xiàn)了4種不同的水波效果

但經(jīng)過CocosCreator版本的不斷升級

尤其是1.10和2.0兩個版本

舊的渲染器被拋棄了

因此老的shader特效也全都不能用了

直到最近正好有時間,花了幾天把原先寫的特效升級到了最新的2.1.0版本

下面記錄一下自定義shader實現(xiàn)方法的改變

以及新的渲染器的理解

?

過往自定義shader的實現(xiàn)依賴

cc.gl

cc.GLProgram

cc.GLProgramState

CCSprite._sgNode

CCTexture2D.setTexParameters

這些統(tǒng)統(tǒng)都不能用了!

取而代之的是新的渲染結(jié)構(gòu)

顯然又是多層封裝咯

最上層的material關(guān)聯(lián)到sprite組件

最底層的pass關(guān)聯(lián)到具體的vert和frag著色器代碼,也就是Shader層

其實Shader層才應(yīng)該是最底層的

從底向上一層層來看

?

Shader

系統(tǒng)默認的shader是通過以下方法保存在lib對象中的

ProgramLib.prototype.define = function define (name, vert, frag, defines) {

而lib對象所在的位置比較奇怪,可能往后的版本會變更

cc.renderer._forward._programLib

著色器代碼也需要稍作修改

以往的CC_Texture0等固定變量都不存在了

?

Pass

Pass的構(gòu)造函數(shù)傳入的name就是與著色器同名的name

所以Pass是直接關(guān)聯(lián)shader的

另外Pass還包含了混合參數(shù)、深度測試參數(shù)、模板測試參數(shù)等等

Base.prototype._draw = function _draw (item) {var this$1 = this;var device = this._device;var programLib = this._programLib;var node = item.node;var ia = item.ia;var effect = item.effect;var technique = item.technique;var defines = item.defines;// reset the pool// NOTE: we can use drawCounter optimize this// TODO: should be configurable _float2_pool.reset();_float3_pool.reset();_float4_pool.reset();_float9_pool.reset();_float16_pool.reset();_float64_pool.reset();_int2_pool.reset();_int3_pool.reset();_int4_pool.reset();_int64_pool.reset();// set common uniforms// TODO: try commit this depends on effect// {node.getWorldMatrix(_m4_tmp$2);device.setUniform('model', mat4.array(_float16_pool.add(), _m4_tmp$2));var inverse = mat3.invert(_m3_tmp$1, mat3.fromMat4(_m3_tmp$1, _m4_tmp$2));if (inverse) {mat3.transpose(_m3_tmp$1, inverse);device.setUniform('normalMatrix', mat3.array(_float9_pool.add(), _m3_tmp$1));}// }// set technique uniformsfor (var i = 0; i < technique._parameters.length; ++i) {
// 這里遍歷technique._parameters
// 再從effect找到參數(shù)的值
// 因此參數(shù)必須在technique中聲明并同時在effect中定義
// 若不在technique中聲明,則不會遍歷不會走到device.setUniform這一步
var prop = technique._parameters[i];var param = effect.getProperty(prop.name);// 若未在effect中賦值,則從technique中找默認if (param === undefined) {param = prop.val;}// 默認也找不到,就給個該類型的default值if (param === undefined) {param = this$1._type2defaultValue[prop.type];}if (param === undefined) {console.warn(("Failed to set technique property " + (prop.name) + ", value not found."));continue;}if (prop.type === enums.PARAM_TEXTURE_2D ||prop.type === enums.PARAM_TEXTURE_CUBE) {if (prop.size !== undefined) {if (prop.size !== param.length) {console.error(("The length of texture array (" + (param.length) + ") is not corrent(expect " + (prop.size) + ")."));continue;}var slots = _int64_pool.add();for (var index = 0; index < param.length; ++index) {slots[index] = this$1._allocTextuerUnit();}device.setTextureArray(prop.name, param, slots);} else {device.setTexture(prop.name, param, this$1._allocTextuerUnit());}} else {var convertedValue = (void 0);if (param instanceof Float32Array || param instanceof Int32Array) {convertedValue = param;}else if (prop.size !== undefined) {var convertArray = _type2uniformArrayValue[prop.type];if (convertArray.func === undefined) {console.error('Uniform array of color3/int3/float3/mat3 can not be supportted!');continue;}if (prop.size * convertArray.size > 64) {console.error('Uniform array is too long!');continue;}convertedValue = convertArray.func(param);} else {var convertFn = _type2uniformValue[prop.type];convertedValue = convertFn(param);}device.setUniform(prop.name, convertedValue);}}// for each passfor (var i$1 = 0; i$1 < technique._passes.length; ++i$1) {var pass = technique._passes[i$1];var count = ia.getPrimitiveCount();// set vertex bufferdevice.setVertexBuffer(0, ia._vertexBuffer);// set index bufferif (ia._indexBuffer) {device.setIndexBuffer(ia._indexBuffer);}// set primitive type device.setPrimitiveType(ia._primitiveType);// set program (通過pass里保存的program名字找到著色器program!)var program = programLib.getProgram(pass._programName, defines);device.setProgram(program);// cull mode device.setCullMode(pass._cullMode);// blendif (pass._blend) {device.enableBlend();device.setBlendFuncSep(pass._blendSrc,pass._blendDst,pass._blendSrcAlpha,pass._blendDstAlpha);device.setBlendEqSep(pass._blendEq,pass._blendAlphaEq);device.setBlendColor32(pass._blendColor);}// depth test & writeif (pass._depthTest) {device.enableDepthTest();device.setDepthFunc(pass._depthFunc);}if (pass._depthWrite) {device.enableDepthWrite();}// stencilif (pass._stencilTest) {device.enableStencilTest();// front device.setStencilFuncFront(pass._stencilFuncFront,pass._stencilRefFront,pass._stencilMaskFront);device.setStencilOpFront(pass._stencilFailOpFront,pass._stencilZFailOpFront,pass._stencilZPassOpFront,pass._stencilWriteMaskFront);// back device.setStencilFuncBack(pass._stencilFuncBack,pass._stencilRefBack,pass._stencilMaskBack);device.setStencilOpBack(pass._stencilFailOpBack,pass._stencilZFailOpBack,pass._stencilZPassOpBack,pass._stencilWriteMaskBack);}// draw pass device.draw(ia._start, count);this$1._resetTextuerUnit();} };

?

Technique

Technique的構(gòu)造函數(shù)如下

var Technique = function Technique(stages, parameters, passes, layer) {

stages不太了解

parameters聲明了注入shader代碼中的參數(shù)名和類型

未聲明的參數(shù)即使寫在shader里面也是無法使用的

passes可以指定多個,是否意味著多次渲染

以下是默認的SpriteMaterial中的Technique

var mainTech = new renderer.Technique(['transparent'],[{ name: 'texture', type: renderer.PARAM_TEXTURE_2D },{ name: 'color', type: renderer.PARAM_COLOR4 } ],[pass] );

可以看到只設(shè)置了兩個參數(shù)

因此在著色器中可以使用texture紋理采樣

同時使用節(jié)點顏色color

?

Effect

Effect的構(gòu)造函數(shù)如下

var Effect = function Effect(techniques, properties, defines) {

以下是默認的SpriteMaterial中的Effect

this._effect = new renderer.Effect([mainTech ],{'color': this._color},[{ name: 'useTexture', value: true },{ name: 'useModel', value: false },{ name: 'alphaTest', value: false },{ name: 'useColor', value: true } ] );

在自定義材質(zhì)中properties直接傳空對象{}即可

如果是不變的uniform參數(shù)可以在technique中賦值默認val

如果是變化的uniform參數(shù),如time、衰減因子、點擊位置等等

通過以下方法來更新變量的值即可

Effect.prototype.setProperty = function setProperty (name, value) {

?

Material

自定義材質(zhì)可以繼承自默認材質(zhì)

也可以類比SpriteMaterial來寫

但我覺得那樣太麻煩了,直接繼承Material把幾個有用的參數(shù)填進去就行了

而材質(zhì)與sprite的綁定也簡化為兩行代碼

原本CCSprite._activateMaterial統(tǒng)統(tǒng)省去

當紋理和頂點信息不改變的情況下

我認為以下兩句是可以省略的

this.markForUpdateRenderData(true);

this.markForRender(true);

并且在h5、微信、安卓原生平臺均驗證有效 class CustomMaterial extends cc.renderer.renderEngine.Material{constructor(name , vert , frag , uniforms = [] , defines = []){super(false);this.name = namelet lib = cc.renderer._forward._programLib;!lib._templates[name] && lib.define(name, vert, frag, defines);this.init(name , uniforms);}use(sprite){// cc.dynamicAtlasManager.enabled = false;// 設(shè)置基本紋理和顏色let texture = sprite.spriteFrame.getTexture();let color = sprite.node.colorthis.setTexture(texture);this.setUniform('color' , { r: color.r / 255, g: color.g / 255, b: color.b / 255, a: sprite.node.opacity / 255 })this.updateHash();// 指定sprite的材質(zhì)sprite._material = this;sprite._renderData._material = this;sprite._state = cc.Sprite.State.CUSTOM;}init(name , uniforms) {let renderer = cc.renderer.renderEngine.renderer;let gfx = cc.renderer.renderEngine.gfx;let pass = new renderer.Pass(name);pass.setDepth(false, false);pass.setCullMode(gfx.CULL_NONE);pass.setBlend(gfx.BLEND_FUNC_ADD,gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,gfx.BLEND_FUNC_ADD,gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA);let mainTech = new renderer.Technique(['transparent'],[...uniforms,{ name: 'texture', type: renderer.PARAM_TEXTURE_2D /*, val : '默認值'*/},{ name: 'color', type: renderer.PARAM_COLOR4 /*, val : '默認值'*/},],[pass]);this._texture = null;this._effect = this.effect = new renderer.Effect([mainTech], {}, []);this._mainTech = mainTech;} };

?

Render

可渲染節(jié)點如包含CCSprite組件的node

渲染組件CCSprite繼承自RenderComponent

渲染組件onEnable時會為node賦值渲染組件的索引

this.node._renderComponent = this;

CCDirector.mainLoop中發(fā)起渲染命令

RenderComponentWalker.visit遍歷場景節(jié)點

RenderFlow._children方法中會過濾點!active和全透明的節(jié)點

if (!c._activeInHierarchy || c._opacity === 0) continue;

RenderComponentWalker._commitComp中比較material的hash值

這也是updateHash的意義所在(若不調(diào)用updateHash很可能會報錯,比如當節(jié)點是首個渲染節(jié)點時)

若hash值相同會使用上一個材質(zhì)(流水線操作)

_commitComp (comp, assembler, cullingMask) {if (this.material._hash !== comp._material._hash || this.cullingMask !== cullingMask) {this._flush();this.node = assembler.useModel ? comp.node : this._dummyNode;this.material = comp._material;this.cullingMask = cullingMask;}assembler.fillBuffers(comp, this);},

RenderComponentWalker._flush

Scene.prototype.addModel添加至渲染模型數(shù)組

Base.prototype._render會遍歷模型數(shù)組

顯然model中是包含material等全部渲染信息的

再由Base.prototype._draw渲染每一個顯示模型

最后由Device.prototype.draw調(diào)用opengl命令完成繪制~

?

貼一張微信小游戲的水波點擊效果圖(H5、安卓原生效果一致)

參考文獻

https://forum.cocos.com/t/cocos-creator-2-x-shader/69098

轉(zhuǎn)載于:https://www.cnblogs.com/billyrun/articles/10383935.html

總結(jié)

以上是生活随笔為你收集整理的CocosCreator2.1.0渲染流程与shader的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。