物体相交描边
可以应用在:
WebGL2 : 064 : Impact Shield Effect
最终效果:
距离能量罩(盾牌)效果只差一步。
1、方案实现
思路:
- 首先得到相交物体的深度图。
- 根据自己的深度和刚才得到的深度进行差异比较。
- 最后放大差异即可。
2、其他方案
使用深度纹理: MeshDepthMaterial
,但是该方法对相机参数(far, near)要求较高,实现难度大。
检查相交的着色器:
const Shader = {
vert: `
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
frag: `
uniform vec2 dims;
uniform float zNear, zFar;
uniform sampler2D depthMap;
void main() {
vec4 solidsDepth = texture2D(depthMap, gl_FragCoord.xy / dims);
float solidsDiff = 1.0 - smoothstep(zNear, zFar, gl_FragCoord.z / gl_FragCoord.w) - solidsDepth;
float alpha = 0.3 + max(0.0, 1.0 - log(100.0 * (solidsDiff - 0.005) + 1.0));
gl_FragColor = vec4(vec3(1.0), alpha);
}
`,
}
var zNear = 1;
var zFar = 1000;
// 获取深度纹理的场景
var solidsScene = new THREE.Scene();
// 主场景
var mainScene = new THREE.Scene();
// ------------创建两个box----------------
const size = 150
var box1 = new THREE.Mesh(
new THREE.BoxGeometry(size, size, size),
new THREE.MeshBasicMaterial({map: crateTexture,color:0x00ff00})
)
box1.name = "box1"
mainScene.add(box1)
var box2 = new THREE.Mesh(
new THREE.BoxGeometry(size, size, size),
new THREE.MeshDepthMaterial()
)
box2.name = "box2"
solidsScene.add(box2)
// ------------创建深度纹理的渲染目标------------
var depthMap = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, {
minFilter: THREE.LinearFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBFormat
});
// ------------创建相交平面----------------------
var shield = new THREE.Mesh(new THREE.PlaneGeometry(400, 400), new THREE.ShaderMaterial({
transparent: true,
uniforms: {
depthMap: {
type: 't',
value: depthMap.texture
},
dims: {
type: 'v2',
value: new THREE.Vector2(window.innerWidth, window.innerHeight)
},
zNear: {
type: 'f',
value: zNear
},
zFar: {
type: 'f',
value: zFar
}
},
vertexShader: Shader.vert,
fragmentShader: Shader.frag
}));
shield.position.set(-5,-5,50)
mainScene.add(shield)
// ---------------主循环----------------
loop(() => {
const { renderer,scene,camera } = this.stage
renderer.setRenderTarget(depthMap)
renderer.render(solidsScene, camera);
renderer.setRenderTarget(null)
renderer.render(mainScene, camera);
})