Fixed lighting for transparent blocks, added emissive blocks

This commit is contained in:
Lucas Dower 2022-10-23 03:50:04 +01:00
parent 546df638cb
commit eb4ab21f4e
7 changed files with 204 additions and 116 deletions

View File

@ -1,7 +1,7 @@
{
"AMBIENT_OCCLUSION_OVERRIDE_CORNER": true,
"LOG_TO_FILE": true,
"USE_WORKER_THREAD": false,
"USE_WORKER_THREAD": true,
"MULTISAMPLE_COUNT": 16,
"OLD_SPACE_SIZE_MB": 8192,
"ALPHA_BIAS": 1.0,

15
res/emissive_blocks.json Normal file
View File

@ -0,0 +1,15 @@
{
"emissive_blocks": [
"minecraft:respawn_anchor",
"minecraft:magma_block",
"minecraft:sculk_catalyst",
"minecraft:crying_obsidian",
"minecraft:shroomlight",
"minecraft:sea_lantern",
"minecraft:jack_o_lantern",
"minecraft:glowstone",
"minecraft:pearlescent_froglight",
"minecraft:verdant_froglight",
"minecraft:ochre_froglight"
]
}

View File

@ -1,85 +1,86 @@
{
"version": 1,
"blocks": [
"minecraft:black_concrete",
"minecraft:black_concrete_powder",
"minecraft:black_glazed_terracotta",
"minecraft:black_terracotta",
"minecraft:black_wool",
"minecraft:blue_concrete",
"minecraft:blue_concrete_powder",
"minecraft:blue_glazed_terracotta",
"minecraft:blue_terracotta",
"minecraft:blue_wool",
"minecraft:brown_concrete",
"minecraft:brown_concrete_powder",
"minecraft:brown_glazed_terracotta",
"minecraft:brown_terracotta",
"minecraft:brown_wool",
"minecraft:cyan_concrete",
"minecraft:cyan_concrete_powder",
"minecraft:cyan_glazed_terracotta",
"minecraft:cyan_terracotta",
"minecraft:cyan_wool",
"minecraft:gray_concrete",
"minecraft:gray_concrete_powder",
"minecraft:gray_glazed_terracotta",
"minecraft:gray_terracotta",
"minecraft:gray_wool",
"minecraft:green_concrete",
"minecraft:green_concrete_powder",
"minecraft:green_glazed_terracotta",
"minecraft:green_terracotta",
"minecraft:green_wool",
"minecraft:light_blue_concrete",
"minecraft:light_blue_concrete_powder",
"minecraft:light_blue_glazed_terracotta",
"minecraft:light_blue_terracotta",
"minecraft:light_blue_wool",
"minecraft:light_gray_concrete",
"minecraft:light_gray_concrete_powder",
"minecraft:light_gray_glazed_terracotta",
"minecraft:light_gray_terracotta",
"minecraft:light_gray_wool",
"minecraft:lime_concrete",
"minecraft:lime_concrete_powder",
"minecraft:lime_glazed_terracotta",
"minecraft:lime_terracotta",
"minecraft:lime_wool",
"minecraft:magenta_concrete",
"minecraft:magenta_concrete_powder",
"minecraft:magenta_glazed_terracotta",
"minecraft:magenta_terracotta",
"minecraft:magenta_wool",
"minecraft:orange_concrete",
"minecraft:orange_concrete_powder",
"minecraft:orange_glazed_terracotta",
"minecraft:orange_terracotta",
"minecraft:orange_wool",
"minecraft:pink_concrete",
"minecraft:pink_concrete_powder",
"minecraft:pink_glazed_terracotta",
"minecraft:pink_terracotta",
"minecraft:pink_wool",
"minecraft:purple_concrete",
"minecraft:purple_concrete_powder",
"minecraft:purple_glazed_terracotta",
"minecraft:purple_terracotta",
"minecraft:purple_wool",
"minecraft:red_concrete",
"minecraft:red_concrete_powder",
"minecraft:red_glazed_terracotta",
"minecraft:red_terracotta",
"minecraft:red_wool",
"minecraft:white_concrete",
"minecraft:white_concrete_powder",
"minecraft:white_glazed_terracotta",
"minecraft:white_terracotta",
"minecraft:white_wool",
"minecraft:yellow_concrete",
"minecraft:yellow_concrete_powder",
"minecraft:yellow_glazed_terracotta",
"minecraft:yellow_terracotta",
"minecraft:yellow_wool"
"black_concrete",
"black_concrete_powder",
"black_glazed_terracotta",
"black_terracotta",
"black_wool",
"blue_concrete",
"blue_concrete_powder",
"blue_glazed_terracotta",
"blue_terracotta",
"blue_wool",
"brown_concrete",
"brown_concrete_powder",
"brown_glazed_terracotta",
"brown_terracotta",
"brown_wool",
"cyan_concrete",
"cyan_concrete_powder",
"cyan_glazed_terracotta",
"cyan_terracotta",
"cyan_wool",
"gray_concrete",
"gray_concrete_powder",
"gray_glazed_terracotta",
"gray_terracotta",
"gray_wool",
"green_concrete",
"green_concrete_powder",
"green_glazed_terracotta",
"green_terracotta",
"green_wool",
"light_blue_concrete",
"light_blue_concrete_powder",
"light_blue_glazed_terracotta",
"light_blue_terracotta",
"light_blue_wool",
"light_gray_concrete",
"light_gray_concrete_powder",
"light_gray_glazed_terracotta",
"light_gray_terracotta",
"light_gray_wool",
"lime_concrete",
"lime_concrete_powder",
"lime_glazed_terracotta",
"lime_terracotta",
"lime_wool",
"magenta_concrete",
"magenta_concrete_powder",
"magenta_glazed_terracotta",
"magenta_terracotta",
"magenta_wool",
"orange_concrete",
"orange_concrete_powder",
"orange_glazed_terracotta",
"orange_terracotta",
"orange_wool",
"pink_concrete",
"pink_concrete_powder",
"pink_glazed_terracotta",
"pink_terracotta",
"pink_wool",
"purple_concrete",
"purple_concrete_powder",
"purple_glazed_terracotta",
"purple_terracotta",
"purple_wool",
"red_concrete",
"red_concrete_powder",
"red_glazed_terracotta",
"red_terracotta",
"red_wool",
"white_concrete",
"white_concrete_powder",
"white_glazed_terracotta",
"white_terracotta",
"white_wool",
"yellow_concrete",
"yellow_concrete_powder",
"yellow_glazed_terracotta",
"yellow_terracotta",
"yellow_wool",
"glowstone",
"sea_lantern"
]
}

View File

@ -0,0 +1,34 @@
{
"transparent_blocks": [
"minecraft:frosted_ice",
"minecraft:glass",
"minecraft:white_stained_glass",
"minecraft:orange_stained_glass",
"minecraft:magenta_stained_glass",
"minecraft:light_blue_stained_glass",
"minecraft:yellow_stained_glass",
"minecraft:lime_stained_glass",
"minecraft:pink_stained_glass",
"minecraft:gray_stained_glass",
"minecraft:light_gray_stained_glass",
"minecraft:cyan_stained_glass",
"minecraft:purple_stained_glass",
"minecraft:blue_stained_glass",
"minecraft:brown_stained_glass",
"minecraft:green_stained_glass",
"minecraft:red_stained_glass",
"minecraft:black_stained_glass",
"minecraft:ice",
"minecraft:oak_leaves",
"minecraft:spruce_leaves",
"minecraft:birch_leaves",
"minecraft:jungle_leaves",
"minecraft:acacia_leaves",
"minecraft:dark_oak_leaves",
"minecraft:mangrove_leaves",
"minecraft:azalea_leaves",
"minecraft:flowering_azalea_leaves",
"minecraft:slime_block",
"minecraft:honey_block"
]
}

View File

@ -8,7 +8,7 @@ import { ChunkedBufferGenerator, TBlockMeshBufferDescription } from './buffer';
import { Palette } from './palette';
import { ProgressManager } from './progress';
import { StatusHandler } from './status';
import { ColourSpace } from './util';
import { ColourSpace, TOptional } from './util';
import { AppError, ASSERT } from './util/error_util';
import { LOGF } from './util/log_util';
import { AppPaths, PathUtil } from './util/path_util';
@ -36,9 +36,11 @@ export class BlockMesh {
private _blocks: Block[];
private _voxelMesh: VoxelMesh;
private _fallableBlocks: string[];
private _transparentBlocks: string[];
private _emissiveBlocks: string[];
private _atlas: Atlas;
private _lightingNew: Array<number>;
private _posToLightingBufferIndex: (vec: Vector3) => number;
private _lightingNew: Buffer;
private _posToLightingBufferIndex: (vec: Vector3) => { index: number, left: boolean };
private _posIsValid: (vec: Vector3) => boolean;
public static createFromVoxelMesh(voxelMesh: VoxelMesh, blockMeshParams: AssignParams.Input) {
@ -54,13 +56,19 @@ export class BlockMesh {
this._voxelMesh = voxelMesh;
this._atlas = Atlas.getVanillaAtlas()!;
//this._lighting = new Map<string, number>();
this._lightingNew = new Array<number>();
this._lightingNew = Buffer.alloc(0);
//this._recreateBuffer = true;
this._posToLightingBufferIndex = () => { return 0; };
this._posToLightingBufferIndex = () => { return { index: 0, left: false }; };
this._posIsValid = () => { return false; };
const fallableBlocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'fallable_blocks.json'), 'utf-8');
this._fallableBlocks = JSON.parse(fallableBlocksString).fallable_blocks;
const transparentlocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'transparent_blocks.json'), 'utf-8');
this._transparentBlocks = JSON.parse(transparentlocksString).transparent_blocks;
const emissivelocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'emissive_blocks.json'), 'utf-8');
this._emissiveBlocks = JSON.parse(emissivelocksString).emissive_blocks;
}
private _assignBlocks(blockMeshParams: AssignParams.Input) {
@ -153,23 +161,41 @@ export class BlockMesh {
];
}
private _internalGetLight(vec: Vector3) {
private _internalGetLight(vec: Vector3): TOptional<number> {
if (this._posIsValid(vec)) {
return this._lightingNew[this._posToLightingBufferIndex(vec)];
const index = this._posToLightingBufferIndex(vec);
const value = this._lightingNew[index.index];
return (index.left ? (value >> 4) : value) & 0xF;
}
return undefined;
}
private _internalSetLight(vec: Vector3, value: number) {
const index = this._posToLightingBufferIndex(vec);
if (index.left) {
this._lightingNew[index.index] = (this._lightingNew[index.index] & 0xF) + (value << 4);
} else {
this._lightingNew[index.index] = (this._lightingNew[index.index] & (0xF << 4)) + value;
}
return 15;
}
private _calculateLighting() {
const blocksBounds = this._voxelMesh.getBounds();
const sizeVector = blocksBounds.getDimensions().add(1).add(2);
this._lightingNew = new Array<number>(sizeVector.x * sizeVector.y * sizeVector.z).fill(0);
// Number of blocks to store lighting values for.
const numBlocks = sizeVector.x * sizeVector.y * sizeVector.z;
// Each block takes up 4-bits
const numBytes = Math.ceil(numBlocks * 0.5);
this._lightingNew = Buffer.alloc(numBytes);
this._posToLightingBufferIndex = (vec: Vector3) => {
const indexVector = Vector3.sub(vec, Vector3.sub(blocksBounds.min, 1));
const index = (sizeVector.z * sizeVector.x * indexVector.y) + (sizeVector.x * indexVector.z) + indexVector.x;
//ASSERT(index >= 0 && index < this._lightingNew.length);
return index;
return {
index: Math.floor(index * 0.5),
left: index % 2 === 0,
};
};
this._posIsValid = (vec: Vector3) => {
@ -194,40 +220,48 @@ export class BlockMesh {
}
while (actions.length > 0) {
const action = actions.pop();
ASSERT(action !== undefined);
const action = actions.pop()!;
const newLightValue = action.value;
if (!this._posIsValid(action.pos)) {
continue;
}
const bufferIndex = this._posToLightingBufferIndex(action.pos);
const currentLightValue = this._lightingNew[bufferIndex] ?? 0;
/*
const currentLightValue = this._lighting.get(action.pos.stringify());
// We're trying to update the lighting value of an out-of-bounds block, skip.
if (currentLightValue === undefined) {
continue;
}
*/
const currentLightValue = this._internalGetLight(action.pos) ?? 0;
// Update lighting values only if the new value is lighter than the current brightness.
if (newLightValue > currentLightValue && !this._voxelMesh.isVoxelAt(action.pos)) {
//this._lighting.set(action.pos.stringify(), newLightValue);
this._lightingNew[bufferIndex] = newLightValue;
//this._lightingNew
const blockHere = this.getBlockAt(action.pos);
if (blockHere !== undefined && this._emissiveBlocks.includes(blockHere.blockInfo.name)) {
if (this._internalGetLight(action.pos)! < 14) {
this._internalSetLight(action.pos, 14);
actions.push({ pos: new Vector3(0, 1, 0).add(action.pos), value: 14 });
actions.push({ pos: new Vector3(1, 0, 0).add(action.pos), value: 14 });
actions.push({ pos: new Vector3(0, 0, 1).add(action.pos), value: 14 });
actions.push({ pos: new Vector3(-1, 0, 0).add(action.pos), value: 14 });
actions.push({ pos: new Vector3(0, 0, -1).add(action.pos), value: 14 });
actions.push({ pos: new Vector3(0, -1, 0).add(action.pos), value: 14 });
}
} else if (newLightValue > currentLightValue) {
if (blockHere === undefined || this._transparentBlocks.includes(blockHere.blockInfo.name)) {
this._internalSetLight(action.pos, newLightValue);
actions.push({ pos: new Vector3(0, 1, 0).add(action.pos), value: newLightValue - 1 }); // up
actions.push({ pos: new Vector3(1, 0, 0).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(0, 0, 1).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(-1, 0, 0).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(0, 0, -1).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(0, -1, 0).add(action.pos), value: newLightValue === 15 ? 15 : newLightValue - 1 }); // down
actions.push({ pos: new Vector3(0, 1, 0).add(action.pos), value: newLightValue - 1 }); // up
actions.push({ pos: new Vector3(1, 0, 0).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(0, 0, 1).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(-1, 0, 0).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(0, 0, -1).add(action.pos), value: newLightValue - 1 });
actions.push({ pos: new Vector3(0, -1, 0).add(action.pos), value: newLightValue === 15 ? 15 : newLightValue - 1 }); // down
}
}
}
}
public getBlockAt(pos: Vector3): TOptional<Block> {
const index = this._voxelMesh.getVoxelIndex(pos);
if (index !== undefined) {
return this._blocks[index];
}
}
public getBlocks(): Block[] {
return this._blocks;
}

View File

@ -153,7 +153,7 @@ export class ChunkedBufferGenerator {
for (let f = 0; f < AppConstants.FACES_PER_VOXEL; ++f) {
const faceName = faceOrder[f];
const faceLighting = lightingRamp.get(blockLighting[f]) ?? 1.0;
const faceLighting = lightingRamp.get(blockLighting[f] ?? 15) ?? 1.0;
const texcoord = blocks[blockIndex].blockInfo.faces[faceName].texcoord;
for (let v = 0; v < AppConstants.VERTICES_PER_FACE; ++v) {

View File

@ -84,6 +84,10 @@ export class VoxelMesh {
return this._bounds;
}
public getVoxelIndex(pos: Vector3) {
return this._voxelsHash.get(pos.stringify());
}
public getVoxelCount() {
return this._voxels.length;
}