当我将此图片加载到沙发模型上时:
我得到了:
我的纹理参数如下:
COL="collectionName"
HOW_MANY=10000
DATE_CUTOFF=$(mongo <host, user, pass...> dbname --quiet \
--eval "db.$COL.find({}, { createdAt: 1 }).sort({ createdAt: -1 }).skip($HOW_MANY).limit(1)"\
| grep -E -o '(ISODate\(.*?\))')
echo "Copying $HOW_MANY items after $DATE_CUTOFF..."
mongodump <host, user, pass...> -d dbname -c ${COL}\
-q "{ createdAt: { \$gte: $DATE_CUTOFF} }" --gzip
当我将gl.CLAMP_TO_EDGE更改为gl.REPEAT时,
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
即使这张f图片是2的幂,我也会得到相同的浑浊图像。
这是正常行为吗?我想看到这个F在模型上重复出现。像这样:
答案 0 :(得分:2)
您需要显示.OBJ加载代码。
在THREE.js中加载相同的文件并应用相同的纹理我得到了
我在this page的底部使用了示例,然后在加载模型后,遍历所有节点并应用了纹理
const loader = new THREE.TextureLoader();
const texture = loader.load('resources/images/f-texture.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
root.traverse((node) => {
if (node.material) {
if (Array.isArray(node.material)) {
node.material.forEach((m) => {
m.map = texture;
});
} else {
node.material.map = texture;
}
}
});
我还快速编写了自己的.OBJ加载器
"use strict";
const vs = `
uniform mat4 u_worldViewProjection;
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texCoord;
void main() {
v_texCoord = texcoord;
gl_Position = u_worldViewProjection * position;
}
`;
const fs = `
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_diffuse;
void main() {
gl_FragColor = texture2D(u_diffuse, v_texCoord);
}
`;
function loadTextFile(url) {
return fetch(url).then(req => req.text());
}
function addModel(context) {
if (context.faces) {
const {faces, modelName, materialName} = context;
context.models.push({
faces, modelName, materialName,
});
context.faces = undefined;
}
}
function addDataFn(name) {
return function(context, args) {
addModel(context);
const {data} = context;
if (!data[name]) {
data[name] = {
numComponents: args.length,
data: [],
};
}
data[name].data.push(...args.map(parseFloat));
};
}
function addPropFn(name) {
return function(context, args) {
context[name] = args.join(' ');
};
}
function addFace(context, args) {
if (!context.faces) {
context.faces = [];
}
context.faces.push(args.map((vert) => {
return vert.split('/').map(v => v.length ? parseInt(v) : undefined);
}));
}
function noop() {
}
const objHandlers = {
mtllib: addPropFn('mtllib'),
v: addDataFn('position'),
vn: addDataFn('normal'),
vt: addDataFn('texcoord'),
g: addPropFn('modelName'),
o: addPropFn('modelName'),
usemtl: addPropFn('materialName'),
s: noop,
f: addFace,
};
function parseObj(objText) {
const context = {
data: {},
models: [],
};
objText.split('\n').forEach((origLine, lineNo) => {
const noCommentLine = origLine.replace(/#.*/, '');
const line = noCommentLine.trim();
if (line === '') {
return;
}
const parts = line.split(/\s+/);
const code = parts.shift();
const fn = objHandlers[code];
if (!fn) {
console.error('unknown code:', code, 'at line', lineNo + 1, ':', line);
} else {
fn(context, parts);
}
});
addModel(context);
const arrays = {};
const indices = [];
let numVerts = 0;
const vertIds = {};
const arrayNames = Object.keys(context.data);
for (const [name, src] of Object.entries(context.data)) {
arrays[name] = {
numComponents: src.numComponents,
data: [],
};
}
// for the f statement
// f v/vt/vn -> position/texcoord/normal
const channelNames = [
'position',
'texcoord',
'normal',
];
function addVertex(vertexPartIndices) {
const parts = [];
vertexPartIndices.forEach((partNdx, ndx) => {
if (partNdx !== undefined) {
parts.push(ndx, partNdx);
}
});
const vId = parts.join(',');
let vertNdx = vertIds[vId];
if (vertNdx === undefined) {
vertNdx = numVerts++;
vertIds[vId] = vertNdx;
vertexPartIndices.forEach((partNdx, ndx) => {
if (partNdx === undefined) {
return;
}
const name = channelNames[ndx];
const data = context.data[name];
const start = (partNdx - 1) * data.numComponents;
const end = start + data.numComponents;
if (end > data.data.length) {
debugger;
}
const values = data.data.slice(start, end);
if (values.length !== 3) {
debugger;
}
arrays[name].data.push(...values);
});
}
return vertNdx;
}
for (const model of context.models) {
for (const face of model.faces) {
const numVerts = face.length;
if (numVerts < 3) {
throw new Error('numVerts for face not at least 3');
}
if (numVerts > 4) {
debugger;
}
const vNdx0 = addVertex(face[0]);
for (let i = 1; i < numVerts - 1; ++i) {
indices.push(vNdx0);
indices.push(addVertex(face[i]));
indices.push(addVertex(face[i + 1]));
}
}
}
arrays.indices = {
data: new (indices.length > 65535 ? Uint32Array : Uint16Array)(indices),
};
return arrays;
}
async function main() {
const objText = await loadTextFile('models/obj/sofa/ROUND SOFA.obj');
const arrays = parseObj(objText);
const m4 = twgl.m4;
const gl = twgl.getContext(document.querySelector("#c"));
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const tex = twgl.createTexture(gl, {
src: 'images/f-texture.png',
flipY: true,
});
const uniforms = {
u_diffuse: tex,
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 1;
const zFar = 10000;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const eye = [500, 2000, -3000];
const target = [0, 400, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
const world = m4.rotationY(time);
uniforms.u_worldViewProjection = m4.multiply(viewProjection, world);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body { margin: 0; }
canvas { display: block; width: 100vw; height: 100vh; }
<canvas id="c"></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
抱歉,不能包含该模型。但是,它产生了这个
一个完全随机的猜测,在.OBJ文件中查找纹理坐标为3D
看文件本身,我看到纹理坐标是3D
vt -0.7657 0.1621 1.3290
vt -0.7585 0.1439 1.3329
vt 0.2553 0.1439 1.8866
vt 0.2553 0.1621 1.8866
vt 1.2742 0.5898 0.6789
...
代替普通的2D。检查three.js加载代码,它似乎忽略了第三坐标。是否有可能为每个坐标加载所有3个值,但将其索引为2?