yuvBehavior.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. import { createScopedThreejs } from 'threejs-miniprogram'
  2. import { registerGLTFLoader } from '../../utils/gltf-loader'
  3. const threeBehavior = Behavior({
  4. methods: {
  5. // 针对 threejs 的初始化逻辑
  6. initTHREE() {
  7. const THREE = this.THREE = createScopedThreejs(this.canvas)
  8. registerGLTFLoader(THREE)
  9. // glTF loader
  10. this.loader = new this.THREE.GLTFLoader()
  11. // 相机
  12. this.camera = new THREE.PerspectiveCamera(50, 0.7, 0.1, 1000)
  13. // 场景
  14. const scene = this.scene = new THREE.Scene()
  15. const sceneCull = this.sceneCull = new THREE.Scene()
  16. // 光源
  17. const ambientLight = new THREE.AmbientLight(0x555555) // 氛围光
  18. scene.add(ambientLight)
  19. const dirLight = new THREE.DirectionalLight(0xffffff, 1) // 平行光
  20. dirLight.position.set(1, 1, 1)
  21. scene.add(dirLight)
  22. const ambientLightCull = new THREE.AmbientLight(0x555555) // 氛围光
  23. sceneCull.add(ambientLightCull)
  24. const dirLightCull = new THREE.DirectionalLight(0xffffff, 1) // 平行光
  25. dirLightCull.position.set(1, 1, 1)
  26. sceneCull.add(dirLightCull)
  27. // 渲染层
  28. const renderer = this.renderer = new THREE.WebGLRenderer({
  29. antialias: true,
  30. alpha: true
  31. })
  32. renderer.gammaOutput = true
  33. renderer.gammaFactor = 2.2
  34. },
  35. initYUVShader() {
  36. const gl = this.gl = this.renderer.getContext()
  37. const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM)
  38. const vs = `
  39. attribute vec2 a_position;
  40. attribute vec2 a_texCoord;
  41. uniform mat3 displayTransform;
  42. varying vec2 v_texCoord;
  43. void main() {
  44. vec3 p = displayTransform * vec3(a_position, 0);
  45. gl_Position = vec4(p, 1);
  46. v_texCoord = a_texCoord;
  47. }
  48. `
  49. const fs = `
  50. precision highp float;
  51. uniform sampler2D y_texture;
  52. uniform sampler2D uv_texture;
  53. varying vec2 v_texCoord;
  54. void main() {
  55. vec4 y_color = texture2D(y_texture, v_texCoord);
  56. vec4 uv_color = texture2D(uv_texture, v_texCoord);
  57. float Y, U, V;
  58. float R ,G, B;
  59. Y = y_color.r;
  60. U = uv_color.r - 0.5;
  61. V = uv_color.a - 0.5;
  62. R = Y + 1.402 * V;
  63. G = Y - 0.344 * U - 0.714 * V;
  64. B = Y + 1.772 * U;
  65. gl_FragColor = vec4(R, G, B, 1.0);
  66. }
  67. `
  68. const vertShader = gl.createShader(gl.VERTEX_SHADER)
  69. gl.shaderSource(vertShader, vs)
  70. gl.compileShader(vertShader)
  71. const fragShader = gl.createShader(gl.FRAGMENT_SHADER)
  72. gl.shaderSource(fragShader, fs)
  73. gl.compileShader(fragShader)
  74. const program = this._program = gl.createProgram()
  75. this._program.gl = gl
  76. gl.attachShader(program, vertShader)
  77. gl.attachShader(program, fragShader)
  78. gl.deleteShader(vertShader)
  79. gl.deleteShader(fragShader)
  80. gl.linkProgram(program)
  81. gl.useProgram(program)
  82. const uniformYTexture = gl.getUniformLocation(program, 'y_texture')
  83. gl.uniform1i(uniformYTexture, 5)
  84. const uniformUVTexture = gl.getUniformLocation(program, 'uv_texture')
  85. gl.uniform1i(uniformUVTexture, 6)
  86. this._dt = gl.getUniformLocation(program, 'displayTransform')
  87. gl.useProgram(currentProgram)
  88. },
  89. initVAO(program) {
  90. const gl = this.renderer.getContext()
  91. const ext = gl.getExtension('OES_vertex_array_object')
  92. this.ext = ext
  93. const currentVAO = gl.getParameter(gl.VERTEX_ARRAY_BINDING)
  94. const vao = ext.createVertexArrayOES()
  95. ext.bindVertexArrayOES(vao)
  96. const posAttr = gl.getAttribLocation(program, 'a_position')
  97. const pos = gl.createBuffer()
  98. gl.bindBuffer(gl.ARRAY_BUFFER, pos)
  99. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 1, -1, 1, 1, -1, -1, -1]), gl.STATIC_DRAW)
  100. gl.vertexAttribPointer(posAttr, 2, gl.FLOAT, false, 0, 0)
  101. gl.enableVertexAttribArray(posAttr)
  102. vao.posBuffer = pos
  103. const texcoordAttr = gl.getAttribLocation(program, 'a_texCoord')
  104. const texcoord = gl.createBuffer()
  105. gl.bindBuffer(gl.ARRAY_BUFFER, texcoord)
  106. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 1, 0, 1, 1, 0, 0, 0]), gl.STATIC_DRAW)
  107. gl.vertexAttribPointer(texcoordAttr, 2, gl.FLOAT, false, 0, 0)
  108. gl.enableVertexAttribArray(texcoordAttr)
  109. vao.texcoordBuffer = texcoord
  110. ext.bindVertexArrayOES(currentVAO)
  111. return vao
  112. },
  113. initYUV() {
  114. this.initYUVShader()
  115. this._vao = this.initVAO(this._program)
  116. },
  117. renderYUV(frame) {
  118. const gl = this.renderer.getContext()
  119. gl.disable(gl.DEPTH_TEST)
  120. const {
  121. yTexture,
  122. uvTexture
  123. } = frame.getCameraTexture(gl, 'yuv')
  124. const displayTransform = frame.getDisplayTransform()
  125. if (yTexture && uvTexture) {
  126. const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM)
  127. const currentActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE)
  128. const currentVAO = gl.getParameter(gl.VERTEX_ARRAY_BINDING)
  129. gl.useProgram(this._program)
  130. this.ext.bindVertexArrayOES(this._vao)
  131. gl.uniformMatrix3fv(this._dt, false, displayTransform)
  132. gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1)
  133. gl.activeTexture(gl.TEXTURE0 + 5)
  134. const bindingTexture5 = gl.getParameter(gl.TEXTURE_BINDING_2D)
  135. gl.bindTexture(gl.TEXTURE_2D, yTexture)
  136. gl.activeTexture(gl.TEXTURE0 + 6)
  137. const bindingTexture6 = gl.getParameter(gl.TEXTURE_BINDING_2D)
  138. gl.bindTexture(gl.TEXTURE_2D, uvTexture)
  139. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
  140. gl.bindTexture(gl.TEXTURE_2D, bindingTexture6)
  141. gl.activeTexture(gl.TEXTURE0 + 5)
  142. gl.bindTexture(gl.TEXTURE_2D, bindingTexture5)
  143. gl.useProgram(currentProgram)
  144. gl.activeTexture(currentActiveTexture)
  145. this.ext.bindVertexArrayOES(currentVAO)
  146. }
  147. },
  148. initDepthShaderHint() {
  149. const gl = this.gl = this.renderer.getContext()
  150. const ext = gl.getExtension('OES_texture_float')
  151. if (!ext) console.warn('OES_texture_float not support')
  152. const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM)
  153. const vs = `
  154. precision highp float;
  155. attribute vec2 a_position;
  156. attribute vec2 a_texCoord;
  157. uniform mat3 displayTransform;
  158. varying vec2 v_texCoord;
  159. void main() {
  160. vec3 p = displayTransform * vec3(a_position, 0);
  161. gl_Position = vec4(p, 1);
  162. v_texCoord = a_texCoord;
  163. }
  164. `
  165. const fs = `
  166. precision highp float;
  167. uniform sampler2D depth_texture;
  168. varying vec2 v_texCoord;
  169. void main() {
  170. vec4 depth_color = texture2D(depth_texture, v_texCoord);
  171. gl_FragColor = vec4(depth_color.rgb, 1.0);
  172. }
  173. `
  174. const vertShader = gl.createShader(gl.VERTEX_SHADER)
  175. gl.shaderSource(vertShader, vs)
  176. gl.compileShader(vertShader)
  177. const fragShader = gl.createShader(gl.FRAGMENT_SHADER)
  178. gl.shaderSource(fragShader, fs)
  179. gl.compileShader(fragShader)
  180. const program = this._depthProgram = gl.createProgram()
  181. this._depthProgram.gl = gl
  182. gl.attachShader(program, vertShader)
  183. gl.attachShader(program, fragShader)
  184. gl.deleteShader(vertShader)
  185. gl.deleteShader(fragShader)
  186. gl.linkProgram(program)
  187. gl.useProgram(program)
  188. const uniformTexture = gl.getUniformLocation(program, 'depth_texture')
  189. gl.uniform1i(uniformTexture, 5)
  190. this._depthDt = gl.getUniformLocation(program, 'displayTransform')
  191. gl.useProgram(currentProgram)
  192. },
  193. initDepthVAOHint() {
  194. const gl = this.renderer.getContext()
  195. const ext = gl.getExtension('OES_vertex_array_object')
  196. this.ext = ext
  197. const currentVAO = gl.getParameter(gl.VERTEX_ARRAY_BINDING)
  198. const vao = ext.createVertexArrayOES()
  199. ext.bindVertexArrayOES(vao)
  200. const posAttr = gl.getAttribLocation(this._depthProgram, 'a_position')
  201. const pos = gl.createBuffer()
  202. gl.bindBuffer(gl.ARRAY_BUFFER, pos)
  203. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.3, 0.3, 1, 0.3, 0.3, 1, 1, 1]), gl.STATIC_DRAW)
  204. gl.vertexAttribPointer(posAttr, 2, gl.FLOAT, false, 0, 0)
  205. gl.enableVertexAttribArray(posAttr)
  206. vao.posBuffer = pos
  207. const texcoordAttr = gl.getAttribLocation(this._depthProgram, 'a_texCoord')
  208. const texcoord = gl.createBuffer()
  209. gl.bindBuffer(gl.ARRAY_BUFFER, texcoord)
  210. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW)
  211. gl.vertexAttribPointer(texcoordAttr, 2, gl.FLOAT, false, 0, 0)
  212. gl.enableVertexAttribArray(texcoordAttr)
  213. vao.texcoordBuffer = texcoord
  214. ext.bindVertexArrayOES(currentVAO)
  215. this._depthVao = vao
  216. },
  217. initDepthShader() {
  218. const gl = this.gl = this.renderer.getContext()
  219. const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM)
  220. const dvs = `#version 300 es
  221. precision highp float;
  222. in vec2 a_position;
  223. in vec2 a_texCoord;
  224. uniform mat3 displayTransform;
  225. uniform sampler2D depth_texture;
  226. out vec2 v_texCoord;
  227. void main() {
  228. vec3 p = displayTransform * vec3(a_position, 1);
  229. v_texCoord = a_texCoord;
  230. vec4 depth_color = texture(depth_texture, v_texCoord);
  231. gl_Position = vec4(p.x, p.y, p.z, 1);
  232. }
  233. `
  234. const dfs = `#version 300 es
  235. precision highp float;
  236. uniform sampler2D depth_texture;
  237. out vec4 FragColor;
  238. in vec2 v_texCoord;
  239. void main() {
  240. vec4 depth_color = texture(depth_texture, v_texCoord);
  241. gl_FragDepth = depth_color.r;
  242. // FragColor = vec4(depth_color.rgb, 1.0);
  243. }
  244. `
  245. const vertShader = gl.createShader(gl.VERTEX_SHADER)
  246. gl.shaderSource(vertShader, dvs)
  247. gl.compileShader(vertShader)
  248. const fragShader = gl.createShader(gl.FRAGMENT_SHADER)
  249. gl.shaderSource(fragShader, dfs)
  250. gl.compileShader(fragShader)
  251. const program = this._depthOutputProgram = gl.createProgram()
  252. this._depthOutputProgram.gl = gl
  253. gl.attachShader(program, vertShader)
  254. gl.attachShader(program, fragShader)
  255. gl.deleteShader(vertShader)
  256. gl.deleteShader(fragShader)
  257. gl.linkProgram(program)
  258. gl.useProgram(program)
  259. const uniformDepthTexture = gl.getUniformLocation(this._depthOutputProgram, 'depth_texture')
  260. gl.uniform1i(uniformDepthTexture, 5)
  261. gl.getUniformLocation(this._depthOutputProgram, 'displayTransform')
  262. gl.useProgram(currentProgram)
  263. },
  264. initDepthGL() {
  265. // 初始化提示
  266. this.initDepthShaderHint()
  267. this.initDepthVAOHint()
  268. // 初始化深度纹理相关
  269. this.initDepthShader()
  270. this._vaoDepth = this.initVAO(this._depthOutputProgram)
  271. },
  272. renderDepthGLHint(frame) {
  273. const gl = this.renderer.getContext()
  274. const displayTransform = frame.getDisplayTransform()
  275. // DepthBuffer
  276. const depthBufferRes = frame.getDepthBuffer()
  277. const depthBuffer = new Float32Array(depthBufferRes.DepthAddress)
  278. // console.log('depthBuffer', depthBuffer[0], depthBuffer[16], depthBuffer[16 * 16], depthBuffer[56 * 56]);
  279. const texture = gl.createTexture()
  280. gl.bindTexture(gl.TEXTURE_2D, texture)
  281. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
  282. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
  283. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
  284. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
  285. const width = depthBufferRes.width
  286. const height = depthBufferRes.height
  287. // 先直接采用 uint8 写入深度纹理,使用浮点写入的方法会存在锯齿
  288. const data = new Uint8Array(width * height * 4)
  289. for (let i = 0; i < depthBuffer.length; i++) {
  290. const num = parseInt(depthBuffer[i] * 255)
  291. data[i] = num
  292. }
  293. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
  294. const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM)
  295. const currentActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE)
  296. const currentVAO = gl.getParameter(gl.VERTEX_ARRAY_BINDING)
  297. gl.useProgram(this._depthProgram)
  298. this.ext.bindVertexArrayOES(this._depthVao)
  299. gl.uniformMatrix3fv(this._depthDt, false, displayTransform)
  300. gl.activeTexture(gl.TEXTURE0 + 5)
  301. const bindingTexture5 = gl.getParameter(gl.TEXTURE_BINDING_2D)
  302. gl.bindTexture(gl.TEXTURE_2D, texture)
  303. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
  304. gl.activeTexture(gl.TEXTURE0 + 5)
  305. gl.bindTexture(gl.TEXTURE_2D, bindingTexture5)
  306. gl.useProgram(currentProgram)
  307. gl.activeTexture(currentActiveTexture)
  308. this.ext.bindVertexArrayOES(currentVAO)
  309. },
  310. renderDepthGL(frame) {
  311. const gl = this.renderer.getContext()
  312. const displayTransform = frame.getDisplayTransform()
  313. // DepthBuffer
  314. const depthBufferRes = frame.getDepthBuffer()
  315. const depthBuffer = new Float32Array(depthBufferRes.DepthAddress)
  316. const texture = gl.createTexture()
  317. gl.bindTexture(gl.TEXTURE_2D, texture)
  318. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
  319. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
  320. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
  321. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
  322. const width = depthBufferRes.width
  323. const height = depthBufferRes.height
  324. // 先直接采用 uint8 写入深度纹理,使用浮点写入的方法会存在锯齿
  325. const data = new Uint8Array(width * height * 4)
  326. for (let i = 0; i < depthBuffer.length; i++) {
  327. const num = parseInt(depthBuffer[i] * 255)
  328. data[i] = num
  329. }
  330. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
  331. // console.log('gl depth texture end')
  332. // 绘制左下角提示
  333. const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM)
  334. const currentActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE)
  335. const currentVAO = gl.getParameter(gl.VERTEX_ARRAY_BINDING)
  336. const bindingTexture = gl.getParameter(gl.TEXTURE_BINDING_2D)
  337. gl.useProgram(this._depthProgram)
  338. this.ext.bindVertexArrayOES(this._depthVao)
  339. gl.uniformMatrix3fv(this._depthDt, false, displayTransform)
  340. gl.activeTexture(gl.TEXTURE0 + 5)
  341. const bindingTexture5 = gl.getParameter(gl.TEXTURE_BINDING_2D)
  342. gl.bindTexture(gl.TEXTURE_2D, texture)
  343. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
  344. gl.activeTexture(gl.TEXTURE0 + 5)
  345. gl.bindTexture(gl.TEXTURE_2D, bindingTexture5)
  346. gl.useProgram(currentProgram)
  347. gl.activeTexture(currentActiveTexture)
  348. this.ext.bindVertexArrayOES(currentVAO)
  349. // console.log('gl hint end')
  350. // 写入深度遮挡纹理到深度值
  351. gl.enable(gl.DEPTH_TEST)
  352. gl.depthMask(true)
  353. gl.depthFunc(gl.ALWAYS)
  354. this.ext.bindVertexArrayOES(this._vaoDepth)
  355. gl.useProgram(this._depthOutputProgram)
  356. gl.uniformMatrix3fv(this._depthDt, false, displayTransform)
  357. gl.activeTexture(gl.TEXTURE0 + 5)
  358. const bindingTexture5Depth = gl.getParameter(gl.TEXTURE_BINDING_2D)
  359. gl.bindTexture(gl.TEXTURE_2D, texture)
  360. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
  361. gl.activeTexture(gl.TEXTURE0 + 5)
  362. gl.bindTexture(gl.TEXTURE_2D, bindingTexture5Depth)
  363. gl.useProgram(currentProgram)
  364. gl.activeTexture(currentActiveTexture)
  365. gl.bindTexture(gl.TEXTURE_2D, bindingTexture)
  366. this.ext.bindVertexArrayOES(currentVAO)
  367. gl.depthMask(false)
  368. gl.depthFunc(gl.LESS)
  369. // console.log('gl depth draw end')
  370. },
  371. },
  372. })
  373. export default threeBehavior