# I tried to generate SDF in Three.js and use it to calculate shadows, but it looks ugly! help!

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){
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++) {
currentPos.set(x,y,z).multiply(step)
//找出包含这个位置的所有obj，找出最接近的面，需要把坐标用临时变量转到对应空间
let minDistance = maxBorder
let isOutside = 1
this.objList.forEach((obj:any)=>{
// let sphereCenter = obj.getWorldPosition(new Vector3())
// let distanceOfsToSphCenter = offset.distanceTo(sphereCenter)
//     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.sdfDebug = new ShaderPass({
uniforms:{
tDiffuse:{value:null},
sdfTexture:{value:null},
wPosTexture:{value:null},
totalSize:{value:null},
bbox: {
value: null,
},
cameraPos:{value:null},
},
varying vec2 vUv;
void main(){
vUv = uv;
vec4 mv = modelViewMatrix*vec4(position,1.);
gl_Position = projectionMatrix*mv;
}
`,
#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);
gl_FragColor = vec4(vec3(color * _0isShadow), 1.);
}
`
})
However, looking at how you calculate `isOutside`, something confuses me. In the following image of a torus, point P is inside the torus in respect to the blue face, but it is outside the torus in respect to the red face.
As a result, `data.push(minDistance * isOutside)` might push the correct or the wrong value, depending on which face is processed last.