mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-01-30 15:42:42 +08:00
Collada cube and mesh export
This commit is contained in:
parent
8da6ae45c5
commit
43608512da
@ -6,38 +6,27 @@ var codec = new Codec('collada', {
|
||||
extension: 'dae',
|
||||
async compile(options = 0) {
|
||||
let scope = this;
|
||||
/*
|
||||
let exporter = new THREE.ColladaExporter();
|
||||
let animations = [];
|
||||
let gl_scene = new THREE.Scene();
|
||||
gl_scene.name = 'blockbench_export'
|
||||
|
||||
gl_scene.add(Project.model_3d);
|
||||
|
||||
if (!Modes.edit) {
|
||||
Animator.showDefaultPose();
|
||||
}
|
||||
if (options.animations !== false) {
|
||||
//animations = buildAnimationTracks();
|
||||
}
|
||||
let result = await new Promise((resolve, reject) => {
|
||||
exporter.parse(gl_scene, (result) => {
|
||||
resolve(result);
|
||||
}, {
|
||||
author: settings.username.value || 'Blockbench User',
|
||||
textureDirectory: 'textures'
|
||||
});
|
||||
})
|
||||
scene.add(Project.model_3d);
|
||||
*/
|
||||
let geometries = [];
|
||||
let root = [];
|
||||
let effects = [];
|
||||
let images = [];
|
||||
let materials = [];
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* different materials per geo
|
||||
* animations
|
||||
* image export
|
||||
*/
|
||||
|
||||
// Structure
|
||||
let model = {
|
||||
type: 'COLLADA',
|
||||
attributes: {
|
||||
xmlns: 'http://www.collada.org/2005/11/COLLADASchema',
|
||||
version: '1.4.1',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
},
|
||||
content: [
|
||||
{
|
||||
type: 'asset',
|
||||
@ -45,12 +34,13 @@ var codec = new Codec('collada', {
|
||||
{
|
||||
name: 'contributor',
|
||||
content: [
|
||||
{type: 'author', content: settings.username.value || 'Blockbench user'},
|
||||
{type: 'authoring_tool', content: 'Blockbench'},
|
||||
{type: 'author', content: settings.username.value || 'Blockbench user'}
|
||||
]
|
||||
},
|
||||
{name: 'created', content: new Date().toISOString()},
|
||||
{name: 'modified', content: new Date().toISOString()},
|
||||
{name: 'unit', attributes: {name: 'meter', meter: "0.0625"}},
|
||||
{name: 'up_axis', content: 'Y_UP'}
|
||||
]
|
||||
},
|
||||
@ -93,6 +83,7 @@ var codec = new Codec('collada', {
|
||||
]
|
||||
}
|
||||
|
||||
// Materials
|
||||
Texture.all.forEach((texture, i) => {
|
||||
effects.push({
|
||||
type: 'effect',
|
||||
@ -102,20 +93,19 @@ var codec = new Codec('collada', {
|
||||
content: [
|
||||
{
|
||||
type: 'newparam',
|
||||
attributes: {sid: `Image_0-surface`},
|
||||
attributes: {sid: `Image_${i}-surface`},
|
||||
content: {
|
||||
type: 'surface',
|
||||
attributes: {type: '2D'},
|
||||
content: {type: 'init_from', content: `Image_0`}
|
||||
content: {type: 'init_from', content: `Image_${i}`}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'newparam',
|
||||
attributes: {sid: `Image_0-sampler`},
|
||||
attributes: {sid: `Image_${i}-sampler`},
|
||||
content: {
|
||||
type: 'sampler2D',
|
||||
attributes: {type: '2D'},
|
||||
content: {type: 'source', content: `Image_0-surface`}
|
||||
content: {type: 'source', content: `Image_${i}-surface`}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -125,7 +115,7 @@ var codec = new Codec('collada', {
|
||||
type: 'lambert',
|
||||
content: [
|
||||
{type: 'emission', content: {type: 'color', attributes: {sid: 'emission'}, content: '0 0 0 1'}},
|
||||
{type: 'diffuse', content: {type: 'texture', attributes: {texture: `Image_0-sampler`, texcoord: 'UVMap'}}},
|
||||
{type: 'diffuse', content: {type: 'texture', attributes: {texture: `Image_${i}-sampler`, texcoord: 'UVMap'}}},
|
||||
{type: 'index_of_refraction', content: {type: 'float', attributes: {sid: 'ior'}, content: '1.45'}}
|
||||
]
|
||||
}
|
||||
@ -141,26 +131,92 @@ var codec = new Codec('collada', {
|
||||
},
|
||||
content: {
|
||||
type: 'init_from',
|
||||
content: `Image_${i}.png`
|
||||
content: `${texture.name.replace(/\.png$/, '')}.png`
|
||||
}
|
||||
})
|
||||
materials.push({
|
||||
type: 'material',
|
||||
attributes: {
|
||||
id: `Image_${i}-material`,
|
||||
name: `Image_${i}`,
|
||||
id: `Material_${i}-material`,
|
||||
name: `Material_${i}`,
|
||||
},
|
||||
content: {name: 'instance_effect', attributes: {url: `#Material_${i}-effect`}}
|
||||
})
|
||||
})
|
||||
|
||||
// Cube Geometry
|
||||
const cube_face_normals = {
|
||||
north: [0, 0, -1],
|
||||
east: [1, 0, 0],
|
||||
south: [0, 0, 1],
|
||||
west: [-1, 0, 0],
|
||||
up: [0, 1, 0],
|
||||
down: [0, -1, 0],
|
||||
}
|
||||
Cube.all.forEach(cube => {
|
||||
|
||||
let positions = [];
|
||||
let normals = [];
|
||||
let uv = [];
|
||||
let vcount = [];
|
||||
let primitive = [];
|
||||
|
||||
function addPosition(x, y, z) {
|
||||
positions.push(x - cube.origin[0], y - cube.origin[1], z - cube.origin[2]);
|
||||
}
|
||||
|
||||
addPosition(cube.to[0] + cube.inflate, cube.to[1] + cube.inflate, cube.to[2] + cube.inflate);
|
||||
addPosition(cube.to[0] + cube.inflate, cube.to[1] + cube.inflate, cube.from[2] - cube.inflate);
|
||||
addPosition(cube.to[0] + cube.inflate, cube.from[1] - cube.inflate, cube.to[2] + cube.inflate);
|
||||
addPosition(cube.to[0] + cube.inflate, cube.from[1] - cube.inflate, cube.from[2] - cube.inflate);
|
||||
addPosition(cube.from[0] - cube.inflate, cube.to[1] + cube.inflate, cube.from[2] - cube.inflate);
|
||||
addPosition(cube.from[0] - cube.inflate, cube.to[1] + cube.inflate, cube.to[2] + cube.inflate);
|
||||
addPosition(cube.from[0] - cube.inflate, cube.from[1] - cube.inflate, cube.from[2] - cube.inflate);
|
||||
addPosition(cube.from[0] - cube.inflate, cube.from[1] - cube.inflate, cube.to[2] + cube.inflate);
|
||||
|
||||
for (let fkey in cube.faces) {
|
||||
let face = cube.faces[fkey];
|
||||
if (face.texture === null) continue;
|
||||
normals.push(...cube_face_normals[fkey]);
|
||||
|
||||
let uv_outputs = [
|
||||
[face.uv[0] / Project.texture_width, 1 - face.uv[1] / Project.texture_height],
|
||||
[face.uv[2] / Project.texture_width, 1 - face.uv[1] / Project.texture_height],
|
||||
[face.uv[2] / Project.texture_width, 1 - face.uv[3] / Project.texture_height],
|
||||
[face.uv[0] / Project.texture_width, 1 - face.uv[3] / Project.texture_height],
|
||||
];
|
||||
var rot = face.rotation || 0;
|
||||
while (rot > 0) {
|
||||
uv_outputs.splice(0, 0, uv_outputs.pop());
|
||||
rot -= 90;
|
||||
}
|
||||
uv_outputs.forEach(coord => {
|
||||
uv.push(...coord);
|
||||
})
|
||||
|
||||
vcount.push(4);
|
||||
let vertices;
|
||||
switch (fkey) {
|
||||
case 'north': vertices = [1, 4, 6, 3]; break;
|
||||
case 'east': vertices = [0, 1, 3, 2]; break;
|
||||
case 'south': vertices = [5, 0, 2, 7]; break;
|
||||
case 'west': vertices = [4, 5, 7, 6]; break;
|
||||
case 'up': vertices = [4, 1, 0, 5]; break;
|
||||
case 'down': vertices = [7, 2, 3, 6]; break;
|
||||
}
|
||||
primitive.push(
|
||||
vertices[0], (normals.length/3)-1, vcount.length*4 - 4,
|
||||
vertices[1], (normals.length/3)-1, vcount.length*4 - 3,
|
||||
vertices[2], (normals.length/3)-1, vcount.length*4 - 2,
|
||||
vertices[3], (normals.length/3)-1, vcount.length*4 - 1,
|
||||
)
|
||||
}
|
||||
|
||||
let geometry = {
|
||||
type: 'geometry',
|
||||
attributes: {
|
||||
id: `${cube.uuid}-mesh`,
|
||||
name: Cube.name
|
||||
name: cube.name
|
||||
},
|
||||
content: [{
|
||||
type: 'mesh',
|
||||
@ -171,14 +227,14 @@ var codec = new Codec('collada', {
|
||||
content: [
|
||||
{
|
||||
type: 'float_array',
|
||||
attributes: {id: `${cube.uuid}-mesh-positions-array`, count: 24},
|
||||
content: cube.mesh.geometry.attributes.position.array.join(' ')
|
||||
attributes: {id: `${cube.uuid}-mesh-positions-array`, count: positions.length},
|
||||
content: positions.join(' ')
|
||||
},
|
||||
{
|
||||
type: 'technique_common',
|
||||
content: {
|
||||
type: 'accessor',
|
||||
attributes: {source: `#${cube.uuid}-mesh-positions-array`, count: 8, stride: 3},
|
||||
attributes: {source: `#${cube.uuid}-mesh-positions-array`, count: positions.length/3, stride: 3},
|
||||
content: [
|
||||
{type: 'param', attributes: {name: 'X', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'Y', type: 'float'}},
|
||||
@ -194,14 +250,14 @@ var codec = new Codec('collada', {
|
||||
content: [
|
||||
{
|
||||
type: 'float_array',
|
||||
attributes: {id: `${cube.uuid}-mesh-normals-array`, count: 18},
|
||||
content: cube.mesh.geometry.attributes.normal.array.join(' ')
|
||||
attributes: {id: `${cube.uuid}-mesh-normals-array`, count: normals.length},
|
||||
content: normals.join(' ')
|
||||
},
|
||||
{
|
||||
type: 'technique_common',
|
||||
content: {
|
||||
type: 'accessor',
|
||||
attributes: {source: `#${cube.uuid}-mesh-normals-array`, count: 6, stride: 3},
|
||||
attributes: {source: `#${cube.uuid}-mesh-normals-array`, count: normals.length/3, stride: 3},
|
||||
content: [
|
||||
{type: 'param', attributes: {name: 'X', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'Y', type: 'float'}},
|
||||
@ -217,14 +273,14 @@ var codec = new Codec('collada', {
|
||||
content: [
|
||||
{
|
||||
type: 'float_array',
|
||||
attributes: {id: `${cube.uuid}-mesh-map-0-array`, count: 48},
|
||||
content: cube.mesh.geometry.attributes.uv.array.join(' ')
|
||||
attributes: {id: `${cube.uuid}-mesh-map-0-array`, count: uv.length},
|
||||
content: uv.join(' ')
|
||||
},
|
||||
{
|
||||
type: 'technique_common',
|
||||
content: {
|
||||
type: 'accessor',
|
||||
attributes: {source: `#${cube.uuid}-mesh-map-0-array`, count: 24, stride: 2},
|
||||
attributes: {source: `#${cube.uuid}-mesh-map-0-array`, count: uv.length/2, stride: 2},
|
||||
content: [
|
||||
{type: 'param', attributes: {name: 'S', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'T', type: 'float'}},
|
||||
@ -239,22 +295,22 @@ var codec = new Codec('collada', {
|
||||
content: [
|
||||
{
|
||||
type: 'input',
|
||||
attributes: {semantic: 'POSITION', id: `${cube.uuid}-mesh-positions`}
|
||||
attributes: {semantic: 'POSITION', source: `#${cube.uuid}-mesh-positions`}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'polylist',
|
||||
attributes: {
|
||||
count: 6,
|
||||
material: ''
|
||||
material: `Material_${Texture.all.indexOf(cube.faces.north.getTexture())}-material`,
|
||||
count: 6
|
||||
},
|
||||
content: [
|
||||
{type: 'input', semantic: 'VERTEX', source: `${cube.uuid}-mesh-positions`, offset: 0},
|
||||
{type: 'input', semantic: 'NORMAL', source: `${cube.uuid}-mesh-normals`, offset: 1},
|
||||
{type: 'input', semantic: 'TEXCOORD', source: `${cube.uuid}-mesh-map-0`, offset: 2, set: 0},
|
||||
{type: 'vcount', content: '4 4 4 4 4 4'},
|
||||
{type: 'p', content: '0 0 0 1 0 1 3 0 2 2 0 3 2 1 4 3 1 5 7 1 6 6 1 7 6 2 8 7 2 9 5 2 10 4 2 11 4 3 12 5 3 13 1 3 14 0 3 15 2 4 16 6 4 17 4 4 18 0 4 19 7 5 20 3 5 21 1 5 22 5 5 23'}
|
||||
{type: 'input', attributes: {semantic: 'VERTEX', source: `#${cube.uuid}-mesh-vertices`, offset: 0}},
|
||||
{type: 'input', attributes: {semantic: 'NORMAL', source: `#${cube.uuid}-mesh-normals`, offset: 1}},
|
||||
{type: 'input', attributes: {semantic: 'TEXCOORD', source: `#${cube.uuid}-mesh-map-0`, offset: 2, set: 0}},
|
||||
{type: 'vcount', content: vcount.join(' ')},
|
||||
{type: 'p', content: primitive.join(' ')}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -263,8 +319,167 @@ var codec = new Codec('collada', {
|
||||
geometries.push(geometry);
|
||||
})
|
||||
|
||||
// Mesh Geo
|
||||
Mesh.all.forEach(mesh => {
|
||||
|
||||
let positions = [];
|
||||
let normals = [];
|
||||
let uv = [];
|
||||
let vcount = [];
|
||||
let primitive = [];
|
||||
let vertex_keys = [];
|
||||
|
||||
function addPosition(x, y, z) {
|
||||
positions.push(x, y, z);
|
||||
}
|
||||
|
||||
for (let vkey in mesh.vertices) {
|
||||
addPosition(...mesh.vertices[vkey]);
|
||||
vertex_keys.push(vkey);
|
||||
}
|
||||
|
||||
let texture;
|
||||
|
||||
for (let key in mesh.faces) {
|
||||
if (mesh.faces[key].texture !== null && mesh.faces[key].vertices.length >= 3) {
|
||||
let face = mesh.faces[key];
|
||||
let vertices = face.getSortedVertices();
|
||||
let tex = mesh.faces[key].getTexture();
|
||||
texture = tex;
|
||||
|
||||
vcount.push(vertices.length);
|
||||
|
||||
vertices.forEach(vkey => {
|
||||
uv.push(face.uv[vkey][0] / Project.texture_width, 1 - face.uv[vkey][1] / Project.texture_height);
|
||||
})
|
||||
|
||||
normals.push(...face.getNormal(true));
|
||||
|
||||
vertices.forEach((vkey, vi) => {
|
||||
primitive.push(
|
||||
vertex_keys.indexOf(vkey),
|
||||
(normals.length/3)-1,
|
||||
(uv.length/2)-vertices.length+vi,
|
||||
)
|
||||
})
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
let geometry = {
|
||||
type: 'geometry',
|
||||
attributes: {
|
||||
id: `${mesh.uuid}-mesh`,
|
||||
name: mesh.name
|
||||
},
|
||||
content: [{
|
||||
type: 'mesh',
|
||||
content: [
|
||||
{
|
||||
type: 'source',
|
||||
attributes: {id: `${mesh.uuid}-mesh-positions`},
|
||||
content: [
|
||||
{
|
||||
type: 'float_array',
|
||||
attributes: {id: `${mesh.uuid}-mesh-positions-array`, count: positions.length},
|
||||
content: positions.join(' ')
|
||||
},
|
||||
{
|
||||
type: 'technique_common',
|
||||
content: {
|
||||
type: 'accessor',
|
||||
attributes: {source: `#${mesh.uuid}-mesh-positions-array`, count: positions.length/3, stride: 3},
|
||||
content: [
|
||||
{type: 'param', attributes: {name: 'X', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'Y', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'Z', type: 'float'}},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'source',
|
||||
attributes: {id: `${mesh.uuid}-mesh-normals`},
|
||||
content: [
|
||||
{
|
||||
type: 'float_array',
|
||||
attributes: {id: `${mesh.uuid}-mesh-normals-array`, count: normals.length},
|
||||
content: normals.join(' ')
|
||||
},
|
||||
{
|
||||
type: 'technique_common',
|
||||
content: {
|
||||
type: 'accessor',
|
||||
attributes: {source: `#${mesh.uuid}-mesh-normals-array`, count: normals.length/3, stride: 3},
|
||||
content: [
|
||||
{type: 'param', attributes: {name: 'X', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'Y', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'Z', type: 'float'}},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'source',
|
||||
attributes: {id: `${mesh.uuid}-mesh-map-0`},
|
||||
content: [
|
||||
{
|
||||
type: 'float_array',
|
||||
attributes: {id: `${mesh.uuid}-mesh-map-0-array`, count: uv.length},
|
||||
content: uv.join(' ')
|
||||
},
|
||||
{
|
||||
type: 'technique_common',
|
||||
content: {
|
||||
type: 'accessor',
|
||||
attributes: {source: `#${mesh.uuid}-mesh-map-0-array`, count: uv.length/2, stride: 2},
|
||||
content: [
|
||||
{type: 'param', attributes: {name: 'S', type: 'float'}},
|
||||
{type: 'param', attributes: {name: 'T', type: 'float'}},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'vertices',
|
||||
attributes: {id: `${mesh.uuid}-mesh-vertices`},
|
||||
content: [
|
||||
{
|
||||
type: 'input',
|
||||
attributes: {semantic: 'POSITION', source: `#${mesh.uuid}-mesh-positions`}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'polylist',
|
||||
attributes: {
|
||||
material: `Material_${Texture.all.indexOf(texture)}-material`,
|
||||
count: 6
|
||||
},
|
||||
content: [
|
||||
{type: 'input', attributes: {semantic: 'VERTEX', source: `#${mesh.uuid}-mesh-vertices`, offset: 0}},
|
||||
{type: 'input', attributes: {semantic: 'NORMAL', source: `#${mesh.uuid}-mesh-normals`, offset: 1}},
|
||||
{type: 'input', attributes: {semantic: 'TEXCOORD', source: `#${mesh.uuid}-mesh-map-0`, offset: 2, set: 0}},
|
||||
{type: 'vcount', content: vcount.join(' ')},
|
||||
{type: 'p', content: primitive.join(' ')}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
geometries.push(geometry);
|
||||
})
|
||||
|
||||
// Object Hierarchy
|
||||
function processNode(node) {
|
||||
let position = node.origin.slice();
|
||||
if (node.parent instanceof Group) position.V3_subtract(node.parent.origin);
|
||||
|
||||
let tag = {
|
||||
name: 'node',
|
||||
attributes: {
|
||||
id: node.uuid,
|
||||
name: node.name,
|
||||
@ -272,13 +487,44 @@ var codec = new Codec('collada', {
|
||||
},
|
||||
content: [
|
||||
{type: 'scale', attributes: {sid: 'scale'}, content: '1 1 1'},
|
||||
{type: 'rotate', attributes: {sid: 'rotationX'}, content: '1 0 0 0'},
|
||||
{type: 'rotate', attributes: {sid: 'rotationY'}, content: '0 1 0 0'},
|
||||
{type: 'rotate', attributes: {sid: 'rotationZ'}, content: '0 0 1 -7'},
|
||||
{type: 'translate', attributes: {sid: 'location'}, content: node.origin.join(' ')},
|
||||
{type: 'instance_geometry', attributes: {url: `#${node.uuid}-mesh`, name: node.name}},
|
||||
{type: 'translate', attributes: {sid: 'location'}, content: position.join(' ')},
|
||||
]
|
||||
}
|
||||
if (node.rotatable) {
|
||||
tag.content.push(
|
||||
{type: 'rotate', attributes: {sid: 'rotationZ'}, content: `0 0 1 ${node.rotation[2]}`},
|
||||
{type: 'rotate', attributes: {sid: 'rotationY'}, content: `0 1 0 ${node.rotation[1]}`},
|
||||
{type: 'rotate', attributes: {sid: 'rotationX'}, content: `1 0 0 ${node.rotation[0]}`},
|
||||
)
|
||||
}
|
||||
if (node instanceof Cube || node instanceof Mesh) {
|
||||
let textures = [];
|
||||
for (let fkey in node.faces) {
|
||||
let tex = node.faces[fkey].getTexture();
|
||||
if (tex instanceof Texture) textures.safePush(tex);
|
||||
}
|
||||
tag.content.push({
|
||||
type: 'instance_geometry',
|
||||
attributes: {url: `#${node.uuid}-mesh`, name: node.name},
|
||||
content: {
|
||||
name: 'bind_material',
|
||||
content: {
|
||||
name: 'technique_common',
|
||||
content: textures.map(tex => {
|
||||
let index = Texture.all.indexOf(tex);
|
||||
return {
|
||||
name: 'instance_material',
|
||||
attributes: {symbol: `Material_${index}-material`, target: `#Material_${index}-material`},
|
||||
content: {
|
||||
name: 'bind_vertex_input',
|
||||
attributes: {semantic: 'UVMap', input_semantic: 'TEXCOORD', input_set: '0'}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (node instanceof Group) {
|
||||
node.children.forEach(node => {
|
||||
tag.content.push(processNode(node));
|
||||
@ -356,7 +602,7 @@ function compileXML(object) {
|
||||
output += `>\n`;
|
||||
let list = object.content instanceof Array ? object.content : [object.content];
|
||||
list.forEach(node => {
|
||||
handleObject(node);
|
||||
if (typeof node == 'object') handleObject(node);
|
||||
})
|
||||
depth--;
|
||||
output += spaces() + `</${type}>\n`;
|
||||
|
@ -181,6 +181,8 @@ var codec = new Codec('gltf', {
|
||||
}
|
||||
})
|
||||
|
||||
codec.buildAnimationTracks = buildAnimationTracks;
|
||||
|
||||
BARS.defineActions(function() {
|
||||
codec.export_action = new Action({
|
||||
id: 'export_gltf',
|
||||
|
@ -91,7 +91,7 @@ var codec = new Codec('obj', {
|
||||
uv_outputs.push(`vt ${face.uv[2] / Project.texture_width} ${1 - face.uv[1] / Project.texture_height}`);
|
||||
uv_outputs.push(`vt ${face.uv[2] / Project.texture_width} ${1 - face.uv[3] / Project.texture_height}`);
|
||||
uv_outputs.push(`vt ${face.uv[0] / Project.texture_width} ${1 - face.uv[3] / Project.texture_height}`);
|
||||
var rot = element.faces[key].rotation || 0;
|
||||
var rot = face.rotation || 0;
|
||||
while (rot > 0) {
|
||||
uv_outputs.splice(0, 0, uv_outputs.pop());
|
||||
rot -= 90;
|
||||
|
@ -410,6 +410,7 @@ class Group extends OutlinerNode {
|
||||
Group.prototype.type = 'group';
|
||||
Group.prototype.icon = 'fa fa-folder';
|
||||
Group.prototype.isParent = true;
|
||||
Group.prototype.rotatable = true;
|
||||
Group.prototype.name_regex = () => Format.bone_rig ? 'a-zA-Z0-9_' : false;
|
||||
Group.prototype.buttons = [
|
||||
Outliner.buttons.autouv,
|
||||
|
@ -862,9 +862,9 @@
|
||||
"action.export_obj": "Export OBJ Model",
|
||||
"action.export_obj.desc": "Export a Wavefront OBJ model for rendering",
|
||||
"action.export_collada": "Export Collada Model (dae)",
|
||||
"action.export_collada.desc": "Export model and animations as dae file to use in other 3D applications",
|
||||
"action.export_collada.desc": "Export model and animations as dae file to use it in other 3D applications",
|
||||
"action.export_gltf": "Export glTF Model",
|
||||
"action.export_gltf.desc": "Export model and animations as glTF file to use in other 3D applications",
|
||||
"action.export_gltf.desc": "Export model and animations as glTF file for sharing and rendering",
|
||||
"action.upload_sketchfab": "Upload to Sketchfab",
|
||||
"action.upload_sketchfab.desc": "Upload your model to Sketchfab",
|
||||
"action.share_model": "Share...",
|
||||
|
Loading…
Reference in New Issue
Block a user