如何将Three.js渲染的Canvas背景设置为透明?
问题:Three.js Canvas背景无法设置为透明
我已经尝试在JS中设置setClearColor,也在CSS中设置Canvas的透明属性,但Canvas背景仍为黑色,希望将其改为透明。

HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <link rel="stylesheet" href="/src/index.css" /> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@v0.150.1/build/three.module.js", "three/addons/": "https://unpkg.com/three@v0.150.1/examples/jsm/" } } </script> <meta name="description" content="Web site created using create-react-app" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <title>EXAMPLE</title> </head> <body> <div id="root"></div> <div class="globe-render" id="globe-render"> <script type="module" src="./globe.js"></script> </div> </body> </html>
CSS代码
@tailwind base; @tailwind components; @tailwind utilities; body { background-color: #000f14; margin: 0; position: relative; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } #globe-render { position: absolute; top: -20%; left: 20%; background-color: rgb(255, 255, 255); } #myCanvas { position: absolute; background-color: green; }
JS代码
import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js"; import { RenderPass } from "three/addons/postprocessing/RenderPass.js"; import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js"; //Radius define let ParticleSurfaceLayer = 7.5; let GlobeRadius = 6.6; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); const renderer = new THREE.WebGLRenderer({ alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); const container = document.querySelector(".globe-render"); renderer.setClearColor(0x000000,0); container.appendChild(renderer.domElement); // Group for globe and particle system const group = new THREE.Group(); scene.add(group); // Bloom pass for the globe const renderScene = new RenderPass(scene, camera); const globeBloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85 ); globeBloomPass.threshold = 0; globeBloomPass.strength = 2; globeBloomPass.radius = 0; const globeComposer = new EffectComposer(renderer); globeComposer.setSize(window.innerWidth, window.innerHeight); globeComposer.addPass(renderScene); globeComposer.addPass(globeBloomPass); // Bloom pass for particles const particleComposer = new EffectComposer(renderer); particleComposer.setSize(window.innerWidth, window.innerHeight); particleComposer.addPass(new RenderPass(group, camera)); // Assuming 'group' contains particles const particleBloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85 ); particleBloomPass.threshold = 0; particleBloomPass.strength = 1.3; particleBloomPass.radius = 0.8; particleComposer.addPass(particleBloomPass); // Update size function function updateSize() { const newWidth = window.innerWidth; const newHeight = window.innerHeight; camera.aspect = newWidth / newHeight; camera.updateProjectionMatrix(); renderer.setSize(newWidth, newHeight); const sphereRadius = Math.min(newWidth, newHeight) * 0.1; globe.geometry = new THREE.SphereGeometry(sphereRadius, 32, 32); const particleSizeMin = Math.min(newWidth, newHeight) * 0.001; const particleSizeMax = Math.min(newWidth, newHeight) * 0.004; group.children.forEach((particle) => { const randomSize = THREE.MathUtils.randFloat( particleSizeMin, particleSizeMax ); particle.scale.set(randomSize, randomSize, randomSize); }); // Update composer sizes globeComposer.setSize(newWidth, newHeight); particleComposer.setSize(newWidth, newHeight); } //orbit controls const controls = new OrbitControls(camera, renderer.domElement); const loader = new THREE.TextureLoader(); controls.enableZoom = false; // controls.enabled=false // Initial setup //////// const geometry = new THREE.SphereGeometry(GlobeRadius, 80, 80); const material1 = new THREE.MeshBasicMaterial({ map: loader.load("./8k_earth_nightmap_underlayer.jpg"), //transparent: true, opacity: 1, }); const material2 = new THREE.MeshBasicMaterial({ color: 0xff047e, transparent: true, opacity: 0.1, }); const multimaterial = [material1, material2]; const globe = new THREE.Mesh(geometry, material1); globe.layers.set(1); group.add(globe); // Particle System const particleCount = 600; const color = new THREE.Color("#fc2414"); for (let i = 0; i < particleCount; i++) { // ... (same as your code) const phi = Math.random() * Math.PI * 2; const theta = Math.random() * Math.PI - Math.PI / 2; const randomradius = 0.01 + Math.random() * 0.04; const radius = ParticleSurfaceLayer; // Radius of the sphere const x = radius * Math.cos(theta) * Math.cos(phi); const y = radius * Math.cos(theta) * Math.sin(phi); const z = radius * Math.sin(theta); const particleGeometry = new THREE.SphereGeometry(randomradius, 30, 25); // Initial size const particleMaterial = new THREE.MeshBasicMaterial({ color: "#00FFFF", }); const particle = new THREE.Mesh(particleGeometry, particleMaterial); particle.position.set(x, y, z); particle.layers.set(1); group.add(particle); } const ambientLight = new THREE.AmbientLight(0xffffff, 100); scene.add(ambientLight); // Camera position camera.position.z = 15; // Rotation animation const rotationSpeed = 0.001; // Animation function const animate = function () { requestAnimationFrame(animate); group.rotation.y += rotationSpeed; // Render globe with bloom effect camera.layers.set(1); globeComposer.render(); // Render particles with bloom effect particleComposer.render(); }; ///////orbit controls///* let isDragging = false; let originalRotation = group.rotation.y; // Event listener for mouse down renderer.domElement.addEventListener("mousedown", () => { isDragging = true; }); // Event listener for mouse up renderer.domElement.addEventListener("mouseup", () => { isDragging = false; // Reset the rotation to its original position group.rotation.y = originalRotation; }); // Event listener for mouse leave (in case mouse leaves the canvas while dragging) renderer.domElement.addEventListener("mouseleave", () => { if (isDragging) { isDragging = false; // Reset the rotation to its original position group.rotation.y = originalRotation; } }); // Handle window resize window.addEventListener("resize", updateSize); // Start animation animate(); const canvas = document.querySelector("canvas"); canvas.id = "myCanvas"; canvas.classList.add("myCanvasClass");
解决方案
问题出在你使用了两个EffectComposer进行渲染,默认情况下EffectComposer会创建不透明的渲染目标,覆盖了你设置的透明背景。需要给每个EffectComposer配置支持透明的渲染目标,并调整渲染逻辑。
修改步骤:
为每个Composer配置透明渲染目标
创建EffectComposer时,传入自定义的WebGLRenderTarget,开启alpha通道:// 替换 globeComposer 创建代码 const globeRenderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, { format: THREE.RGBAFormat, alpha: true }); const globeComposer = new EffectComposer(renderer, globeRenderTarget); // 替换 particleComposer 创建代码 const particleRenderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, { format: THREE.RGBAFormat, alpha: true }); const particleComposer = new EffectComposer(renderer, particleRenderTarget);调整渲染时的缓冲区清除逻辑
修改animate函数,确保渲染时保留透明通道,避免第二个Composer覆盖背景:const animate = function () { requestAnimationFrame(animate); group.rotation.y += rotationSpeed; // 渲染前清除颜色和深度缓冲区,保留透明 renderer.setClearColor(0x000000, 0); renderer.clear(); camera.layers.set(1); globeComposer.render(); // 渲染粒子时只清除深度缓冲区,保留已有透明内容 renderer.clearDepth(); particleComposer.render(); };移除CSS中遮挡透明的背景色
删除或注释掉以下CSS规则:#globe-render { /* background-color: rgb(255, 255, 255); */ } #myCanvas { /* background-color: green; */ }
完成以上修改后,Canvas背景会变为透明,你可以看到页面的#000f14背景色。
内容的提问来源于stack exchange,提问作者B ANURAG
相关产品推荐
相关产品推荐

