没有cc_matWorld的逆矩阵吗?

无语,内置的居然没有cc_matWorld的逆矩阵?

@ panda

https://docs.cocos.com/creator/manual/zh/shader/uniform.html

cc_matWorldIT 看看这个

这个是逆转置矩阵,我需要的是逆矩阵

模型顶点少的话自己在vs里面算一下吧,否则只能自己在脚本里面算好然后传local了。

 mat4 inverse_mat4(mat4 m)
    {
      float Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
      float Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
      float Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
      
      float Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
      float Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
      float Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
      
      float Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
      float Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
      float Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
      
      float Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
      float Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
      float Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
      
      float Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
      float Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
      float Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
      
      float Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
      float Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
      float Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
      
      const vec4 SignA = vec4( 1.0, -1.0,  1.0, -1.0);
      const vec4 SignB = vec4(-1.0,  1.0, -1.0,  1.0);
      
      vec4 Fac0 = vec4(Coef00, Coef00, Coef02, Coef03);
      vec4 Fac1 = vec4(Coef04, Coef04, Coef06, Coef07);
      vec4 Fac2 = vec4(Coef08, Coef08, Coef10, Coef11);
      vec4 Fac3 = vec4(Coef12, Coef12, Coef14, Coef15);
      vec4 Fac4 = vec4(Coef16, Coef16, Coef18, Coef19);
      vec4 Fac5 = vec4(Coef20, Coef20, Coef22, Coef23);
      
      vec4 Vec0 = vec4(m[1][0], m[0][0], m[0][0], m[0][0]);
      vec4 Vec1 = vec4(m[1][1], m[0][1], m[0][1], m[0][1]);
      vec4 Vec2 = vec4(m[1][2], m[0][2], m[0][2], m[0][2]);
      vec4 Vec3 = vec4(m[1][3], m[0][3], m[0][3], m[0][3]);
      
      vec4 Inv0 = SignA * (Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2);
      vec4 Inv1 = SignB * (Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4);
      vec4 Inv2 = SignA * (Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5);
      vec4 Inv3 = SignB * (Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5);
      
      mat4 Inverse = mat4(Inv0, Inv1, Inv2, Inv3);
      
      vec4 Row0 = vec4(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]);
      
      float Determinant = dot(m[0], Row0);
      
      Inverse /= Determinant;
      
      return Inverse;
    }

cocos 目前 shader基建确实是差了点

1赞

嗯,只能这样了,对了,兄弟,你知道cocos里怎么给Shader传递全局的变量吗?不改源码情况下

有方法 通过顶点参数传递的

如果你是用的builtin pipeline的话,global应该除了修改源码别无他法。如果你是SRP的话,应该可以用

#pragma builtin(global)
layout(set = 0, binding = 8) uniform CustomGlobal {
  //...
};

然后在

const pass = ppl.addRenderPass(...);
pass.addConstant(“CustomGlobal”);
pass.setMat4(...);
pass.setVec2(...);
// or other set function

我没有尝试过,只是提供个不改源码下的可能思路。

难受得一批,在cocos里想做一些效果,限制好多。麻烦得很

哎,不要太难受,cocos现阶段不知道在搞啥,3D开发者迫切需要的功能一个不上。shader graph/flare/light cookie/global uniform/volumetric rendering/…etc. 然后他们加了大部分手游都用不到的功能,什么海飞丝/Zeno & Houdini/Skin/…etc

别问,问就是定制引擎。

Houdini都支持? 没必要吧,Houdini连对Unity的支持都不是很好,bug一对,没啥用。难道cocos还想搞pcg?还不如做一些实用功能。说实话,我每次用cocos都感觉难受得一批,之前都好想做一些插件,做些材质,但是一想到cocos就难受,搞个东西麻烦得很。

无语,我想定义一个宏,在inspector面板上显示一个下拉列表,原本想的是这样:#pragma define-meta VOLUME_LIGHT_TYPE options([sphere, box, cylinder, cone])
后面通过判断 VOLUME_LIGHT_TYPE 来区分代码块。试了好多次都不行,

如果是这样的话#pragma define-meta VOLUME_LIGHT_TYPE options([0,1,2,3]),
inspector上面又只能显示数字。真的无语了。

官方文档也是写得不清不楚的。
感觉做一个东西困难重重,比tm唐僧取经还难。

是这样的,我有一个方法可以曲线救国,你试试看行不行

// 定义一个inspector options 
#pragma define-meta VOLUME_LIGHT_TYPE options([sphere, box, cylinder, cone])
// 定义一个已CC_开头不会显示在inspector上的define-meta,且值永远要保持为假
#pragma define-meta CC_USER_VOLUME_LIGHT_TYPE

// 定义一个程序块
CCProgram fun %{
  vec4 sphere() { return vec4(vec3(0.5),1.0);}
  vec4 box() { return vec4(vec3(0.2),1.0);}
  vec4 cylinder() {return vec4(0.0);}
  vec4 cone() {return vec4(1.0);}
}%

