PBR preview (wip)

bedrock texture set import
This commit is contained in:
JannisX11 2024-09-15 21:18:17 +02:00
parent 85577d38aa
commit 25ae6a5046
9 changed files with 146 additions and 24 deletions

View File

@ -214,7 +214,7 @@ function buildSkinnedMesh(root_group, scale) {
if (face.texture === null) continue;
let tex = face.getTexture();
if (tex && tex.uuid) {
materials.push(Project.materials[tex.uuid])
materials.push(tex.getMaterial())
} else {
materials.push(Canvas.emptyMaterials[child.color])
}

View File

@ -1172,7 +1172,7 @@ new NodePreviewController(Cube, {
if (element.faces[face].texture !== null) {
let tex = element.faces[face].getTexture();
if (tex && tex.uuid) {
materials.push(Project.materials[tex.uuid])
materials.push(tex.getMaterial())
} else {
materials.push(Canvas.emptyMaterials[element.color % Canvas.emptyMaterials.length])
}

View File

@ -1118,7 +1118,7 @@ new NodePreviewController(Mesh, {
if (faces[key].vertices.length < 3) continue;
var tex = faces[key].getTexture()
if (tex && tex.uuid) {
materials.push(Project.materials[tex.uuid])
materials.push(tex.getMaterial())
} else {
materials.push(Canvas.emptyMaterials[element.color])
}

View File

@ -305,7 +305,7 @@ new NodePreviewController(TextureMesh, {
} else {
var tex = Texture.getDefault();
if (tex && tex.uuid) {
mesh.material = Project.materials[tex.uuid]
mesh.material = tex.getMaterial()
} else {
mesh.material = Canvas.emptyMaterials[0]
}

View File

@ -949,7 +949,7 @@ const Canvas = {
let side = Canvas.getRenderSide();
ModelProject.all.forEach(project => {
project.textures.forEach((tex) => {
var mat = project.materials[tex.uuid];
var mat = tex.getMaterial();
if (!mat) return;
mat.side = Canvas.getRenderSide(tex);
})
@ -1216,7 +1216,7 @@ const Canvas = {
if (layers instanceof Array == false) layers = Texture.all;
layers.forEachReverse(texture => {
if (texture.visible && i < 3) {
uniforms[`t${i}`].value = texture.getMaterial().map;
uniforms[`t${i}`].value = texture.getOwnMaterial().map;
i++;
}
})
@ -1269,7 +1269,7 @@ const Canvas = {
} else {
var tex = cube.faces[face].getTexture()
if (tex && tex.uuid) {
materials.push(Project.materials[tex.uuid])
materials.push(tex.getMaterial())
} else {
materials.push(Canvas.emptyMaterials[cube.color])
}

View File

@ -104,8 +104,13 @@ class PreviewScene {
Canvas.global_light_color.copy(this.light_color);
Canvas.global_light_side = this.light_side;
scene.background = this.cubemap;
scene.fog = this.fog;
Canvas.scene.background = this.cubemap;
Canvas.scene.fog = this.fog;
let pmremGenerator = new THREE.PMREMGenerator( Preview.selected.renderer );
Canvas.scene.environment = pmremGenerator.fromCubemap(this.cubemap).texture;
if (this.fov) {
Preview.selected.setFOV(this.fov);
}

View File

@ -29,7 +29,7 @@ const Painter = {
if (options.no_undo && options.use_cache) {
texture.updateLayerChanges();
let map = texture.getMaterial().map;
let map = texture.getOwnMaterial().map;
map.needsUpdate = true;
UVEditor.vue.updateTextureCanvas();
} else {

View File

@ -7,6 +7,12 @@ class TextureGroup {
TextureGroup.properties[key].reset(this);
}
if (data) this.extend(data);
this._static = Object.freeze({
properties: {
material: null
}
})
}
extend(data) {
for (let key in TextureGroup.properties) {
@ -16,6 +22,9 @@ class TextureGroup {
}
add() {
TextureGroup.all.push(this);
if (this.is_material) {
this.updateMaterial();
}
return this;
}
select() {
@ -66,6 +75,67 @@ class TextureGroup {
}
return copy;
}
updateMaterial() {
let material = this._static.properties.material;
if (!material) {
//let g = new THREE.PMREMGenerator(Preview.selected.renderer);
//let pmrem_render_target = g.fromScene(Canvas.scene);
// https://threejs.org/docs/index.html#api/en/materials/MeshStandardMaterial
material = this._static.properties.material = new THREE.MeshStandardMaterial({
//envMap: pmrem_render_target
});
}
let textures = this.getTextures();
let color_tex = textures.find(t => t.pbr_channel == 'color');
let normal_tex = textures.find(t => t.pbr_channel == 'normal');
let height_tex = textures.find(t => t.pbr_channel == 'height');
let mer_tex = textures.find(t => t.pbr_channel == 'mer');
if (color_tex) {
material.map = color_tex.getOwnMaterial().map;
}
if (normal_tex) {
material.normalMap = normal_tex.getOwnMaterial().map;
material.bumpMap = null;
} else if (height_tex) {
material.bumpMap = height_tex.getOwnMaterial().map;
material.normalMap = null;
}
if (mer_tex && mer_tex.img?.naturalWidth) {
let image_data = mer_tex.canvas.getContext('2d').getImageData(0, 0, mer_tex.width, mer_tex.height);
function generateMap(source_channel, target_channel, key) {
let canvas = material[key]?.image ?? document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = mer_tex.width;
canvas.height = mer_tex.height;
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, mer_tex.width, mer_tex.height);
document.body.append(canvas)
let image_data_new = ctx.getImageData(0, 0, mer_tex.width, mer_tex.height);
for (let i = 0; i < image_data.data.length; i += 4) {
image_data_new.data[i + target_channel] = image_data.data[i + source_channel];
}
ctx.putImageData(image_data_new, 0, 0);
if (!material[key] || true) {
material[key] = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
material[key].needsUpdate = true;
}
}
generateMap(0, 2, 'metalnessMap');
generateMap(1, 0, 'emissiveMap');
generateMap(2, 1, 'roughnessMap');
}
material.needsUpdate = true;
}
getMaterial() {
if (!this._static.properties.material) {
this.updateMaterial();
}
return this._static.properties.material;
}
}
Object.defineProperty(TextureGroup, 'all', {
get() {

View File

@ -725,7 +725,7 @@ class Texture {
}
updateMaterial() {
if (Format.image_editor) return this;
let mat = this.getMaterial();
let mat = this.getOwnMaterial();
mat.name = this.name;
mat.uniforms.EMISSIVE.value = this.render_mode == 'emissive';
@ -881,7 +881,14 @@ class Texture {
return this;
}
getMaterial() {
return Project.materials[this.uuid]
let group = this.getGroup();
if (group?.is_material) {
return group.getMaterial();
}
return Project.materials[this.uuid];
}
getOwnMaterial() {
return Project.materials[this.uuid];
}
//Management
select(event) {
@ -1741,7 +1748,7 @@ class Texture {
this.ctx.globalCompositeOperation = 'source-over';
if (!Format.image_editor && this.getMaterial()) {
this.getMaterial().map.needsUpdate = true;
this.getOwnMaterial().map.needsUpdate = true;
}
if (update_data_url) {
this.internal = true;
@ -1756,7 +1763,7 @@ class Texture {
} else {
if (!this.internal) this.convertToInternal();
if (!Format.image_editor) {
this.getMaterial().map.needsUpdate = true;
this.getOwnMaterial().map.needsUpdate = true;
}
this.source = this.canvas.toDataURL('image/png', 1);
this.updateImageFromCanvas();
@ -1849,7 +1856,7 @@ class Texture {
name: 'menu.texture.pbr_channel',
condition: (texture) => texture.getGroup()?.is_material,
children(texture) {
function setViewMode(channel) {
function applyChannel(channel) {
let group = texture.getGroup();
let changed_textures = group.getTextures();
@ -1858,13 +1865,14 @@ class Texture {
changed_textures.forEach(t => {
t.updateMaterial();
});
if (group) group.updateMaterial();
Undo.finishEdit('Change texture PBR channel');
}
return [
{name: 'menu.texture.pbr_channel.color', icon: texture.pbr_channel == 'color' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {setViewMode('color')}},
{name: 'menu.texture.pbr_channel.normal', icon: texture.pbr_channel == 'normal' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {setViewMode('normal')}},
{name: 'menu.texture.pbr_channel.height', icon: texture.pbr_channel == 'height' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {setViewMode('height')}},
{name: 'menu.texture.pbr_channel.mer', icon: texture.pbr_channel == 'mer' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {setViewMode('mer')}},
{name: 'menu.texture.pbr_channel.color', icon: texture.pbr_channel == 'color' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {applyChannel('color')}},
{name: 'menu.texture.pbr_channel.normal', icon: texture.pbr_channel == 'normal' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {applyChannel('normal')}},
{name: 'menu.texture.pbr_channel.height', icon: texture.pbr_channel == 'height' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {applyChannel('height')}},
{name: 'menu.texture.pbr_channel.mer', icon: texture.pbr_channel == 'mer' ? 'far.fa-dot-circle' : 'far.fa-circle', click() {applyChannel('mer')}},
]
}
},
@ -2251,18 +2259,57 @@ BARS.defineActions(function() {
arr.push('textures')
start_path = arr.join(osfs)
}
let extensions = ['png', 'tga'];
if (isApp) {
extensions.push('texture_set.json');
}
Blockbench.import({
resource_id: 'texture',
readtype: 'image',
type: 'PNG Texture',
extensions: ['png', 'tga'],
extensions,
multiple: true,
startpath: start_path
}, function(results) {
let new_textures = [];
}, function(files) {
let new_textures = [], new_texture_groups = [];
let texture_group = context instanceof TextureGroup ? context : Texture.selected?.getGroup();
Undo.initEdit({textures: new_textures});
results.forEach(function(f) {
Undo.initEdit({textures: new_textures, texture_groups: new_texture_groups});
files.forEach((f) => {
if (f.name.endsWith('texture_set.json')) {
let texture_group = new TextureGroup({is_material: true});
texture_group.name = f.name.replace('.texture_set.json', '');
let content = fs.readFileSync(f.path, {encoding: 'utf-8'});
let content_json = autoParseJSON(content);
if (content_json && content_json['minecraft:texture_set']) {
let channels = {
color: 'color',
normal: 'normal',
heightmap: 'height',
metalness_emissive_roughness: 'mer',
};
for (let key in channels) {
let source = content_json['minecraft:texture_set'][key];
if (typeof source == 'string') {
let path = PathModule.resolve(f.path, '../' + source + '.png');
Blockbench.read([path], {
readtype: 'image',
}, ([file2]) => {
let t = new Texture({
name: file2.name,
pbr_channel: channels[key]
}).fromFile(file2).add(false, true).fillParticle();
new_textures.push(t);
t.group = texture_group.uuid;
})
}
}
}
new_texture_groups.push(texture_group);
texture_group.add(false);
return;
}
let t = new Texture({name: f.name}).fromFile(f).add(false, true).fillParticle();
new_textures.push(t);
if (texture_group) {