Hi All, I’m trying to render an FBX model that has a texture, but my texture doesn’t seem to be mapping to the model properly:
I tried some different blending and texture wrapping options, but haven’t figured out how to get the windows to display properly yet. If anyone has any ideas on how to diagnose and resolve this kind of issue, I’d be grateful for their input!
When debugging texture coordinates in general, I find it helpful to visualize the uv data with a special debugging texture. Stuff like wrong uv data or discontinuities can easily be discovered at one glance.
Demo: Edit fiddle - JSFiddle - Code Playground
1 Like
You have some yellow triangle dublicates slightly in front of the windows, you see it when moving the camera on it.

Also notice some flipped dublicates inside of the taxi.
2 Likes
This is clever! I have a quick follow up–I wrapped my little car with this uv texture, but I can’t quite tell what coordinates are being plotted as the upper triangle on the windshield:
Is there a clever way to figure that out? I feel like GPU picking is the right way to solve this, but that’s a bit of work to set up. If there’s something simple it’d be great to read about it!
Interesting, what is a dublicate @Fyrestar?
There are simply triangles covering your actual windows. The dublicates inside are basically the exact triangles 2 times at the same spot, while the second is flipped so it is only visible when viewed backside.
1 Like
Aha! Did you use something like Blender to investigate the vertices? Or just scour for duplicate vertices in three.js?
I’ve just moved the camera inside the taxi to inspect, in your codepen 
But i would use the modelling tool like Blender or C4D yes.
1 Like
@Fyrestar just so I understand, if I climb inside the mesh and can see rendered textures in there (like below, which is looking at the back left of the car), does that mean that I have duplicated vertices and a texture that’s facing into the center of the car?
Yes, by default backface culling is enabled that means triangles are rendered only from the front, it’s defined by the order of the face indices being clockwise. If backface culling isn’t enabled in the tool that doesn’t mean there will be dublicated triangles, they just render both sides but for some reason in your model they are dublicated. If you see a hole from the outside, but the triangle from the inside, it is just 1 triangle being flipped.
If it doesn’t appear wrong in your modelling tool you’d need to investigate from the tool, there might be procedural operations which aren’t backed into the geometry and backed wrong on export, but it’s just a wild guess. Anyway you can just delete the unwanted faces in Blender.
1 Like
Hallo everyone I found an example using a script that generates images of the uv maps.
I moddiefied it, so that also applies the uv map back to the model, for easier refference
js fiddle
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js - UV mapping tests</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background: #ffffff;
color: #000000;
text-align: center;
font-family: sans-serif;
}
h3 {
margin-top: 60px;
margin-bottom: 30px;
font-weight: normal;
}
canvas {
width: 80vw;
}
</style>
</head>
<body> <script type="importmap">{
"imports": {
"three": "https://threejs.org/build/three.module.js"
}
}</script>
<script type="module">
import * as THREE from "three";
const geometry = new THREE.ConeGeometry(50, 100, 8); // define the geo you want to inspect here
import { OrbitControls } from "https://sbedit.net/jsm/controls/OrbitControls.js";
import { UVsDebug } from 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/jsm/utils/UVsDebug.js';
/*
* This is to help debug UVs problems in geometry,
* as well as allow a new user to visualize what UVs are about.
*/
function test(name, geometry) {
const d = document.createElement('div');
d.innerHTML = '<h3>' + name + '</h3>';
d.appendChild(UVsDebug(geometry));
document.body.appendChild(d);
}
const points = [];
for (let i = 0; i < 10; i++) {
points.push(new THREE.Vector2(Math.sin(i * 0.2) * 15 + 50, (i - 5) * 2));
}
// Debug UVs for a cone geometry
test(' THREE.ConeGeometry', geometry);
// Create the scene, camera, and renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth*0.9, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Add OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.screenSpacePanning = true;
//controls.maxPolarAngle = Math.PI / 2;
// Load a texture
const ctx = document.getElementsByTagName('canvas')[0].getContext('2d');
const texture = new THREE.CanvasTexture(ctx.canvas);
// Create a cone geometry and apply the texture
const material = new THREE.MeshBasicMaterial({ map: texture });
const cone = new THREE.Mesh(geometry, material);
scene.add(cone);
// Initial camera position
camera.position.z = 200;
// Animation loop
function animate() {
requestAnimationFrame(animate);
renderer.setSize(window.innerWidth*0.8, window.innerWidth*0.8);
// cone.rotation.x += 0.005;
// cone.rotation.y += 0.01;
controls.update(); // Only required if controls.enableDamping = true, or if controls.autoRotate = true
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>