// 在需要的顶点或片元阶段引入
#include <fun>

// 在代码块中使用永远为假的判断避免编译时tree-shaking
// 切记这段代码一定要有,否则函数被判断为永不可能调用,会被删除,一旦被删除最终VOLUME_LIGHT_TYPE将找不到函数
#if CC_USER_VOLUME_LIGHT_TYPE
  sphere();
  box();
  cylinder();
  cone();
#endif

// 然后可以正常使用了
vec4 a = VOLUME_LIGHT_TYPE();    
s.albedo = a;

// inspector 种选择什么函数就会调用什么函数,曲线救国实现非数字下拉列表调用不同逻辑

嗯,谢谢老哥,我刚才试了下确实可以

话说,老哥,cocos里有没有什么比较好的办法渲染一张深度图呀?我看论坛里都是单独创建一个camera然后设置RenderTarget,这样的话drawcall就会翻倍了,有没有办法直接把main camera的depth buffer copy到RT上?

目前没有太好的办法,要么产生又读又写的问题,要么就只能不写只读,要么就是上pre depth pass。如果你是渲染任意物体都可能要用到depth texture,感觉只有pre depth pass靠谱啊,如果是post process阶段用深度图那直接用 currCamera.targetTexture.window.framebuffer.depthStencilTexture呗。该翻番翻番。哈哈哈。有什么好办法记得回来告诉我。或者你自己改引擎吧,在渲染完opaque后自己拷贝一份用。

好吧,只有我先自己研究一下了

你愿意自定义引擎吗

我这里讲一下定制引擎的思路吧!不一定是最好的。

首先webgl之类的API不允许既读既写。一般会报错。

 Feedback loop formed between Framebuffer and active Texture.

而我们又不想开PreDepthPass获取深度,以便dc * 2.
所以办法就是在渲染完opaque后,在渲染transparent前拷贝depth buffer到另一个texture。为什么不直接使用depth buffer,原因如上,不允许既读既写。虽然transparent不会开启depth write。

好了,只要在engine\engine\cocos\rendering\forward\forward-stage.ts 种添加如下代码即可:

首先定义一个类成员:

private _depthTexture: Texture = null!;

然后在render函数中初始化:

// 因为需要拷贝的深度缓冲,所以各个参数的意义就很清晰了。此处不在阐述。
        if (!this._depthTexture) {
			this._depthTexture = device.createTexture(
				new TextureInfo(
					TextureType.TEX2D,
					TextureUsageBit.DEPTH_STENCIL_ATTACHMENT | TextureUsageBit.SAMPLED,
					Format.DEPTH_STENCIL,
					this._renderArea.width,
					this._renderArea.height
				)
			);
		}

然后在渲染完opaque后,在渲染transparent前拷贝depth buffer


 let depth = camera.window.framebuffer.depthStencilTexture!;

 if (this._depthTexture) {
			const bufferCopy = new TextureBlit();
			bufferCopy.srcOffset.x = 0;
			bufferCopy.srcOffset.y = 0;
			bufferCopy.srcExtent.width = depth.width;
			bufferCopy.srcExtent.height = depth.height;

			bufferCopy.dstOffset.x = 0;
			bufferCopy.dstOffset.y = 0;
			bufferCopy.dstExtent.width = depth.width;
			bufferCopy.dstExtent.height = depth.height;

			cmdBuff.blitTexture(depth, this._depthTexture!, [bufferCopy], Filter.POINT);
 }

最后在recordCommandBuffer种修改将depthTexture传递到shader中

 // engine\engine\cocos\rendering\render-queue.ts
// 需要修改函数形参加上	depth?:Texture, sampler?: Sampler
  if (this._passDesc.isTransparent) {
	const handler = pass.getBinding('depthTexture');
	if (handler != 0) {
	   pass.bindTexture(handler, depth!);
	   pass.bindSampler(handler, sampler!);
    }
  }

// 调用如下: this._renderQueues[1].recordCommandBuffer(device, renderPass, cmdBuff,depth,camera.scene?.root.pipeline.globalDSManager.pointSampler!);

然后你会发现:
image

没拷贝成功~。这里我不知道为什么没拷贝成功~。

但是在我的自定义引擎中是成功的。因为我的自定义引擎和官方引擎的区别是官方forward是上屏渲染。而我为了后处理把forward改成了离屏渲染。

所以我的forward本身就是一个离屏framebuffer。然后depth texture是一个通过device.createTextue创建的gfx.texture。不管咋样,离屏framebuffer的depth buffer可以拷贝成功。

image

就酱!如果你要是晓得为什么上屏没有拷贝成功,请务必告诉我。

再说个就是官方现在的SRP非常不稳定,问题很大,性能和内置的差太多,基本上处于不可用状态。不管是做小游戏还是其他什么游戏。