效果如下所示
说明
仿照 光辉城市 软件中材质修改面板选中模型的效果,基于视觉空间,不受模型本身大小旋转的影。代码包含两个函数(一个选中替换shader,一个取消选中还原shader)
代码如下
/**
* 取消选中mesh
*/
cancleSelect() {
if (this.selectMat) {
// 去掉材质的选中效果(阵列黑点)
this.selectMat.onBeforeCompile = (shader) => {
// 去掉自定义uniforms
if (shader.uniforms.uResolution) delete shader.uniforms.uResolution;
if (shader.uniforms.uSpacing) delete shader.uniforms.uSpacing;
if (shader.uniforms.uRadius) delete shader.uniforms.uRadius;
// 在着色器中去掉uniform声明
shader.fragmentShader = shader.fragmentShader.replace(
this.argunmentChunk,
"#include <common>"
);
// 替换片元着色器中的dithering部分,去掉黑点逻辑
shader.fragmentShader = shader.fragmentShader.replace(
this.fragmentChunk,
"#include <dithering_fragment>"
);
};
this.selectMat.needsUpdate = true;
}
this.selectMat = null;
}
/**
* 选中mesh
* @param {*} mat
* @returns
*/
selectMat(mat) {
// 选中同一个材质就取消
if (mat && this.selectMat && this.selectMat === mat) {
this.cancleSelect();
return;
}
this.cancleSelect();
if (!mat) return;
this.selectMat = mat;
if (!this.argunmentChunk) {
this.argunmentChunk = `
#include <common>
uniform vec2 uResolution;
uniform float uSpacing;
uniform float uRadius;
`;
}
if (!this.fragmentChunk) {
this.fragmentChunk = `
#include <dithering_fragment>
// 替换原片元着色器中的黑点生成逻辑
vec2 uv = gl_FragCoord.xy / uResolution;
// 1. 坐标系修正:将Y轴翻转(适配左上角原点)
uv.y = 1.0 - uv.y;
// 2. 宽高比补偿(保持正圆)
float aspect = uResolution.x / uResolution.y;
uv.x *= aspect;
// 3. 网格映射(强制正方形单元格)
float spacing = uSpacing;
vec2 gridPos = uv * (1.0 / spacing);
vec2 cell = fract(gridPos);
// 4. 圆形计算(反向补偿宽高比)
vec2 offset = cell - vec2(0.5);
//offset.x /= aspect; // 关键修正点
float dist = length(offset);
// 5. 抗锯齿 + 颜色混合(保留原材质)
float smoothEdge = fwidth(dist) * 2.0; // 自动边缘平滑
float mask = smoothstep(uRadius + smoothEdge, uRadius - smoothEdge, dist);
gl_FragColor = mix(gl_FragColor, vec4(0.0, 0.0, 0.0, 1.0), mask);
`;
}
// 给材质添加选中效果(阵列黑点)
mat.onBeforeCompile = (shader) => {
// 添加自定义uniforms
shader.uniforms.uResolution = {
value: new Vector2(window.innerWidth, window.innerHeight),
};
shader.uniforms.uSpacing = { value: 0.04 };
shader.uniforms.uRadius = { value: 0.07 };
// 在着色器中插入uniform声明
shader.fragmentShader = shader.fragmentShader.replace(
"#include <common>",
this.argunmentChunk
);
// 替换片元着色器中的dithering部分,添加黑点逻辑
shader.fragmentShader = shader.fragmentShader.replace(
"#include <dithering_fragment>",
this.fragmentChunk
);
};
mat.needsUpdate = true;
}