mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2025-03-07 14:06:41 +08:00
Added bilinear texture filtering for voxel colours
This commit is contained in:
parent
0537f75169
commit
bb11207e70
@ -8,6 +8,7 @@ import { ASSERT, CustomError, CustomWarning, LOG, LOG_ERROR } from './util';
|
||||
import { remote } from 'electron';
|
||||
import { VoxelMesh } from './voxel_mesh';
|
||||
import { BlockMesh } from './block_mesh';
|
||||
import { TextureFiltering } from './texture';
|
||||
|
||||
/* eslint-disable */
|
||||
export enum ActionReturnType {
|
||||
@ -156,10 +157,11 @@ export class AppContext {
|
||||
const desiredHeight = UI.Get.layout.build.elements.height.getValue();
|
||||
const ambientOcclusion = UI.Get.layout.build.elements.ambientOcclusion.getValue() === 'on';
|
||||
const multisampleColouring = UI.Get.layout.build.elements.multisampleColouring.getValue() === 'on';
|
||||
const textureFiltering = UI.Get.layout.build.elements.textureFiltering.getValue() === 'nearest' ? TextureFiltering.Nearest : TextureFiltering.Linear;
|
||||
|
||||
ASSERT(this._loadedMesh);
|
||||
this._loadedVoxelMesh = new VoxelMesh(desiredHeight);
|
||||
this._loadedVoxelMesh.voxelise(this._loadedMesh, multisampleColouring);
|
||||
this._loadedVoxelMesh.voxelise(this._loadedMesh, multisampleColouring, textureFiltering);
|
||||
|
||||
Renderer.Get.useVoxelMesh(this._loadedVoxelMesh, ambientOcclusion);
|
||||
}
|
||||
|
@ -33,4 +33,9 @@ export const roundToNearest = (value: number, base: number) => {
|
||||
return Math.round(value / base) * base;
|
||||
};
|
||||
|
||||
export const wayThrough = (value: number, min: number, max: number) => {
|
||||
// ASSERT(value >= min && value <= max);
|
||||
return (value - min) / (max - min);
|
||||
};
|
||||
|
||||
export const degreesToRadians = Math.PI / 180;
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { UV, ASSERT, CustomError } from './util';
|
||||
import { UV, ASSERT, CustomError, LOG } from './util';
|
||||
import { RGB } from './util';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as jpeg from 'jpeg-js';
|
||||
import { PNG } from 'pngjs';
|
||||
import path from 'path';
|
||||
import { Vector3 } from './vector';
|
||||
import { clamp, wayThrough } from './math';
|
||||
|
||||
/* eslint-disable */
|
||||
export enum TextureFormat {
|
||||
@ -13,6 +15,13 @@ export enum TextureFormat {
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
/* eslint-disable */
|
||||
export enum TextureFiltering {
|
||||
Linear,
|
||||
Nearest
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
export class Texture {
|
||||
private _image: {
|
||||
data: Buffer,
|
||||
@ -40,10 +49,58 @@ export class Texture {
|
||||
}
|
||||
}
|
||||
|
||||
getRGB(uv: UV): RGB {
|
||||
getRGB(uv: UV, filtering: TextureFiltering): RGB {
|
||||
if (filtering === TextureFiltering.Nearest) {
|
||||
return this._getNearestRGB(uv);
|
||||
} else {
|
||||
return this._getLinearRGB(uv);
|
||||
}
|
||||
}
|
||||
|
||||
private _getLinearRGB(uv: UV): RGB {
|
||||
uv.v = 1.0 - uv.v;
|
||||
if (uv.u === 0 || uv.u === 1 || uv.v === 0 || uv.v === 1) {
|
||||
LOG('bad');
|
||||
}
|
||||
|
||||
const x = uv.u * this._image.width;
|
||||
const y = uv.v * this._image.height;
|
||||
|
||||
const xL = Math.floor(x);
|
||||
const xU = Math.ceil(x);
|
||||
const yL = Math.floor(y);
|
||||
const yU = Math.ceil(y);
|
||||
|
||||
const u = wayThrough(x, xL, xU);
|
||||
const v = wayThrough(y, yL, yU);
|
||||
ASSERT(u >= 0.0 && u <= 1.0 && v >= 0.0 && v <= 1.0);
|
||||
|
||||
const A = this._getFromXY(xL, yU).toVector3();
|
||||
const B = this._getFromXY(xU, yU).toVector3();
|
||||
const midAB = Vector3.mulScalar(B, u).add(Vector3.mulScalar(A, 1.0-u));
|
||||
|
||||
const C = this._getFromXY(xL, yL).toVector3();
|
||||
const D = this._getFromXY(xU, yL).toVector3();
|
||||
const midCD = Vector3.mulScalar(D, u).add(Vector3.mulScalar(C, 1.0-u));
|
||||
|
||||
const mid = Vector3.mulScalar(midAB, v).add(Vector3.mulScalar(midCD, 1.0-v));
|
||||
if (mid.equals(RGB.black.toVector3())) {
|
||||
LOG('bad');
|
||||
}
|
||||
return RGB.fromVector3(mid);
|
||||
}
|
||||
|
||||
private _getNearestRGB(uv: UV): RGB {
|
||||
const x = Math.floor(uv.u * this._image.width);
|
||||
const y = Math.floor((1 - uv.v) * this._image.height);
|
||||
|
||||
return this._getFromXY(x, y);
|
||||
}
|
||||
|
||||
private _getFromXY(x: number, y: number): RGB {
|
||||
x = clamp(x, 0, this._image.width - 1);
|
||||
y = clamp(y, 0, this._image.height - 1);
|
||||
|
||||
const index = 4 * (this._image.width * y + x);
|
||||
const rgba = this._image.data.slice(index, index + 4);
|
||||
|
||||
|
@ -46,12 +46,16 @@ export class UI {
|
||||
{ id: 'on', displayText: 'On (recommended)' },
|
||||
{ id: 'off', displayText: 'Off (faster)' },
|
||||
]),
|
||||
'multisampleColouring': new ComboBoxElement('Multisample Colouring', [
|
||||
'multisampleColouring': new ComboBoxElement('Multisample colouring', [
|
||||
{ id: 'on', displayText: 'On (recommended)' },
|
||||
{ id: 'off', displayText: 'Off (faster)' },
|
||||
]),
|
||||
'textureFiltering': new ComboBoxElement('Texture filtering', [
|
||||
{ id: 'linear', displayText: 'Linear (recommended)' },
|
||||
{ id: 'nearest', displayText: 'Nearest (faster)' },
|
||||
]),
|
||||
},
|
||||
elementsOrder: ['height', 'ambientOcclusion', 'multisampleColouring'],
|
||||
elementsOrder: ['height', 'ambientOcclusion', 'multisampleColouring', 'textureFiltering'],
|
||||
submitButton: new ButtonElement('Voxelise mesh', () => {
|
||||
AppContext.Get.do(Action.Voxelise);
|
||||
}),
|
||||
|
@ -5,7 +5,7 @@ import { HashMap } from './hash_map';
|
||||
import { MaterialType, Mesh, SolidMaterial, TexturedMaterial } from './mesh';
|
||||
import { OcclusionManager } from './occlusion';
|
||||
import { Axes, generateRays, rayIntersectTriangle } from './ray';
|
||||
import { Texture } from './texture';
|
||||
import { Texture, TextureFiltering } from './texture';
|
||||
import { Triangle, UVTriangle } from './triangle';
|
||||
import { Bounds, LOG, RGB, UV } from './util';
|
||||
import { Vector3 } from './vector';
|
||||
@ -41,7 +41,7 @@ export class VoxelMesh {
|
||||
return this._voxelsHash.has(pos);
|
||||
}
|
||||
|
||||
public voxelise(mesh: Mesh, multisampleColouring: boolean) {
|
||||
public voxelise(mesh: Mesh, multisampleColouring: boolean, filtering: TextureFiltering) {
|
||||
LOG('Voxelising');
|
||||
|
||||
mesh.tris.forEach((tri, index) => {
|
||||
@ -52,11 +52,11 @@ export class VoxelMesh {
|
||||
}
|
||||
}
|
||||
const uvTriangle = mesh.getUVTriangle(index);
|
||||
this._voxeliseTri(uvTriangle, material, tri.material, multisampleColouring);
|
||||
this._voxeliseTri(uvTriangle, material, tri.material, multisampleColouring, filtering);
|
||||
});
|
||||
}
|
||||
|
||||
private _voxeliseTri(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, multisampleColouring: boolean) {
|
||||
private _voxeliseTri(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, multisampleColouring: boolean, filtering: TextureFiltering) {
|
||||
const v0Scaled = Vector3.divScalar(triangle.v0, this._voxelSize);
|
||||
const v1Scaled = Vector3.divScalar(triangle.v1, this._voxelSize);
|
||||
const v2Scaled = Vector3.divScalar(triangle.v2, this._voxelSize);
|
||||
@ -83,18 +83,18 @@ export class VoxelMesh {
|
||||
const samples: RGB[] = [];
|
||||
for (let i = 0; i < AppConfig.MULTISAMPLE_COUNT; ++i) {
|
||||
const samplePosition = Vector3.mulScalar(Vector3.add(voxelPosition, Vector3.random().addScalar(-0.5)), this._voxelSize);
|
||||
samples.push(this._getVoxelColour(triangle, material, materialName, samplePosition));
|
||||
samples.push(this._getVoxelColour(triangle, material, materialName, samplePosition, filtering));
|
||||
}
|
||||
voxelColour = RGB.averageFrom(samples);
|
||||
} else {
|
||||
voxelColour = this._getVoxelColour(triangle, material, materialName, Vector3.mulScalar(voxelPosition, this._voxelSize));
|
||||
voxelColour = this._getVoxelColour(triangle, material, materialName, Vector3.mulScalar(voxelPosition, this._voxelSize), filtering);
|
||||
}
|
||||
this._addVoxel(voxelPosition, voxelColour);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _getVoxelColour(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, location: Vector3): RGB {
|
||||
private _getVoxelColour(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, location: Vector3, filtering: TextureFiltering): RGB {
|
||||
if (material.type == MaterialType.solid) {
|
||||
return material.colour;
|
||||
}
|
||||
@ -113,7 +113,7 @@ export class VoxelMesh {
|
||||
triangle.uv0.v * w0 + triangle.uv1.v * w1 + triangle.uv2.v * w2,
|
||||
);
|
||||
|
||||
return this._loadedTextures[materialName].getRGB(uv);
|
||||
return this._loadedTextures[materialName].getRGB(uv, filtering);
|
||||
}
|
||||
|
||||
private _addVoxel(pos: Vector3, colour: RGB) {
|
||||
|
Loading…
Reference in New Issue
Block a user