使用Babylon JS通过DynamicTexture在球体上绘制圆形出现椭圆变形问题
Hey Carlos, I’ve run into this exact issue before with Babylon.js’s DynamicTexture on spheres—here’s a quick, straightforward fix to get your circle looking round again!
Why This Happens
The problem boils down to how UV mapping works on spheres. Unlike a flat plane, a sphere’s UV coordinates don’t map 1:1 to equal lengths across its surface. The horizontal (longitude) axis spans 360 degrees, while the vertical (latitude) axis only spans 180 degrees. This means the texture gets compressed vertically relative to horizontally when wrapped around the sphere—so a perfect circle drawn on the flat DynamicTexture turns into an ellipse once applied.
Simple Fix: Adjust Your Arc to Counteract UV Stretch
The easiest solution is to draw an intentional ellipse on the DynamicTexture that gets "corrected" into a circle when stretched by the sphere’s UVs. Here’s how to do it:
Example Code for Equator Circle
If you’re placing your circle around the sphere’s equator (the most common case), use a 2:1 aspect ratio for your arc’s vertical radius to offset the UV compression:
// Set up your sphere and DynamicTexture const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2 }, scene); const textureSize = 512; const dynamicTexture = new BABYLON.DynamicTexture("circleTex", { width: textureSize, height: textureSize }, scene); const ctx = dynamicTexture.getContext(); // Counteract sphere UV stretch: longitude (360°) vs latitude (180°) = 2:1 ratio const uvCorrectionRatio = 2; // Draw an ellipse that becomes a circle on the sphere ctx.beginPath(); // arc(x, y, radiusX, radiusY, startAngle, endAngle) ctx.arc( textureSize / 2, // Center X textureSize / 2, // Center Y 100, // Horizontal radius (matches desired circle size) 100 * uvCorrectionRatio, // Vertical radius (stretched to counter UV compression) 0, Math.PI * 2 ); ctx.strokeStyle = "#ff0000"; ctx.lineWidth = 4; ctx.stroke(); // Update texture and apply to sphere dynamicTexture.update(); const mat = new BABYLON.StandardMaterial("sphereMat", scene); mat.diffuseTexture = dynamicTexture; sphere.material = mat;
For Circles Near Poles
If you need to draw a circle closer to the poles, the UV stretch changes with latitude. Use the cosine of the latitude angle (in radians) to calculate the correct correction ratio:
// Theta = latitude in radians (0 = equator, Math.PI/2 = north pole) const theta = Math.PI / 4; // 45° north latitude // Local stretch ratio: inverse of the parallel circumference at this latitude const uvCorrectionRatio = 1 / Math.cos(theta); // Use this ratio in your arc call just like the equator example ctx.arc(textureSize/2, textureSize/2, 100, 100 * uvCorrectionRatio, 0, Math.PI*2);
How This Works
At any given latitude, the circumference of the sphere’s parallel (the circle around the sphere at that latitude) is smaller than the equator’s circumference by a factor of cos(theta). By stretching the vertical radius of our drawn ellipse by the inverse of that factor, we cancel out the UV compression, resulting in a perfect circle on the sphere’s surface.
内容的提问来源于stack exchange,提问作者Carlos Mendieta

