2013-12-25 4 views
23

Я работаю над импортом модели в сцену с помощью загрузчика THREE.js OBJ.THREE.js генерирует координату UV

Я знаю, что я могу импортировать геометрию в порядке, потому что, когда я назначаю ему MeshNormalMaterial, она отображается отлично. Однако, если я использую все, что требует UV координат, он дает мне ошибку:

[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 1 

Я знаю это потому, что загруженный OBJ не имеет UV координат, но мне было интересно, есть ли способ произвести необходимые текстурные координаты. Я пробовал

material.needsUpdate = true; 
geometry.uvsNeedUpdate = true; 
geometry.buffersNeedUpdate = true; 

... но не напрасно.

Есть ли способ автоматически генерировать УФ-текстуры с использованием three.js, или мне нужно самим назначить координаты?

ответ

35

Насколько я знаю, нет автоматического способа вычисления УФ-излучения.

Вы должны высчитать сумму. Рассчитать УФ для самолета довольно просто, этот сайт объясняет, как: calculating texture coordinates

Для сложной формы я не знаю как. Возможно, вы можете обнаружить плоскую поверхность.

EDIT

Вот пример кода для плоской поверхности (x, y, z) где z = 0:

geometry.computeBoundingBox(); 

var max = geometry.boundingBox.max, 
    min = geometry.boundingBox.min; 
var offset = new THREE.Vector2(0 - min.x, 0 - min.y); 
var range = new THREE.Vector2(max.x - min.x, max.y - min.y); 
var faces = geometry.faces; 

geometry.faceVertexUvs[0] = []; 

for (var i = 0; i < faces.length ; i++) { 

    var v1 = geometry.vertices[faces[i].a], 
     v2 = geometry.vertices[faces[i].b], 
     v3 = geometry.vertices[faces[i].c]; 

    geometry.faceVertexUvs[0].push([ 
     new THREE.Vector2((v1.x + offset.x)/range.x ,(v1.y + offset.y)/range.y), 
     new THREE.Vector2((v2.x + offset.x)/range.x ,(v2.y + offset.y)/range.y), 
     new THREE.Vector2((v3.x + offset.x)/range.x ,(v3.y + offset.y)/range.y) 
    ]); 
} 
geometry.uvsNeedUpdate = true; 
+4

Чтобы помочь тем, которые могли бы искать несуществующее решение ... для «сложной», неправильной формы единственного (нормальный) путь - использовать 3D-программное обеспечение, такое как Blender, вручную разместить текстуру на модели и экспортировать файл. – taseenb

12

Другие ответы здесь были большим подспорьем, но не вполне соответствует моим требованиям к применить повторяя узорную текстуру со всех сторон формы с преимущественно плоскими поверхностями. Проблема заключается в том, что использование только х и у компонентов как и и v приводит к странным растянутым текстурам на вертикальных поверхностях.

Мое решение ниже использует нормали поверхности, чтобы выбрать, какие две компоненты (x, y и z) должны отображаться на u и v. Это все еще довольно грубо, но работает очень хорошо.

function assignUVs(geometry) { 

    geometry.faceVertexUvs[0] = []; 

    geometry.faces.forEach(function(face) { 

     var components = ['x', 'y', 'z'].sort(function(a, b) { 
      return Math.abs(face.normal[a]) > Math.abs(face.normal[b]); 
     }); 

     var v1 = geometry.vertices[face.a]; 
     var v2 = geometry.vertices[face.b]; 
     var v3 = geometry.vertices[face.c]; 

     geometry.faceVertexUvs[0].push([ 
      new THREE.Vector2(v1[components[0]], v1[components[1]]), 
      new THREE.Vector2(v2[components[0]], v2[components[1]]), 
      new THREE.Vector2(v3[components[0]], v3[components[1]]) 
     ]); 

    }); 

    geometry.uvsNeedUpdate = true; 
} 

Эта функция не нормализует УФ по размеру объекта. Это работает лучше при применении той же текстуры к объектам разного размера в одной и той же сцене. Однако, в зависимости от размера вашей мировой системы координат, вам, вероятно, нужно масштабировать и повторять текстуру, а также:

texture.repeat.set(0.1, 0.1); 
texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping; 
+0

Это было именно то, что мне нужно. Благодаря! – OpherV

+0

Вау, спасибо за это! Потребовал бы меня, чтобы понять это правильно. – Arg0n

3

Ответы здесь великолепны и мне очень помогли. только одна вещь: Если вы обновляете вершины, не переназначить Увс, но установить их, как и в (сфера моя геометрия):

scope.updateUVs = (copy=true) => { 

    scope.computeBoundingBox(); 

    var max  = scope.boundingBox.max; 
    var min  = scope.boundingBox.min; 

    var offset = new THREE.Vector2(0 - min.x, 0 - min.y); 
    var range = new THREE.Vector2(max.x - min.x, max.y - min.y); 

    if (!copy) { 
     scope.faceVertexUvs[0] = []; 
    } 
    var faces = scope.faces; 

    for (i = 0; i < scope.faces.length ; i++) { 

     var v1 = scope.vertices[faces[i].a]; 
     var v2 = scope.vertices[faces[i].b]; 
     var v3 = scope.vertices[faces[i].c]; 

     var uv0 = new THREE.Vector2((v1.x + offset.x)/range.x , (v1.y + offset.y)/range.y); 
     var uv1 = new THREE.Vector2((v2.x + offset.x)/range.x , (v2.y + offset.y)/range.y); 
     var uv2 = new THREE.Vector2((v3.x + offset.x)/range.x , (v3.y + offset.y)/range.y); 

     if (copy) { 
      var uvs =scope.faceVertexUvs[0][i]; 
      uvs[0].copy(uv0); 
      uvs[1].copy(uv1); 
      uvs[2].copy(uv2); 
     } else { 
      scope.faceVertexUvs[0].push([uv0, uv1, uv2]); 
     } 
    } 

    scope.uvsNeedUpdate = true; 

} 
2

Это общая версия, которая работает для сферического отображения (рыскания , шаг координаты), смотрите пример here (смотрите на loadSuzanne функции):

function assignUVs(geometry) { 

    geometry.faceVertexUvs[0] = []; 

    geometry.faces.forEach(function(face) { 

     var uvs = []; 
     var ids = [ 'a', 'b', 'c']; 
     for(var i = 0; i < ids.length; i++) { 
      var vertex = geometry.vertices[ face[ ids[ i ] ] ].clone(); 

      var n = vertex.normalize(); 
      var yaw = .5 - Math.atan(n.z, - n.x)/(2.0 * Math.PI); 
      var pitch = .5 - Math.asin(n.y)/Math.PI; 

      var u = yaw, 
       v = pitch; 
      uvs.push(new THREE.Vector2(u, v)); 
     } 
     geometry.faceVertexUvs[ 0 ].push(uvs); 
    }); 

    geometry.uvsNeedUpdate = true; 
} 
+0

Я пробовал вышеупомянутое решение для геометрии сферы. Хотя это и дало некоторый результат, он работал неправильно. Поэтому я исправил его - вы можете увидеть его в действии здесь: http://codepen.io/knee-cola/pen/XMVBwQ –