mirror of
https://github.com/CesiumGS/obj2gltf.git
synced 2024-11-23 08:34:14 -05:00
Add triangle winding order sanitization option
This commit is contained in:
parent
fb491952fc
commit
5fc3ff8d6e
@ -4,7 +4,7 @@ Change Log
|
||||
### 3.?.? - 2021-??-??
|
||||
|
||||
* Removed `minFilter` and `magFilter` from generated samplers so that runtime engines can use their preferred texture filtering. [#240](https://github.com/CesiumGS/obj2gltf/pull/240)
|
||||
* Remove triangle winding order sanitization. [#236](https://github.com/CesiumGS/obj2gltf/pull/236)
|
||||
* Triangle winding order sanitization is longer done by default. Use the `--triangle-winding-order-sanitization` option. [#236](https://github.com/CesiumGS/obj2gltf/pull/236)
|
||||
|
||||
### 3.1.1 - 2021-06-22
|
||||
|
||||
|
@ -112,6 +112,9 @@ As a convenience the PBR textures may be supplied directly to the command line.
|
||||
|`--baseColorTexture`|Path to the baseColor/diffuse texture that should override textures in the .mtl file.|No|
|
||||
|`--emissiveTexture`|Path to the emissive texture that should override textures in the .mtl file.|No|
|
||||
|`--alphaTexture`|Path to the alpha texture that should override textures in the .mtl file.|No|
|
||||
|`--input-up-axis`|Up axis of the obj.|No|
|
||||
|`--output-up-axis`|Up axis of the converted glTF.|No|
|
||||
|`--triangle-winding-order-sanitization`|Apply triangle winding order sanitization.|No|
|
||||
|
||||
## Build Instructions
|
||||
|
||||
|
@ -91,6 +91,11 @@ const argv = yargs
|
||||
type : 'boolean',
|
||||
default : defaults.specularGlossiness
|
||||
},
|
||||
unlit : {
|
||||
describe : 'The glTF will be saved with the KHR_materials_unlit extension.',
|
||||
type : 'boolean',
|
||||
default : defaults.unlit
|
||||
},
|
||||
metallicRoughnessOcclusionTexture : {
|
||||
describe : 'Path to the metallic-roughness-occlusion texture that should override textures in the .mtl file, where occlusion is stored in the red channel, roughness is stored in the green channel, and metallic is stored in the blue channel. The model will be saved with a pbrMetallicRoughness material. This is often convenient in workflows where the .mtl does not exist or is not set up to use PBR materials. Intended for models with a single material',
|
||||
type : 'string',
|
||||
@ -124,11 +129,6 @@ const argv = yargs
|
||||
alphaTexture : {
|
||||
describe : 'Path to the alpha texture that should override textures in the .mtl file.'
|
||||
},
|
||||
unlit : {
|
||||
describe : 'The glTF will be saved with the KHR_materials_unlit extension.',
|
||||
type : 'boolean',
|
||||
default : defaults.unlit
|
||||
},
|
||||
inputUpAxis : {
|
||||
describe: 'Up axis of the obj.',
|
||||
choices: ['X', 'Y', 'Z'],
|
||||
@ -140,6 +140,11 @@ const argv = yargs
|
||||
choices: ['X', 'Y', 'Z'],
|
||||
type: 'string',
|
||||
default: 'Y'
|
||||
},
|
||||
triangleWindingOrderSanitization : {
|
||||
describe: 'Apply triangle winding order sanitization.',
|
||||
type: 'boolean',
|
||||
default: defaults.triangleWindingOrderSanitization
|
||||
}
|
||||
}).parse(args);
|
||||
|
||||
@ -187,7 +192,8 @@ const options = {
|
||||
overridingTextures : overridingTextures,
|
||||
outputDirectory : outputDirectory,
|
||||
inputUpAxis : argv.inputUpAxis,
|
||||
outputUpAxis : argv.outputUpAxis
|
||||
outputUpAxis : argv.outputUpAxis,
|
||||
triangleWindingOrderSanitization: argv.triangleWindingOrderSanitization
|
||||
};
|
||||
|
||||
console.time('Total');
|
||||
|
@ -256,6 +256,18 @@ function loadObj(objPath, options) {
|
||||
return Cartesian3.fromElements(px, py, pz, result);
|
||||
}
|
||||
|
||||
function getNormal(index, result) {
|
||||
const nx = globalNormals.get(index * 3);
|
||||
const ny = globalNormals.get(index * 3 + 1);
|
||||
const nz = globalNormals.get(index * 3 + 2);
|
||||
return Cartesian3.fromElements(nx, ny, nz, result);
|
||||
}
|
||||
|
||||
const scratch1 = new Cartesian3();
|
||||
const scratch2 = new Cartesian3();
|
||||
const scratch3 = new Cartesian3();
|
||||
const scratch4 = new Cartesian3();
|
||||
const scratch5 = new Cartesian3();
|
||||
const scratchCenter = new Cartesian3();
|
||||
const scratchAxis1 = new Cartesian3();
|
||||
const scratchAxis2 = new Cartesian3();
|
||||
@ -264,6 +276,23 @@ function loadObj(objPath, options) {
|
||||
const scratchVertexIndices = [];
|
||||
const scratchPoints = [];
|
||||
|
||||
function checkWindingCorrect(positionIndex1, positionIndex2, positionIndex3, normalIndex) {
|
||||
if (!defined(normalIndex)) {
|
||||
// If no face normal, we have to assume the winding is correct.
|
||||
return true;
|
||||
}
|
||||
const normal = getNormal(normalIndex, scratchNormal);
|
||||
const A = getPosition(positionIndex1, scratch1);
|
||||
const B = getPosition(positionIndex2, scratch2);
|
||||
const C = getPosition(positionIndex3, scratch3);
|
||||
|
||||
const BA = Cartesian3.subtract(B, A, scratch4);
|
||||
const CA = Cartesian3.subtract(C, A, scratch5);
|
||||
const cross = Cartesian3.cross(BA, CA, scratch3);
|
||||
|
||||
return (Cartesian3.dot(normal, cross) >= 0);
|
||||
}
|
||||
|
||||
function addTriangle(index1, index2, index3, correctWinding) {
|
||||
if (correctWinding) {
|
||||
primitive.indices.push(index1);
|
||||
@ -276,7 +305,7 @@ function loadObj(objPath, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function addFace(vertices, positions, uvs, normals) {
|
||||
function addFace(vertices, positions, uvs, normals, triangleWindingOrderSanitization) {
|
||||
correctAttributeIndices(positions, globalPositions, 3);
|
||||
correctAttributeIndices(normals, globalNormals, 3);
|
||||
correctAttributeIndices(uvs, globalUvs, 2);
|
||||
@ -285,10 +314,11 @@ function loadObj(objPath, options) {
|
||||
checkPrimitive(uvs, faceNormals);
|
||||
|
||||
if (vertices.length === 3) {
|
||||
const isWindingCorrect = !triangleWindingOrderSanitization || checkWindingCorrect(positions[0], positions[1], positions[2], normals[0]);
|
||||
const index1 = addVertex(vertices[0], positions[0], uvs[0], normals[0]);
|
||||
const index2 = addVertex(vertices[1], positions[1], uvs[1], normals[1]);
|
||||
const index3 = addVertex(vertices[2], positions[2], uvs[2], normals[2]);
|
||||
addTriangle(index1, index2, index3, true);
|
||||
addTriangle(index1, index2, index3, isWindingCorrect);
|
||||
} else { // Triangulate if the face is not a triangle
|
||||
const points = scratchPoints;
|
||||
const vertexIndices = scratchVertexIndices;
|
||||
@ -381,7 +411,7 @@ function loadObj(objPath, options) {
|
||||
faceNormals.push(result[3]);
|
||||
}
|
||||
if (faceVertices.length > 2) {
|
||||
addFace(faceVertices, facePositions, faceUvs, faceNormals);
|
||||
addFace(faceVertices, facePositions, faceUvs, faceNormals, options.triangleWindingOrderSanitization);
|
||||
}
|
||||
|
||||
faceVertices.length = 0;
|
||||
|
@ -36,6 +36,7 @@ module.exports = obj2gltf;
|
||||
* @param {String} [options.overridingTextures.alphaTexture] Path to the alpha texture.
|
||||
* @param {String} [options.inputUpAxis='Y'] Up axis of the obj. Choices are 'X', 'Y', and 'Z'.
|
||||
* @param {String} [options.outputUpAxis='Y'] Up axis of the converted glTF. Choices are 'X', 'Y', and 'Z'.
|
||||
* @param {String} [options.triangleWindingOrderSanitization=false] Apply triangle winding order sanitization.
|
||||
* @param {Logger} [options.logger] A callback function for handling logged messages. Defaults to console.log.
|
||||
* @param {Writer} [options.writer] A callback function that writes files that are saved as separate resources.
|
||||
* @param {String} [options.outputDirectory] Output directory for writing separate resources when options.writer is not defined.
|
||||
@ -58,6 +59,7 @@ function obj2gltf(objPath, options) {
|
||||
options.writer = defaultValue(options.writer, getDefaultWriter(options.outputDirectory));
|
||||
options.inputUpAxis = defaultValue(options.inputUpAxis, defaults.inputUpAxis);
|
||||
options.outputUpAxis = defaultValue(options.outputUpAxis, defaults.outputUpAxis);
|
||||
options.triangleWindingOrderSanitization = defaultValue(options.triangleWindingOrderSanitization, defaults.triangleWindingOrderSanitization);
|
||||
|
||||
if (!defined(objPath)) {
|
||||
throw new DeveloperError('objPath is required');
|
||||
@ -180,7 +182,13 @@ obj2gltf.defaults = {
|
||||
* @type String
|
||||
* @default 'Y'
|
||||
*/
|
||||
outputUpAxis: 'Y'
|
||||
outputUpAxis: 'Y',
|
||||
/**
|
||||
* Gets or sets whether triangle winding order sanitization will be applied.
|
||||
* @type Boolean
|
||||
* @default false
|
||||
*/
|
||||
windingOrderSanitization : false
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user