mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-04-06 17:31:09 +08:00
PBR progress
This commit is contained in:
parent
25ae6a5046
commit
a2b55e826b
@ -7,6 +7,13 @@ function setupDragHandlers() {
|
||||
loadImages(files, event)
|
||||
}
|
||||
)
|
||||
Blockbench.addDragHandler(
|
||||
'texture_set',
|
||||
{extensions: ['texture_set.json'], propagate: true, readtype: 'image', condition: () => !Dialog.open},
|
||||
function(files, event) {
|
||||
importTextureSet(files[0]);
|
||||
}
|
||||
)
|
||||
Blockbench.addDragHandler(
|
||||
'reference_image',
|
||||
{extensions: ReferenceImage.supported_extensions, propagate: true, readtype: 'image', condition: () => Project && !Dialog.open},
|
||||
|
@ -854,6 +854,10 @@ const Canvas = {
|
||||
}
|
||||
Blockbench.dispatchEvent('update_view', options);
|
||||
},
|
||||
updateViewMode() {
|
||||
this.updateAllFaces();
|
||||
this.updateShading();
|
||||
},
|
||||
//Main updaters
|
||||
clear() {
|
||||
var objects = []
|
||||
|
@ -2068,28 +2068,51 @@ function animate() {
|
||||
|
||||
function updateShading() {
|
||||
Canvas.updateLayeredTextures();
|
||||
scene.remove(lights)
|
||||
Sun.intensity = settings.brightness.value/50;
|
||||
if (settings.shading.value === true) {
|
||||
Sun.intensity *= 0.5;
|
||||
let parent = scene;
|
||||
parent.add(lights);
|
||||
lights.position.copy(parent.position).multiplyScalar(-1);
|
||||
scene.remove(lights);
|
||||
let settings_brightness = settings.brightness.value/50;
|
||||
Sun.intensity = settings_brightness;
|
||||
let view_mode = window.BarItems ? BarItems.view_mode.value : 'textured';
|
||||
|
||||
if (view_mode == 'material') {
|
||||
|
||||
let light = Canvas.material_light ?? new THREE.DirectionalLight(0xffffca, 0.7 * settings_brightness);
|
||||
Canvas.material_light = light;
|
||||
scene.add(light);
|
||||
light.position.y = 100
|
||||
light.position.x = 60
|
||||
light.position.z = 2
|
||||
|
||||
scene.add(Sun);
|
||||
Sun.intensity *= 0.3;
|
||||
|
||||
TextureGroup.all.forEach(tg => {
|
||||
if (tg.is_material) tg.updateMaterial();
|
||||
})
|
||||
|
||||
} else {
|
||||
if (settings.shading.value === true) {
|
||||
Sun.intensity *= 0.5;
|
||||
let parent = scene;
|
||||
parent.add(lights);
|
||||
lights.position.copy(parent.position).multiplyScalar(-1);
|
||||
}
|
||||
lights.add(Sun);
|
||||
Texture.all.forEach(tex => {
|
||||
let material = tex.getMaterial();
|
||||
if (!material.uniforms) return;
|
||||
material.uniforms.SHADE.value = settings.shading.value;
|
||||
material.uniforms.LIGHTCOLOR.value.copy(Canvas.global_light_color).multiplyScalar(settings.brightness.value / 50);
|
||||
material.uniforms.LIGHTSIDE.value = Canvas.global_light_side;
|
||||
})
|
||||
Canvas.emptyMaterials.forEach(material => {
|
||||
material.uniforms.SHADE.value = settings.shading.value;
|
||||
material.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
||||
})
|
||||
Canvas.coloredSolidMaterials.forEach(material => {
|
||||
material.uniforms.SHADE.value = settings.shading.value;
|
||||
material.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
||||
})
|
||||
}
|
||||
Texture.all.forEach(tex => {
|
||||
let material = tex.getMaterial();
|
||||
material.uniforms.SHADE.value = settings.shading.value;
|
||||
material.uniforms.LIGHTCOLOR.value.copy(Canvas.global_light_color).multiplyScalar(settings.brightness.value / 50);
|
||||
material.uniforms.LIGHTSIDE.value = Canvas.global_light_side;
|
||||
})
|
||||
Canvas.emptyMaterials.forEach(material => {
|
||||
material.uniforms.SHADE.value = settings.shading.value;
|
||||
material.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
||||
})
|
||||
Canvas.coloredSolidMaterials.forEach(material => {
|
||||
material.uniforms.SHADE.value = settings.shading.value;
|
||||
material.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
||||
})
|
||||
Canvas.monochromaticSolidMaterial.uniforms.SHADE.value = settings.shading.value;
|
||||
Canvas.monochromaticSolidMaterial.uniforms.BRIGHTNESS.value = settings.brightness.value / 50;
|
||||
Canvas.uvHelperMaterial.uniforms.SHADE.value = settings.shading.value;
|
||||
@ -2118,10 +2141,11 @@ BARS.defineActions(function() {
|
||||
wireframe: {name: true, icon: 'far.fa-square', condition: () => (!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('wireframe'))},
|
||||
uv: {name: true, icon: 'grid_guides', condition: () => (!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('uv'))},
|
||||
normal: {name: true, icon: 'fa-square-caret-up', condition: () => ((!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('normal')) && Mesh.all.length)},
|
||||
material: {name: true, icon: 'pages', condition: () => ((!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('normal')) && TextureGroup.all.find(tg => tg.is_material))},
|
||||
},
|
||||
onChange() {
|
||||
Project.view_mode = this.value;
|
||||
Canvas.updateAllFaces();
|
||||
Canvas.updateViewMode();
|
||||
if (Modes.id === 'animate') {
|
||||
Animator.preview();
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ const Painter = {
|
||||
|
||||
callback(canvas, Painter.current);
|
||||
|
||||
Blockbench.dispatchEvent('edit_texture', {texture, options, canvas, ctx, offset});
|
||||
|
||||
if (options.use_cache && options.no_update === true) {
|
||||
return;
|
||||
}
|
||||
@ -2217,7 +2219,7 @@ BARS.defineActions(function() {
|
||||
cursor: 'grab',
|
||||
selectFace: false,
|
||||
transformerMode: 'hidden',
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
condition: Blockbench.isMobile && {modes: ['paint']}
|
||||
})
|
||||
@ -2293,7 +2295,7 @@ BARS.defineActions(function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
keybind: new Keybind({key: 'b'}),
|
||||
modes: ['paint'],
|
||||
side_menu: new Menu('brush_tool', () => {
|
||||
@ -2443,7 +2445,7 @@ BARS.defineActions(function() {
|
||||
return result_color;
|
||||
}
|
||||
},
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
onCanvasClick(data) {
|
||||
Painter.startPaintToolCanvas(data, data.event);
|
||||
@ -2472,7 +2474,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
onCanvasClick: function(data) {
|
||||
Painter.startPaintToolCanvas(data, data.event)
|
||||
@ -2522,7 +2524,7 @@ BARS.defineActions(function() {
|
||||
return pxcolor;
|
||||
}
|
||||
},
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
keybind: new Keybind({key: 'e'}),
|
||||
onCanvasClick: function(data) {
|
||||
@ -2544,7 +2546,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
onCanvasClick(data) {
|
||||
Painter.startPaintToolCanvas(data, data.event)
|
||||
@ -2572,7 +2574,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
condition: {modes: ['paint']},
|
||||
keybind: new Keybind({key: 'u'}),
|
||||
@ -2596,7 +2598,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
condition: {modes: ['paint']},
|
||||
//keybind: new Keybind({key: 'u'}),
|
||||
@ -2620,7 +2622,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
condition: {modes: ['paint']},
|
||||
keybind: new Keybind({key: 'm'}),
|
||||
@ -2650,7 +2652,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
keybind: new Keybind({key: 'm'}, {
|
||||
create: '',
|
||||
@ -2725,7 +2727,7 @@ BARS.defineActions(function() {
|
||||
selectFace: true,
|
||||
transformerMode: 'hidden',
|
||||
paintTool: true,
|
||||
allowed_view_modes: ['textured'],
|
||||
allowed_view_modes: ['textured', 'material'],
|
||||
modes: ['paint'],
|
||||
keybind: new Keybind({shift: true, key: 'v'}),
|
||||
onCanvasClick(data) {
|
||||
|
@ -100,22 +100,44 @@ class TextureGroup {
|
||||
|
||||
} else if (height_tex) {
|
||||
material.bumpMap = height_tex.getOwnMaterial().map;
|
||||
material.bumpScale = 0.4;
|
||||
material.normalMap = null;
|
||||
// Bump map scale
|
||||
let canvas = document.createElement('canvas');
|
||||
let ctx = canvas.getContext('2d');
|
||||
canvas.width = height_tex.width * 8;
|
||||
canvas.height = height_tex.height * 8;
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
ctx.drawImage(height_tex.canvas, 0, 0, canvas.width, canvas.height);
|
||||
material.bumpMap.image = canvas;
|
||||
material.bumpMap.magFilter = THREE.LinearFilter;
|
||||
material.bumpMap.needsUpdate = true;
|
||||
}
|
||||
if (mer_tex && mer_tex.img?.naturalWidth) {
|
||||
let image_data = mer_tex.canvas.getContext('2d').getImageData(0, 0, mer_tex.width, mer_tex.height);
|
||||
let image_data_albedo = color_tex.canvas.getContext('2d').getImageData(0, 0, color_tex.width, color_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.fillStyle = 'black';
|
||||
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];
|
||||
if (target_channel == 0) {
|
||||
let value = image_data.data[i + source_channel] / 255;
|
||||
image_data_new.data[i + 0] = image_data_albedo.data[i + 0] * value;
|
||||
image_data_new.data[i + 1] = image_data_albedo.data[i + 1] * value;
|
||||
image_data_new.data[i + 2] = image_data_albedo.data[i + 2] * value;
|
||||
} else {
|
||||
image_data_new.data[i + target_channel] = image_data.data[i + source_channel];
|
||||
if (source_channel == 2 && image_data_new.data[i + target_channel] == 0) {
|
||||
//image_data_new.data[i + target_channel] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.putImageData(image_data_new, 0, 0);
|
||||
|
||||
@ -123,10 +145,14 @@ class TextureGroup {
|
||||
material[key] = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
|
||||
material[key].needsUpdate = true;
|
||||
}
|
||||
//material.map = material[key];
|
||||
}
|
||||
generateMap(0, 2, 'metalnessMap');
|
||||
generateMap(1, 0, 'emissiveMap');
|
||||
generateMap(2, 1, 'roughnessMap');
|
||||
material.emissive.set(0xffffff);
|
||||
material.emissiveIntensity = 30;
|
||||
material.metalness = 1;
|
||||
}
|
||||
material.needsUpdate = true;
|
||||
}
|
||||
@ -178,6 +204,52 @@ ToDo:
|
||||
- Search
|
||||
*/
|
||||
|
||||
Blockbench.on('edit_texture', ({texture}) => {
|
||||
if (texture.pbr_channel == 'mer' && texture.getGroup()?.is_material && BarItems.view_mode.value == 'material') {
|
||||
texture.getGroup().updateMaterial();
|
||||
}
|
||||
})
|
||||
|
||||
function importTextureSet(file) {
|
||||
let new_textures = [], new_texture_groups = [];
|
||||
Undo.initEdit({textures: new_textures, texture_groups: new_texture_groups});
|
||||
if (file.name.endsWith('texture_set.json')) {
|
||||
let texture_group = new TextureGroup({is_material: true});
|
||||
texture_group.name = file.name.replace('.texture_set.json', '');
|
||||
|
||||
let content = fs.readFileSync(file.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(file.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);
|
||||
}
|
||||
Undo.finishEdit('Import texture set');
|
||||
}
|
||||
|
||||
SharedActions.add('rename', {
|
||||
condition: () => Prop.active_panel == 'textures' && TextureGroup.active_menu_group,
|
||||
run() {
|
||||
|
@ -882,7 +882,7 @@ class Texture {
|
||||
}
|
||||
getMaterial() {
|
||||
let group = this.getGroup();
|
||||
if (group?.is_material) {
|
||||
if (group?.is_material && BarItems.view_mode.value == 'material') {
|
||||
return group.getMaterial();
|
||||
}
|
||||
return Project.materials[this.uuid];
|
||||
@ -2271,52 +2271,21 @@ BARS.defineActions(function() {
|
||||
multiple: true,
|
||||
startpath: start_path
|
||||
}, function(files) {
|
||||
if (files[0].name.endsWith('texture_set.json')) {
|
||||
importTextureSet(files[0]);
|
||||
return;
|
||||
}
|
||||
let new_textures = [], new_texture_groups = [];
|
||||
let texture_group = context instanceof TextureGroup ? context : Texture.selected?.getGroup();
|
||||
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) {
|
||||
t.group = texture_group.uuid;
|
||||
}
|
||||
})
|
||||
Undo.finishEdit('Add texture')
|
||||
Undo.finishEdit('Add texture');
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1673,6 +1673,7 @@
|
||||
"action.view_mode.wireframe": "Wireframe",
|
||||
"action.view_mode.uv": "UV Preview",
|
||||
"action.view_mode.normal": "Face Orientation",
|
||||
"action.view_mode.material": "Material Preview",
|
||||
"action.preview_scene": "Preview Scene",
|
||||
"action.preview_scene.desc": "Change the model preview scene",
|
||||
"action.screenshot_model": "Screenshot Model",
|
||||
|
Loading…
x
Reference in New Issue
Block a user