import assert from 'node:assert/strict'; import {test} from 'node:test'; import {readFile} from 'node:fs/promises'; import * as THREE from 'three'; import {loadTypescript} from './support/load-typescript.mjs'; const {attachMeshRefraction,meshRefractionShader}=await loadTypescript(new URL('../src/rendering/MeshRefraction.ts',import.meta.url)); const {PetDepthMesh}=await loadTypescript(new URL('../src/objects/PetDepthMesh.ts',import.meta.url)); test('opt-in photo alpha preserves original opaque default and exposes partial-edge continuation',()=>{ const source=new PetDepthMesh(new THREE.Texture(),new THREE.Texture()); assert.equal(source.material.uniforms.uUsePhotoAlpha?.value,false); const b=attachMeshRefraction(new THREE.MeshPhysicalMaterial(),source); source.material.uniforms.uUsePhotoAlpha.value=true; b.sync({width:1,height:1,grid:20,curvature:1},.58,new THREE.Color()); assert.equal(b.uniforms.uBUsePhotoAlpha.value,true); assert.match(meshRefractionShader,/photoColor\.rgb\+backgroundColor\*\(1\.-photoColor\.a\)/); assert.match(meshRefractionShader,/bCourtyardHit\(exitPoint,outgoing/); assert.match(source.material.fragmentShader,/if\(uUsePhotoAlpha/); source.geometry.dispose();source.material.dispose(); }); test('house post-pass depth honors the same dog alpha instead of occluding its rectangular background',async()=>{ const {createHousePhotoOccluder}=await loadTypescript(new URL('../src/objects/BlenderHouseSurround.ts',import.meta.url)); const source=new PetDepthMesh(new THREE.Texture(),new THREE.Texture()),depth=createHousePhotoOccluder(source); assert.match(depth.mesh.material.fragmentShader,/uUsePhotoAlpha/);assert.match(depth.mesh.material.fragmentShader,/discard/); assert.equal(depth.mesh.material.uniforms,source.material.uniforms);depth.dispose();source.geometry.dispose();source.material.dispose(); }); test('two separated photo hits accumulate a soft fringe in front of an opaque dog instead of leaking yard',()=>{ const depth=new THREE.PlaneGeometry(1,1,128,128),position=depth.getAttribute('position'); for(let i=0;i!i||Math.abs(hit.distance-all[i-1].distance)>.00001); assert.ok(hits.length>=2,'actual displaced geometry provides distinct front-facing layers'); const match=meshRefractionShader.match(/float bPhotoCoverageWeight\(float coverage,float alpha\)\s*\{return ([^;]+);\}/); assert.ok(match,'production ray uses front-to-back coverage weight'); const weight=new Function('coverage','alpha','return '+match[1]); let coverage=0,rgb=[0,0,0]; for(const [color,alpha] of [[[1,0,0],.25],[[0,1,0],1]]){const w=weight(coverage,alpha);rgb=rgb.map((v,i)=>v+w*color[i]);coverage+=w;} assert.deepEqual(rgb,[.25,.75,0]);assert.equal(coverage,1); assert.match(meshRefractionShader,/sampleIndex<2/);assert.match(meshRefractionShader,/t