javascript
// GPU vs CPU
// CPU: 少量强大核心,适合复杂逻辑
// GPU: 大量简单核心,适合并行计算
算术运算 > 纹理采样
局部计算 > 分支预测
连续访问 > 随机访问
glsl
// ❌ 低效 - 多次除法
float result = (a / b) / c;
// ✅ 高效 - 预计算倒数
float invBC = 1.0 / (b * c);
float result = a * invBC;
// ❌ 低效 - 多次pow
float value = pow(x, 2.0) + pow(y, 2.0);
// ✅ 高效 - 使用乘法
float value = x * x + y * y;
glsl
// ❌ 低效 - 动态分支
float calculateLight(vec3 normal, vec3 lightDir) {
float dotProduct = dot(normal, lightDir);
if (dotProduct > 0.0) {
return dotProduct;
} else {
return 0.0;
}
}
// ✅ 高效 - 使用max/min/clamp
float calculateLight(vec3 normal, vec3 lightDir) {
return max(dot(normal, lightDir), 0.0);
}
// ✅ 高效 - 使用step/smoothstep
float calculateLight(vec3 normal, vec3 lightDir) {
float dotProduct = dot(normal, lightDir);
return dotProduct * step(0.0, dotProduct);
}
// ✅ 高效 - 使用mix代替分支
vec4 getColor(float condition) {
// 代替:if (condition > 0.5) return color1; else return color2;
float factor = step(0.5, condition);
return mix(color2, color1, factor);
}
glsl
// ❌ 低效 - 动态循环次数
for (int i = 0; i < int(iterations); i++) {
// ...
}
// ✅ 高效 - 编译时常量循环
#define MAX_ITERATIONS 10
for (int i = 0; i < MAX_ITERATIONS; i++) {
// 展开循环(编译器会自动展开小循环)
}
// ✅ 高效 - 循环展开(手动)
vec4 color = vec4(0.0);
color += sampleTexture(uv + offsets[0]) * weights[0];
color += sampleTexture(uv + offsets[1]) * weights[1];
color += sampleTexture(uv + offsets[2]) * weights[2];
// ... 而不是循环
glsl
// 内置函数通常经过高度优化
// ✅ 使用内置函数
float distance = length(vec);
float clamped = clamp(value, 0.0, 1.0);
float lerped = mix(a, b, t);
float stepped = step(edge, x);
glsl
// 根据需求选择合适精度
precision highp float; // 32位,高精度
precision mediump float; // 16位,中等精度(默认)
precision lowp float; // 10位,低精度
// 局部变量可以使用更低的精度
mediump vec2 uv;
lowp vec3 color; // 对于颜色计算,低精度通常足够
// 位置计算需要高精度
highp vec4 position;
glsl
// ❌ 低效 - 多次采样相同纹理
float r = texture2D(map, uv + vec2(offset, 0.0)).r;
float g = texture2D(map, uv + vec2(0.0, offset)).g;
float b = texture2D(map, uv - vec2(offset, 0.0)).b;
// ✅ 高效 - 一次采样,多次使用
vec4 texel = texture2D(map, uv);
float r = texel.r;
float g = texel.g;
float b = texel.b;
// ✅ 高效 - 使用mipmaps
// 确保纹理启用mipmaps
texture.minFilter = THREE.LinearMipMapLinearFilter;
// 在着色器中自动使用LOD
vec4 color = texture2DLodEXT(texture, uv, mipLevel);
glsl
// ❌ 低效 - 随机访问(缓存不友好)
float value = 0.0;
for (int i = 0; i < 100; i++) {
vec2 randomUV = uv + vec2(randomOffset(i), randomOffset(i));
value += texture2D(noiseTex, randomUV).r;
}
// ✅ 高效 - 空间连续性访问
for (int x = -2; x <= 2; x++) {
for (int y = -2; y <= 2; y++) {
vec2 sampleUV = uv + vec2(x, y) * pixelSize;
value += texture2D(tex, sampleUV).r;
}
}
javascript
// 将多个小纹理打包成大纹理
const atlasTexture = new THREE.TextureLoader().load('atlas.png');
const material = new THREE.ShaderMaterial({
uniforms: {
atlas: { value: atlasTexture },
uvOffset: { value: new THREE.Vector2(0, 0) },
uvScale: { value: new THREE.Vector2(0.25, 0.25) }
},
// ...
});
glsl
// 在着色器中
uniform sampler2D atlas;
uniform vec2 uvOffset;
uniform vec2 uvScale;
vec2 atlasUV = uv * uvScale + uvOffset;
vec4 color = texture2D(atlas, atlasUV);
javascript
// ❌ 低效 - 单独更新
uniforms.time.value = clock.getElapsedTime();
uniforms.lightPos.value = light.position;
// ✅ 高效 - 批量更新
const batchUpdates = () => {
material.uniforms.time.value = clock.getElapsedTime();
material.uniforms.lightPos.value = light.position;
// 所有uniforms一起更新
material.uniformsNeedUpdate = true;
};
// ✅ 高效 - 使用UniformsUtils
const commonUniforms = {
time: { value: 0 },
resolution: { value: new THREE.Vector2() }
};
const material1 = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.merge([
commonUniforms,
{ color: { value: new THREE.Color(0xff0000) } }
]),
// ...
});
javascript
// 只在必要时更新
let lastCameraPosition = new THREE.Vector3();
let lastTime = 0;
function updateUniforms() {
const now = performance.now();
// 每帧必须更新的
material.uniforms.time.value = now * 0.001;
// 只有变化时才更新
if (!camera.position.equals(lastCameraPosition)) {
material.uniforms.cameraPos.value.copy(camera.position);
lastCameraPosition.copy(camera.position);
}
// 低频更新(例如每秒更新)
if (now - lastTime > 1000) {
material.uniforms.lightIntensity.value = calculateLightIntensity();
lastTime = now;
}
}
glsl
// ❌ 低效 - 在顶点着色器中进行复杂计算
attribute vec3 extraData;
varying float complexValue;
void main() {
// 复杂计算
complexValue = sin(extraData.x) * cos(extraData.y) * tan(extraData.z);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
// ✅ 高效 - 在片元着色器中进行复杂计算
// 或者在CPU中预计算
javascript
// 实例化渲染大量相同几何体
const geometry = new THREE.InstancedBufferGeometry();
geometry.copy(baseGeometry);
// 添加实例化属性
const offsets = new Float32Array(count * 3);
const colors = new Float32Array(count * 3);
geometry.setAttribute('offset', new THREE.InstancedBufferAttribute(offsets, 3));
geometry.setAttribute('color', new THREE.InstancedBufferAttribute(colors, 3));
// 着色器中使用
const vertexShader = `
attribute vec3 offset;
attribute vec3 color;
varying vec3 vColor;
void main() {
vColor = color;
vec3 pos = position + offset;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`;
javascript
// 对后处理效果使用半分辨率
const composer = new THREE.EffectComposer(renderer, {
multisampling: 4,
frameBufferType: THREE.HalfFloatType
});
// 降低渲染目标分辨率
const renderTarget = new THREE.WebGLRenderTarget(
window.innerWidth * 0.5, // 半宽
window.innerHeight * 0.5, // 半高
{
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
type: THREE.HalfFloatType
}
);
javascript
// 合并多个后处理效果
class CombinedShader {
constructor() {
this.uniforms = {
tDiffuse: { value: null },
bloomStrength: { value: 1.0 },
vignetteAmount: { value: 0.5 }
};
this.fragmentShader = `
uniform sampler2D tDiffuse;
uniform float bloomStrength;
uniform float vignetteAmount;
// 合并多个效果到一个shader中
void main() {
vec4 color = texture2D(tDiffuse, vUv);
// 绽放效果
vec4 bloom = getBloom(color);
// 晕影效果
float vignette = getVignette(vUv);
// 颜色校正
vec4 corrected = colorCorrection(color);
// 合并
gl_FragColor = mix(corrected, bloom, bloomStrength) * vignette;
}
`;
}
}
javascript
// 检查着色器编译状态
material.onCompile = (shader) => {
console.log('Shader info:', {
program: shader.program,
uniforms: Object.keys(shader.uniforms),
attributes: Object.keys(shader.attributes)
});
};
// 使用Three.js的ShaderChunk进行调试
const customShader = THREE.ShaderLib.standard;
customShader.fragmentShader = customShader.fragmentShader.replace(
'#include <output_fragment>',
`
#include <output_fragment>
// 添加调试信息
#ifdef DEBUG_PERFORMANCE
gl_FragColor.r += 0.1; // 标记此shader
#endif
`
);
javascript
class ShaderPerformance {
constructor(material) {
this.frameCount = 0;
this.totalTime = 0;
this.startTime = 0;
// 替换原始着色器
this.originalVertexShader = material.vertexShader;
this.originalFragmentShader = material.fragmentShader;
// 添加性能计数代码
material.vertexShader = this.instrumentShader(this.originalVertexShader, 'vertex');
material.fragmentShader = this.instrumentShader(this.originalFragmentShader, 'fragment');
}
instrumentShader(source, type) {
return `
#define SHADER_PERF_${type.toUpperCase()}
${source}
#ifdef SHADER_PERF_VERTEX
uniform float uPerfTime;
#endif
`;
}
}
glsl
// 使用mediump作为默认精度
precision mediump float;
// 避免使用高精度计算
mediump float distance = length(vec);
// 减少纹理采样次数
#if defined(GL_FRAGMENT_PRECISION_HIGH)
// 高性能设备
#define SAMPLE_COUNT 16
#else
// 低性能设备
#define SAMPLE_COUNT 8
#endif
// 根据设备性能动态调整
uniform float quality;
float adjustedQuality = quality * devicePixelRatio;
javascript
// 检测设备性能并调整着色器
function adaptShaderForDevice() {
const isMobile = /Mobi|Android/i.test(navigator.userAgent);
const isLowEnd = navigator.hardwareConcurrency <= 4;
if (isMobile || isLowEnd) {
// 使用简化版着色器
material.fragmentShader = simplifiedFragmentShader;
material.defines['LOW_QUALITY'] = 1;
material.precision = 'mediump';
} else {
// 使用完整版着色器
material.fragmentShader = fullFragmentShader;
material.precision = 'highp';
}
}
javascript
class ShaderCache {
constructor() {
this.cache = new Map();
}
getShader(key, createShader) {
if (this.cache.has(key)) {
return this.cache.get(key);
}
const shader = createShader();
this.cache.set(key, shader);
return shader;
}
}
// 使用
const cache = new ShaderCache();
const material = cache.getShader('wave-effect', () => {
return new THREE.ShaderMaterial({
vertexShader: waveVertexShader,
fragmentShader: waveFragmentShader,
uniforms: waveUniforms
});
});
javascript
// 在场景加载时预编译着色器
function precompileShaders() {
const dummyScene = new THREE.Scene();
const dummyCamera = new THREE.Camera();
const dummyRenderer = new THREE.WebGLRenderer();
const shaders = [
{ material: waterMaterial, mesh: waterMesh },
{ material: fireMaterial, mesh: fireMesh },
// ...
];
shaders.forEach(({ material, mesh }) => {
dummyScene.add(mesh);
dummyRenderer.render(dummyScene, dummyCamera);
dummyScene.remove(mesh);
});
}
ShaderToy to Three.js转换器:在线转换工具
Spector.js:WebGL调试器
WebGL Inspector:Chrome扩展
RenderDoc:图形调试工具
Three.js Shader Editor扩展:VSCode插件
记住:先实现功能,再优化性能,最后验证结果。使用性能分析工具找到真正的瓶颈,避免过早优化。