mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-04-06 17:31:09 +08:00
PBR fixes and WIP map generator
This commit is contained in:
parent
c6e383dbd5
commit
6a0fbe69dd
@ -90,7 +90,8 @@ class TextureGroup {
|
||||
//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
|
||||
envMap: PreviewScene.active?.cubemap ?? null,
|
||||
envMapIntensity: 0.5,
|
||||
alphaTest: 0.05,
|
||||
});
|
||||
}
|
||||
@ -101,6 +102,13 @@ class TextureGroup {
|
||||
let mer_tex = textures.find(t => t.pbr_channel == 'mer');
|
||||
if (color_tex) {
|
||||
material.map = color_tex.getOwnMaterial().map;
|
||||
material.color.set('#ffffff');
|
||||
material.opacity = 1;
|
||||
} else {
|
||||
material.map = null;
|
||||
let c = this.material_config.color_value;
|
||||
material.color.set({r: c[0] / 255, g: c[1] / 255, b: c[2] / 255});
|
||||
material.opacity = c[4] / 255;
|
||||
}
|
||||
if (normal_tex) {
|
||||
material.normalMap = normal_tex.getOwnMaterial().map;
|
||||
@ -159,8 +167,16 @@ class TextureGroup {
|
||||
generateMap(1, 0, 'emissiveMap');
|
||||
generateMap(2, 1, 'roughnessMap');
|
||||
material.emissive.set(0xffffff);
|
||||
material.emissiveIntensity = 30;
|
||||
material.emissiveIntensity = 1;
|
||||
material.metalness = 1;
|
||||
} else {
|
||||
material.metalnessMap = null;
|
||||
material.emissiveMap = material.map;
|
||||
material.roughnessMap = null;
|
||||
material.emissive.set(0xffffff);
|
||||
material.metalness = this.material_config.mer_value[0] / 255;
|
||||
material.emissiveIntensity = this.material_config.mer_value[1] / 255;
|
||||
material.roughness = this.material_config.mer_value[2] / 255;
|
||||
}
|
||||
material.needsUpdate = true;
|
||||
}
|
||||
@ -312,30 +328,113 @@ class TextureGroupMaterialConfig {
|
||||
this.menu.open(event, this);
|
||||
}
|
||||
propertiesDialog() {
|
||||
let texture_options = {};
|
||||
let texture_options_optional = {
|
||||
none: 'None',
|
||||
};
|
||||
let texture_options_custom = {
|
||||
uniform: 'Uniform...',
|
||||
};
|
||||
let textures = this.texture_group.getTextures();
|
||||
for (let texture of textures) {
|
||||
let opt = {
|
||||
name: texture.name,
|
||||
icon: texture.img,
|
||||
}
|
||||
texture_options_optional[texture.uuid] = texture_options[texture.uuid] = texture_options_custom[texture.uuid] = opt;
|
||||
}
|
||||
new Dialog('material_config', {
|
||||
title: 'dialog.material_config.title',
|
||||
form: {
|
||||
color: {
|
||||
type: 'select',
|
||||
label: 'menu.texture.pbr_channel.color',
|
||||
options: texture_options_custom,
|
||||
value: textures.find(tex => tex.pbr_channel == 'color')?.uuid ?? 'uniform',
|
||||
},
|
||||
color_value: {
|
||||
label: 'dialog.material_config.color_value',
|
||||
type: 'vector', dimensions: 4,
|
||||
min: 0, max: 255, step: 1, force_step: true,
|
||||
value: this.color_value.map(v => Math.clamp(v, 0, 255)),
|
||||
condition: form => form.color == 'uniform',
|
||||
type: 'color',
|
||||
value: {
|
||||
r: this.color_value[0],
|
||||
g: this.color_value[1],
|
||||
b: this.color_value[2],
|
||||
a: this.color_value[3] / 255
|
||||
}
|
||||
},
|
||||
'mer': '_',
|
||||
mer: {
|
||||
type: 'select',
|
||||
label: 'dialog.material_config.mer',
|
||||
options: texture_options_custom,
|
||||
value: textures.find(tex => tex.pbr_channel == 'mer')?.uuid ?? 'uniform',
|
||||
},
|
||||
mer_value: {
|
||||
label: 'dialog.material_config.mer_value',
|
||||
condition: form => form.mer == 'uniform',
|
||||
type: 'vector', dimensions: 3,
|
||||
min: 0, max: 255, step: 1, force_step: true,
|
||||
value: this.mer_value.map(v => Math.clamp(v, 0, 255)),
|
||||
//toggle_enabled: true, toggle_default: this.mer_value.allEqual(0),
|
||||
}
|
||||
},
|
||||
'depth': '_',
|
||||
depth_type: {
|
||||
type: 'inline_select',
|
||||
label: 'dialog.material_config.depth_type',
|
||||
options: {
|
||||
height: 'menu.texture.pbr_channel.height',
|
||||
normal: 'menu.texture.pbr_channel.normal'
|
||||
},
|
||||
value: textures.find(tex => tex.pbr_channel == 'normal') ? 'normal' : 'height'
|
||||
},
|
||||
height: {
|
||||
type: 'select',
|
||||
label: 'menu.texture.pbr_channel.height',
|
||||
condition: form => form.depth_type == 'height',
|
||||
options: texture_options_optional,
|
||||
value: textures.find(tex => tex.pbr_channel == 'height')?.uuid ?? 'none',
|
||||
},
|
||||
normal: {
|
||||
type: 'select',
|
||||
label: 'menu.texture.pbr_channel.normal',
|
||||
condition: form => form.depth_type == 'normal',
|
||||
options: texture_options_optional,
|
||||
value: textures.find(tex => tex.pbr_channel == 'normal')?.uuid ?? 'none',
|
||||
},
|
||||
},
|
||||
onConfirm: (result) => {
|
||||
Undo.initEdit({texture_groups: [this.texture_group]});
|
||||
this.color_value.replace(result.color_value);
|
||||
if (result.mer_value) {
|
||||
console.log(result)
|
||||
Undo.initEdit({texture_groups: [this.texture_group], textures});
|
||||
|
||||
if (result.color == 'uniform') {
|
||||
let color = result.color_value.toRgb();
|
||||
let color_array = [color.r, color.g, color.b, Math.round(color.a * 255)];
|
||||
this.color_value.replace(color_array);
|
||||
} else {
|
||||
let target = textures.find(t => t.uuid == result.color);
|
||||
if (target) target.pbr_channel = 'color';
|
||||
}
|
||||
|
||||
if (result.mer == 'uniform') {
|
||||
this.mer_value.replace(result.mer_value);
|
||||
} else {
|
||||
this.mer_value.V3_set(0, 0, 0);
|
||||
this.mer_value.replace([0, 0, 0]);
|
||||
let target = textures.find(t => t.uuid == result.mer);
|
||||
if (target) target.pbr_channel = 'mer';
|
||||
}
|
||||
|
||||
if (result.depth_type == 'normal') {
|
||||
textures.forEach(t => {
|
||||
if (t.pbr_channel == 'normal') t.pbr_channel = 'color';
|
||||
})
|
||||
let target = textures.find(t => t.uuid == result.normal);
|
||||
if (target) target.pbr_channel = 'normal';
|
||||
} else {
|
||||
textures.forEach(t => {
|
||||
if (t.pbr_channel == 'height') t.pbr_channel = 'color';
|
||||
})
|
||||
let target = textures.find(t => t.uuid == result.height);
|
||||
if (target) target.pbr_channel = 'height';
|
||||
}
|
||||
this.saved = false;
|
||||
Undo.finishEdit('Change material config properties')
|
||||
@ -344,10 +443,11 @@ class TextureGroupMaterialConfig {
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
new Property(TextureGroupMaterialConfig, 'vector4', 'color_value');
|
||||
new Property(TextureGroupMaterialConfig, 'vector4', 'color_value', {default: [255, 255, 255, 255]});
|
||||
new Property(TextureGroupMaterialConfig, 'vector', 'mer_value');
|
||||
new Property(TextureGroupMaterialConfig, 'boolean', 'saved', {default: true});
|
||||
TextureGroupMaterialConfig.prototype.menu = new Menu('texture_group_material_config', [
|
||||
'generate_pbr_map',
|
||||
new MenuSeparator('file'),
|
||||
{
|
||||
icon: 'folder',
|
||||
@ -472,4 +572,117 @@ BARS.defineActions(function() {
|
||||
Undo.finishEdit('Add texture group', {texture_groups: [texture_group], textures: textures_to_add});
|
||||
}
|
||||
})
|
||||
});
|
||||
new Action('create_material', {
|
||||
icon: 'lightbulb_circle',
|
||||
category: 'textures',
|
||||
click() {
|
||||
let texture = Texture.selected;
|
||||
let texture_group = new TextureGroup({is_material: true});
|
||||
texture_group.name = (texture?.name || 'New') + ' material';
|
||||
let textures_to_add = Texture.all.filter(tex => tex.selected || tex.multi_selected);
|
||||
Undo.initEdit({texture_groups: [], textures: textures_to_add});
|
||||
for (let texture of textures_to_add) {
|
||||
texture.group = texture_group.uuid;
|
||||
if (texture != Texture.selected) {
|
||||
console.log(texture.name)
|
||||
if (texture.name.match(/height/i)) {
|
||||
texture.pbr_channel = 'height';
|
||||
} else if (texture.name.match(/[._-]normal/i)) {
|
||||
texture.pbr_channel = 'normal';
|
||||
} else if (texture.name.match(/[._-]mer[._-]/i)) {
|
||||
texture.pbr_channel = 'mer';
|
||||
}
|
||||
}
|
||||
}
|
||||
texture_group.add(false);
|
||||
Undo.finishEdit('Add material', {texture_groups: [texture_group], textures: textures_to_add});
|
||||
}
|
||||
})
|
||||
new Action('generate_pbr_map', {
|
||||
icon: 'texture_add',
|
||||
category: 'textures',
|
||||
condition: () => Texture.selected,
|
||||
click() {
|
||||
let texture = Texture.selected;
|
||||
let texture_group = texture.getGroup();
|
||||
|
||||
let canvas = document.createElement('canvas');
|
||||
let ctx = canvas.getContext('2d');
|
||||
canvas.width = texture.width;
|
||||
canvas.height = texture.height;
|
||||
let original_data = texture.canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
|
||||
let new_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
canvas.style.width = 256 + 'px';
|
||||
let original_image = new CanvasFrame(texture.canvas);
|
||||
|
||||
function updateCanvas(result) {
|
||||
ctx.clearRect(canvas.width, canvas.height);
|
||||
for (let i = 0; i < original_data.data.length; i+=4) {
|
||||
let source = [
|
||||
original_data.data[i+0],
|
||||
original_data.data[i+1],
|
||||
original_data.data[i+2],
|
||||
original_data.data[i+3],
|
||||
];
|
||||
if (true) {
|
||||
let value = ((source[0] + source[1] + source[2]) / 3) * source[3];
|
||||
value = Math.clamp(Math.getLerp(result.range[0], result.range[1], value) * 255, 0, 255);
|
||||
new_data.data[i+0] = value;
|
||||
new_data.data[i+1] = value;
|
||||
new_data.data[i+2] = value;
|
||||
new_data.data[i+3] = 255;
|
||||
}
|
||||
}
|
||||
ctx.putImageData(new_data, 0, 0);
|
||||
}
|
||||
|
||||
new Dialog('generate_pbr_map', {
|
||||
title: 'dialog.generate_pbr_map.title',
|
||||
form: {
|
||||
channel: {
|
||||
type: 'select',
|
||||
options: {
|
||||
normal: 'menu.texture.pbr_channel.normal',
|
||||
height: 'menu.texture.pbr_channel.height',
|
||||
metalness: 'Metalness',
|
||||
emissive: 'Emissive',
|
||||
roughness: 'Roughness',
|
||||
}
|
||||
},
|
||||
method: {
|
||||
type: 'select',
|
||||
options: {
|
||||
value: 'Value',
|
||||
saturation: 'Value',
|
||||
}
|
||||
},
|
||||
range: {
|
||||
type: 'vector',
|
||||
dimensions: 2, min: 0, max: 255
|
||||
},
|
||||
invert: {type: 'checkbox', value: false},
|
||||
},
|
||||
lines: [original_image.canvas, canvas],
|
||||
onFormChange(result) {
|
||||
updateCanvas(result)
|
||||
},
|
||||
onConfirm() {
|
||||
updateCanvas(result);
|
||||
let textures = [];
|
||||
Undo.initEdit({texture_groups: [texture_group], textures});
|
||||
let pbr_channel = form.channel;
|
||||
let texture = new Texture({
|
||||
name: texture.name,
|
||||
pbr_channel,
|
||||
group: texture_group.uuid,
|
||||
}).fromDataURL(canvas.toDataURL()).add(false);
|
||||
textures.push(texture)
|
||||
Undo.finishEdit('Add material', {texture_groups: [texture_group], textures: textures_to_add});
|
||||
}
|
||||
}).show();
|
||||
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -734,6 +734,13 @@ class Texture {
|
||||
|
||||
// Map
|
||||
mat.map.needsUpdate = true;
|
||||
|
||||
// PBR material
|
||||
if (this.group && (this.pbr_channel == 'mer' || this.pbr_channel == 'height') && this.getGroup()?.is_material && BarItems.view_mode.value == 'material') {
|
||||
setTimeout(() => {
|
||||
this.getGroup()?.updateMaterial();
|
||||
}, 40);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
reopen(force) {
|
||||
@ -913,7 +920,7 @@ class Texture {
|
||||
Texture.all.forEach(s => {
|
||||
if (s.selected) s.selected = false;
|
||||
if (s.multi_selected) s.multi_selected = false;
|
||||
})
|
||||
});
|
||||
this.selected = true;
|
||||
Texture.selected = this;
|
||||
Texture.last_selected = Texture.all.indexOf(this);
|
||||
@ -931,7 +938,14 @@ class Texture {
|
||||
Canvas.updateAllFaces()
|
||||
}
|
||||
updateSelection()
|
||||
if ((Texture.all.length > 1 || !Format.edit_mode) && Modes.paint && !UVEditor.getReferenceFace()) {
|
||||
if (
|
||||
(Texture.all.length > 1 || !Format.edit_mode) &&
|
||||
Modes.paint &&
|
||||
(
|
||||
!UVEditor.getReferenceFace() ||
|
||||
(BarItems.view_mode.value == 'material' && UVEditor.getReferenceFace().getTexture()?.getGroup()?.getTextures()?.includes(this))
|
||||
)
|
||||
) {
|
||||
UVEditor.vue.updateTexture();
|
||||
}
|
||||
Panels.layers.inside_vue.layers = this.layers;
|
||||
@ -1909,6 +1923,7 @@ class Texture {
|
||||
},
|
||||
'resize_texture',
|
||||
'animated_texture_editor',
|
||||
'create_material',
|
||||
'append_to_template',
|
||||
{
|
||||
name: 'menu.texture.merge_onto_texture',
|
||||
|
@ -2457,6 +2457,11 @@ Interface.definePanels(function() {
|
||||
}
|
||||
if (texture === null) {
|
||||
this.texture = null;
|
||||
} else if (texture instanceof Texture && BarItems.view_mode.value == 'material' && texture?.getGroup()?.getTextures()?.includes(Texture.selected)) {
|
||||
this.texture = texture = Texture.selected;
|
||||
if (!UVEditor.isBoxUV() && UVEditor.auto_grid) {
|
||||
UVEditor.grid = texture.width / UVEditor.getUVWidth();
|
||||
}
|
||||
} else if (texture instanceof Texture) {
|
||||
this.texture = texture;
|
||||
if (!UVEditor.isBoxUV() && UVEditor.auto_grid) {
|
||||
|
@ -501,7 +501,9 @@
|
||||
|
||||
"dialog.material_config.title": "Material Config",
|
||||
"dialog.material_config.color_value": "Color Value",
|
||||
"dialog.material_config.mer_value": "Metal-Emissive-Roughness",
|
||||
"dialog.material_config.mer": "Metal-Emissive-Roughness",
|
||||
"dialog.material_config.mer_value": "MER Value",
|
||||
"dialog.material_config.depth_type": "Depth Type",
|
||||
|
||||
"dialog.edit_texture.preview": "Preview",
|
||||
|
||||
@ -1725,6 +1727,8 @@
|
||||
"action.create_texture.desc": "Create a blank texture or template texture",
|
||||
"action.create_texture_group": "Create Texture Group",
|
||||
"action.create_texture_group.desc": "Create a group for your textures",
|
||||
"action.create_material": "Create Material",
|
||||
"action.create_material.desc": "Create a new PBR material out of the selected texture",
|
||||
"action.append_to_template": "Append Elements to Template...",
|
||||
"action.append_to_template.desc": "Add the currently selected elements to the texture template",
|
||||
"action.save_textures": "Save Textures",
|
||||
|
Loading…
x
Reference in New Issue
Block a user