this is my code:
getSDFTexture(group:any){
this.initWposMat(group)
this.ray = new Raycaster();
this.ray.firstHitOnly = true;
let boundingBox = new Box3().setFromObject(group) //min max
this.sdfDebug.uniforms.bbox.value = [boundingBox.min, boundingBox.max]
this.totalSize = boundingBox.getSize(new Vector3());
group.traverse((obj:any)=>{
if(obj.isMesh){
obj.geometry.computeBoundingSphere() //obj.geometry.boundingSphere.radius
obj.userData.radius = obj.geometry.boundingSphere.radius
this.objList.push(obj)
}
})
//划分网格
let reso = 64
// let minBorder = Math.min(this.totalSize.x,this.totalSize.y,this.totalSize.z)
let maxBorder = Math.sqrt(Math.pow(reso,2)*3)
let data32Size = new Vector3(reso,reso,reso) //new Vector3().copy(this.totalSize).divideScalar(minBorder).ceil().multiplyScalar(32)
let step = new Vector3().copy(this.totalSize).divide(data32Size);
let halfStep = new Vector3().copy(step).multiplyScalar(0.5)
let currentPos = new Vector3()
let offset = new Vector3()
let data = []
let curIdx = 0
for (let z = 0; z < data32Size.z; z++) {
for (let y = 0; y < data32Size.y; y++) {
for (let x = 0; x < data32Size.x; x++) {
offset = new Vector3().copy(boundingBox.min).add(halfStep)
currentPos.set(x,y,z).multiply(step)
offset.add(currentPos)
//找出包含这个位置的所有obj,找出最接近的面,需要把坐标用临时变量转到对应空间
let minDistance = maxBorder
let isOutside = 1
this.objList.forEach((obj:any)=>{
// let sphereCenter = obj.getWorldPosition(new Vector3())
// let radius = obj.userData.radius
// let distanceOfsToSphCenter = offset.distanceTo(sphereCenter)
// if(distanceOfsToSphCenter>radius){
// return
// }
let meshInvMatrix = new Matrix4()
meshInvMatrix.copy(obj.matrixWorld).invert();
let local = offset.clone().applyMatrix4(meshInvMatrix)
//找出距离最近的三角形
let geo = obj.geometry
let positionAtt = geo.attributes.position
let indexAtt = geo.index
let triangle
if(indexAtt){
for (let i = 0; i < indexAtt.count; i += 3) {
const a = indexAtt.getX(i);
const b = indexAtt.getX(i + 1);
const c = indexAtt.getX(i + 2);
const vertexA = new Vector3().fromBufferAttribute(positionAtt, a);
const vertexB = new Vector3().fromBufferAttribute(positionAtt, b);
const vertexC = new Vector3().fromBufferAttribute(positionAtt, c);
triangle = new Triangle(vertexA, vertexB, vertexC)
let clostLocPos = triangle.closestPointToPoint(local,new Vector3())
let distSquat = local.distanceTo(clostLocPos)
if(distSquat<minDistance){
minDistance = distSquat
//请在这里计算local点在模型的正面还是反面
let normal = triangle.getNormal(new Vector3())
let toPoint = local.clone().sub(clostLocPos)
isOutside = Math.sign(normal.dot(toPoint))
}
}
}else{
for (let i = 0; i < positionAtt.count; i += 9) {
const vertexA = new Vector3(
positionAtt.getX(i),
positionAtt.getY(i),
positionAtt.getZ(i)
);
const vertexB = new Vector3(
positionAtt.getX(i + 3),
positionAtt.getY(i + 3),
positionAtt.getZ(i + 3)
);
const vertexC = new Vector3(
positionAtt.getX(i + 6),
positionAtt.getY(i + 6),
positionAtt.getZ(i + 6)
);
triangle = new Triangle(vertexA, vertexB, vertexC)
let clostLocPos = triangle.closestPointToPoint(local,new Vector3())
let distSquat = local.distanceTo(clostLocPos)
if(distSquat<minDistance){
minDistance = distSquat
//请在这里计算local点在模型的正面还是反面
let normal = triangle.getNormal(new Vector3())
let toPoint = local.clone().sub(clostLocPos)
isOutside = Math.sign(normal.dot(toPoint))
}
}
}
//内外
})
data.push(minDistance * isOutside) //isOutside区分正反面
curIdx++
let process = curIdx/(data32Size.x*data32Size.y*data32Size.z)
console.log(process,isOutside)
if(curIdx%500===0){
console.clear()
}
}
}
}
let texture = new Data3DTexture(
new Float32Array(data),
data32Size.x,
data32Size.y,
data32Size.z
);
texture.format = RedFormat;
texture.type = FloatType;
texture.minFilter = texture.magFilter = LinearFilter;
texture.unpackAlignment = 1;
texture.needsUpdate = true;
this.sdfDebug.uniforms.sdfTexture.value = texture
console.log(texture)
return texture
}
this is my shader:
this.sdfDebug = new ShaderPass({
uniforms:{
tDiffuse:{value:null},
sdfTexture:{value:null},
wPosTexture:{value:null},
totalSize:{value:null},
bbox: {
value: null,
},
cameraPos:{value:null},
},
vertexShader:`
varying vec2 vUv;
void main(){
vUv = uv;
vec4 mv = modelViewMatrix*vec4(position,1.);
gl_Position = projectionMatrix*mv;
}
`,
fragmentShader:`
#include <packing>
precision highp float;
precision highp sampler3D;
precision highp int;
varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform sampler3D sdfTexture;
uniform sampler2D wPosTexture;
uniform vec3 totalSize;
uniform vec3[2] bbox;
uniform vec3 cameraPos;
vec2 sampleSDF(vec3 uv3){
vec3 uvSpatial = (uv3 - bbox[0]) / (bbox[1] - bbox[0]);
// 检查 uvSpatial 的每个分量是否在 [0, 1] 范围内
bool outOfBounds = any(lessThan(uvSpatial, vec3(0.))) || any(greaterThan(uvSpatial, vec3(1.)));
// 如果超出范围,y 分量赋值为 1,否则为 0
float outOfBoundsFlag = outOfBounds ? 1.0 : 0.0;
return vec2(texture(sdfTexture, uvSpatial).r,outOfBoundsFlag);
}
float isInShadow(vec3 fragPos, vec3 lightDir) {
float res = 1.;
float t = 0.01;
float k = 8.;
for( int i=0; i<256 ; i++ )
{
vec2 rs = sampleSDF(fragPos+lightDir*t);
float h = rs.x;
if(rs.y==1.){
break;
}
if( h<0.001 )
return 0.0;
res = min( res, k*h/t );
t += h;
}
return res;
}
void main() {
vec3 lightPos = vec3(-5., 5., 5.);
vec3 color = texture(tDiffuse, vUv).rgb;
vec4 base = texture(wPosTexture, vUv);
vec3 dirToLi = normalize(lightPos);
float _0isShadow = isInShadow(base.xyz, dirToLi);
gl_FragColor = vec4(vec3(color * _0isShadow), 1.);
}
`
})
this.mainComposer.addPass(this.sdfDebug)