问题
I loaded an object with OBJLoader. I want to use a Shader Material with a texture. I pass my texture to the uniforms parameters of the material. I pass the UV variable from the vertex shader to the fragment shader.
But when I use the uv coordinate for mapping my texture I get always 0,0 or at least this is what it looks like. The whole object is coloured with the bottom left pixel of the texture.
Here are my shaders:
<script type='x-shader/x-vertex' id='vertex-shader'>
uniform float u_time;
varying vec2 vUv;
void main() {
vUv = uv;
vec4 pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
gl_Position = pos;
}
</script>
<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;
uniform float u_time;
uniform vec2 u_resolution;
uniform sampler2D texture;
varying vec2 vUv;
void main(){
vec2 st = vUv;
vec4 tex = texture2D(texture, st);
gl_FragColor = tex;
}
</script>
And here is how I load the object and assign the material
var loader = new THREE.OBJLoader();
loader.load(
'assets/standing.obj',
function (object){
main.man = object;
main.man.position.set(0,-600,400);
main.texture = new THREE.TextureLoader().load( 'assets/na_00004c.jpg' );
main.texture_needsUpdate = true;
var uniforms = {
u_time:{type:'f', value:0.0},
u_mouse:{type:'v2', value: new THREE.Vector2()},
u_resolution: {type: 'v2', value: {x:2048.,y:1024.}},
texture: {type: 't', value: main.texture}
}
main.material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('vertex-shader').textContent,
fragmentShader: document.getElementById('fragment-shader').textContent,
transparent: true
});
main.material.needsUpdate = true;
main.material.side = THREE.DoubleSide;
main.man.traverse(function(child){
if(child instanceof THREE.Mesh){
child.material = main.material;
child.material.needsUpdate = true;
child.geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );
child.geometry.computeVertexNormals();
child.geometry.elementsNeedUpdate = true;
child.geometry.mergeVertices();
child.verticesNeedUpdate = true;
child.normalsNeedUpdate = true;
child.uvsNeedUpdate = true;
child.material.flatShading = THREE.SmoothShading;
}
});
main.scene.add(main.man);
},
function (xhr){
console.log((xhr.loaded/xhr.total*100)+'% loaded');
},
function (error){
console.log(error,'An error happened');
}
);
Here there is the full example http://cmt.re/dev/na/
This is the image that I want to use as a texture http://cmt.re/dev/na/assets/na_00004c.jpg
Does somebody know why this is happening?
Thanks a lot.
回答1:
Your code works fine, but your *.obj
file doesn't contain any texture coordinates. The Wavefront OBJ file (.obj file) is a text file, texture coordinates are the entries with the key vt
, if this entries are missing, the mesh doesn't have any texture coordinates.
Your code works fine, see the example, where I used your original code with a simple model:
var main = new function(){
this.init = function(){
this.initThree();
}
this.initThree = function(){
main.scene = new THREE.Scene();
main.scene.background = new THREE.Color(0xCCCCCC);
var aspectRatio = window.innerWidth / window.innerHeight;
main.camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 100000);
//main.camera.position.set(-40, 0, 512);
main.camera.position.set(1,2,0);
main.renderer = new THREE.WebGLRenderer({antialias: true});
main.renderer.setPixelRatio(window.devicePixelRatio);
main.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(main.renderer.domElement);
main.controls = new THREE.OrbitControls(main.camera);
main.controls.enableDamping = true;
main.controls.dampingFactor = 0.1;
main.controls.screenSpacePanning = false;
var helper = new THREE.GridHelper(2000, 100);
helper.material.opacity = 0.25;
helper.material.transparent = true;
main.scene.add(helper);
var axis = new THREE.AxesHelper();
main.scene.add(axis);
makeTextFile = function (text) {
var data = new Blob([text], {type: 'text/plain'});
var textFile = window.URL.createObjectURL(data);
return textFile;
}
var textbox_obj = document.getElementById('plane_obj');
var obj_url = makeTextFile(textbox_obj.value);
var loader = new THREE.OBJLoader();
loader.load(
obj_url,
function (object){
main.man = object;
//main.man.position.set(0,-600,400);
main.man.position.set(0,0,0);
main.texture = new THREE.TextureLoader().load( 'https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/Gominolas.png' );
main.texture_needsUpdate = true;
var uniforms = {
u_time:{type:'f', value:0.0},
u_mouse:{type:'v2', value: new THREE.Vector2()},
u_resolution: {type: 'v2', value: {x:2048.,y:1024.}},
texture: {type: 't', value: main.texture}
}
main.material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('vertex-shader').textContent,
fragmentShader: document.getElementById('fragment-shader').textContent,
transparent: true
});
main.material.needsUpdate = true;
main.material.side = THREE.DoubleSide;
// main.material = new THREE.MeshNormalMaterial();
main.man.traverse(function(child){
if(child instanceof THREE.Mesh){
child.material = main.material;
child.material.needsUpdate = true;
child.geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );
child.geometry.computeVertexNormals();
child.geometry.elementsNeedUpdate = true;
child.geometry.mergeVertices();
child.verticesNeedUpdate = true;
child.normalsNeedUpdate = true;
child.uvsNeedUpdate = true;
child.material.flatShading = THREE.SmoothShading;
}
});
main.scene.add(main.man);
},
function (xhr){
console.log((xhr.loaded/xhr.total*100)+'% loaded');
},
function (error){
console.log(error,'An error happened');
}
);
window.onresize = main.onResize;
this.render();
}
this.render = function(){
var time = Date.now();
main.controls.update();
requestAnimationFrame(main.render);
main.renderer.render(main.scene, main.camera);
}
this.onResize = function(event) {
main.renderer.setSize(window.innerWidth, window.innerHeight);
main.camera.aspect = window.innerWidth / window.innerHeight;
main.camera.updateProjectionMatrix();
}
}
main.init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader.js"></script>
<textarea id="plane_obj" style="display:none;">
v -1.000000 0.000000 1.000000
v 1.000000 0.000000 1.000000
v -1.000000 0.000000 -1.000000
v 1.000000 0.000000 -1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vn 0.0000 1.0000 0.0000
f 1/1/1 2/2/1 4/4/1 3/3/1
</textarea>
<script type='x-shader/x-vertex' id='vertex-shader'>
uniform float u_time;
varying vec2 vUv;
void main() {
vUv = uv;
vec4 pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
gl_Position = pos;
}
</script>
<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;
uniform float u_time;
uniform vec2 u_resolution;
uniform sampler2D texture;
varying vec2 vUv;
void main(){
vec2 st = vUv;
vec4 tex = texture2D(texture, st);
gl_FragColor = tex;
}
</script>
来源:https://stackoverflow.com/questions/53681200/three-js-vertex-shader-uv-variable-return-only-0-0