mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2024-12-15 02:59:55 +08:00
Added Minecraft-esque ambient occlusion & lighting
This commit is contained in:
parent
3f60531fcd
commit
6dedc11c88
22
shaders/ao_fragment.fs
Normal file
22
shaders/ao_fragment.fs
Normal file
@ -0,0 +1,22 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 v_colour;
|
||||
varying vec4 v_occlusion;
|
||||
varying vec2 v_texcoord;
|
||||
|
||||
|
||||
void main() {
|
||||
float u = v_texcoord.x;
|
||||
float v = v_texcoord.y;
|
||||
|
||||
float a = v_occlusion.x;
|
||||
float b = v_occlusion.y;
|
||||
float c = v_occlusion.z;
|
||||
float d = v_occlusion.w;
|
||||
|
||||
float g = v*(u*b + (1.0-u)*d) + (1.0-v)*(u*a + (1.0-u)*c);
|
||||
|
||||
gl_FragColor = vec4(v_colour.xyz * g, 1.0);
|
||||
//gl_FragColor = vec4(v_colour.xyz, 1.0);
|
||||
//gl_FragColor = vec4(vec3(g), 1.0);
|
||||
}
|
23
shaders/ao_vertex.vs
Normal file
23
shaders/ao_vertex.vs
Normal file
@ -0,0 +1,23 @@
|
||||
uniform mat4 u_worldViewProjection;
|
||||
|
||||
attribute vec4 position;
|
||||
attribute vec3 normal;
|
||||
attribute vec4 occlusion;
|
||||
attribute vec2 texcoord;
|
||||
|
||||
varying vec4 v_colour;
|
||||
varying vec4 v_occlusion;
|
||||
varying vec2 v_texcoord;
|
||||
|
||||
vec3 light = vec3(0.78, 0.98, 0.59);
|
||||
|
||||
|
||||
void main() {
|
||||
v_texcoord = texcoord;
|
||||
v_occlusion = occlusion;
|
||||
//float lighting = dot(light, abs(normal)) * (1.0 - occlusion * 0.2);
|
||||
//float lighting = 0.2 * occlusion;
|
||||
//v_colour = vec4(abs(normal), 1.0);
|
||||
v_colour = vec4(vec3(dot(light, abs(normal))), 1.0);
|
||||
gl_Position = u_worldViewProjection * vec4(position.xyz, 1.0);
|
||||
}
|
@ -7,13 +7,16 @@ const { Schematic } = require('./src/schematic.js');
|
||||
const dialog = require('electron').remote.dialog;
|
||||
|
||||
const voxelSize = document.querySelector("#voxelInput").value;
|
||||
let renderer = new Renderer(30, new Vector3(0.1, 0.1, 0.1));
|
||||
|
||||
let renderer = new Renderer(30, new Vector3(0.1, 0.1, 0.1));
|
||||
const voxelManager = new VoxelManager(voxelSize);
|
||||
const canvas = document.querySelector("#c");
|
||||
|
||||
let loadedMesh = null;
|
||||
//const mesh = new Mesh('./resources/suzanne.obj');
|
||||
//renderer.registerMesh(mesh);
|
||||
//renderer.compile();
|
||||
|
||||
let loadedMesh = null;
|
||||
|
||||
|
||||
function showToastWithText(text, style) {
|
||||
@ -48,8 +51,10 @@ $("#loadBtn").on("click", () => {
|
||||
}
|
||||
|
||||
renderer.clear();
|
||||
//renderer.setDebug(true);
|
||||
renderer.registerMesh(loadedMesh);
|
||||
renderer.compile();
|
||||
console.log(renderer);
|
||||
|
||||
$('#voxelInput').prop('disabled', false);
|
||||
$('#voxelBtn').prop('disabled', false);
|
||||
@ -115,6 +120,7 @@ $("#voxelBtn").on("click", () => {
|
||||
});
|
||||
|
||||
|
||||
// SPLIT BUTTON
|
||||
$("#splitBtn").on("click", () => {
|
||||
const voxelSize = $("#voxelInput").prop('value');
|
||||
$("#voxelInput").prop('value', voxelSize / 2);
|
||||
@ -127,7 +133,6 @@ $("#splitBtn").on("click", () => {
|
||||
});
|
||||
|
||||
|
||||
|
||||
// EXPORT SCHEMATIC
|
||||
$("#exportBtn").on("click", async () => {
|
||||
|
||||
|
@ -70,12 +70,14 @@ class GeometryTemplates {
|
||||
let cube = {
|
||||
position: new Float32Array(72),
|
||||
normal: new Float32Array(72),
|
||||
indices: new Float32Array(72)
|
||||
indices: new Float32Array(72),
|
||||
texcoord: new Float32Array(48)
|
||||
};
|
||||
|
||||
cube.position.set(default_cube.position);
|
||||
cube.normal.set(default_cube.normal);
|
||||
cube.indices.set(default_cube.indices);
|
||||
cube.texcoord.set(default_cube.texcoord);
|
||||
|
||||
for (let i = 0; i < 72; i += 3) {
|
||||
cube.position[i + 0] = (cube.position[i + 0] * size.x) + centre.x;
|
||||
|
153
src/renderer.js
153
src/renderer.js
@ -16,8 +16,8 @@ class Renderer {
|
||||
this._gl = document.querySelector("#c").getContext("webgl");
|
||||
this._camera = new ArcballCamera(fov, this._gl.canvas.clientWidth / this._gl.canvas.clientHeight, 0.5, 100.0);
|
||||
|
||||
this._registerEvents();
|
||||
this._getNewBuffers();
|
||||
this._registerEvents(); // Register mouse events for interacting with canvas
|
||||
this._getNewBuffers(); // Setup WebGL Buffers
|
||||
|
||||
this._debug = false;
|
||||
this._compiled = false;
|
||||
@ -39,6 +39,39 @@ class Renderer {
|
||||
this._registerData(data);
|
||||
}
|
||||
|
||||
_registerVoxel(centre, voxelSize, voxelManager) {
|
||||
const sizeVector = new Vector3(voxelSize, voxelSize, voxelSize);
|
||||
|
||||
let occlusions = new Array(6);
|
||||
// For each face
|
||||
for (let f = 0; f < 6; ++f) {
|
||||
// For each vertex
|
||||
occlusions[f] = [0, 0, 0, 0];
|
||||
for (let v = 0; v < 4; ++v) {
|
||||
// For each occlusion vertex
|
||||
for (let o = 0; o < 3; ++o) {
|
||||
occlusions[f][v] += voxelManager.isVoxelAt(Vector3.add(centre, this.occlusions[f][v][o]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Each vertex of a face needs the occlusion data for the other 3 vertices
|
||||
// in it's face, not just itself, pack this into a vec4.
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
occlusions[i] = [].concat(...new Array(4).fill(occlusions[i]));
|
||||
}
|
||||
|
||||
let data = GeometryTemplates.getBoxBufferData(centre, sizeVector, false);
|
||||
data.occlusion = [].concat(...occlusions);
|
||||
|
||||
// Convert from occlusion denoting the occlusion factor to the
|
||||
// attenuation in light value: 0 -> 1.0, 1 -> 0.8, 2 -> 0.6, 3 -> 0.4
|
||||
data.occlusion = data.occlusion.map(x => 1.0 - 0.2 * x);
|
||||
|
||||
//this._registerData(data);
|
||||
this._registerVoxels.add(data);
|
||||
}
|
||||
|
||||
registerTriangle(triangle) {
|
||||
const data = GeometryTemplates.getTriangleBufferData(triangle, this._debug);
|
||||
this._registerData(data);
|
||||
@ -51,10 +84,26 @@ class Renderer {
|
||||
}
|
||||
|
||||
registerVoxelMesh(voxelManager) {
|
||||
const voxelSize = voxelManager._voxelSize;
|
||||
const sizeVector = new Vector3(voxelSize/2, voxelSize/2, voxelSize/2);
|
||||
if (this.debug) {
|
||||
voxelManager.voxels.forEach((voxel) => {
|
||||
this.registerBox(voxel, sizeVector);
|
||||
});
|
||||
} else {
|
||||
this._setupOcclusions(voxelSize); // Setup arrays for calculating voxel ambient occlusion
|
||||
|
||||
voxelManager.voxels.forEach((voxel) => {
|
||||
this._registerVoxel(voxel, voxelSize, voxelManager);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
const mesh = voxelManager.buildMesh();
|
||||
for (const box of mesh) {
|
||||
this.registerBox(box.centre, box.size, false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
clear() {
|
||||
@ -63,7 +112,8 @@ class Renderer {
|
||||
|
||||
compile() {
|
||||
this._registerDebug.compile(this._gl);
|
||||
this._register.compile(this._gl);
|
||||
this._registerVoxels.compile(this._gl);
|
||||
this._registerDefault.compile(this._gl);
|
||||
this._compiled = true;
|
||||
}
|
||||
|
||||
@ -75,32 +125,70 @@ class Renderer {
|
||||
|
||||
this._setupScene();
|
||||
|
||||
this._drawDebugRegisters();
|
||||
this._drawRegisters();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
_drawDebugRegisters() {
|
||||
const debugUniforms = {
|
||||
// Draw debug register
|
||||
this._drawRegister(this._registerDebug, this._gl.LINES, shaderManager.debugProgram, {
|
||||
u_worldViewProjection: this._camera.getWorldViewProjection(),
|
||||
};
|
||||
|
||||
for (const buffer of this._registerDebug.WebGLBuffers) {
|
||||
this._drawBuffer(this._gl.LINES, buffer, shaderManager.debugProgram, debugUniforms);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_drawRegisters() {
|
||||
const uniforms = {
|
||||
// Draw voxel register
|
||||
this._drawRegister(this._registerVoxels, this._gl.TRIANGLES, shaderManager.aoProgram, {
|
||||
u_worldViewProjection: this._camera.getWorldViewProjection()
|
||||
});
|
||||
|
||||
// Draw default register
|
||||
this._drawRegister(this._registerDefault, this._gl.TRIANGLES, shaderManager.shadedProgram, {
|
||||
u_lightWorldPos: this._camera.getCameraPosition(0.0, 0.0),
|
||||
u_worldViewProjection: this._camera.getWorldViewProjection(),
|
||||
u_worldInverseTranspose: this._camera.getWorldInverseTranspose()
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
for (const buffer of this._register.WebGLBuffers) {
|
||||
this._drawBuffer(this._gl.TRIANGLES, buffer, shaderManager.shadedProgram, uniforms);
|
||||
_drawRegister(register, drawMode, shaderProgram, uniforms) {
|
||||
for (const buffer of register.WebGLBuffers) {
|
||||
this._drawBuffer(drawMode, buffer, shaderProgram, uniforms);
|
||||
}
|
||||
}
|
||||
|
||||
_setupOcclusions(voxelSize) {
|
||||
this.occlusions = new Array(6).fill(null).map(function() { return new Array(4).fill(0); });
|
||||
|
||||
this.occlusions[0][0] = [new Vector3( 1, 1, 0), new Vector3( 1, 1, -1), new Vector3( 1, 0, -1)];
|
||||
this.occlusions[0][1] = [new Vector3( 1, -1, 0), new Vector3( 1, -1, -1), new Vector3( 1, 0, -1)];
|
||||
this.occlusions[0][2] = [new Vector3( 1, 1, 0), new Vector3( 1, 1, 1), new Vector3( 1, 0, 1)];
|
||||
this.occlusions[0][3] = [new Vector3( 1, -1, 0), new Vector3( 1, -1, 1), new Vector3( 1, 0, 1)];
|
||||
|
||||
this.occlusions[1][0] = [new Vector3(-1, 1, 0), new Vector3(-1, 1, 1), new Vector3(-1, 0, 1)];
|
||||
this.occlusions[1][1] = [new Vector3(-1, -1, 0), new Vector3(-1, -1, 1), new Vector3(-1, 0, 1)];
|
||||
this.occlusions[1][2] = [new Vector3(-1, 1, 0), new Vector3(-1, 1, -1), new Vector3(-1, 0, -1)];
|
||||
this.occlusions[1][3] = [new Vector3(-1, -1, 0), new Vector3(-1, -1, -1), new Vector3(-1, 0, -1)];
|
||||
|
||||
this.occlusions[2][0] = [new Vector3(-1, 1, 0), new Vector3(-1, 1, 1), new Vector3( 0, 1, 1)];
|
||||
this.occlusions[2][1] = [new Vector3(-1, 1, 0), new Vector3(-1, 1, -1), new Vector3( 0, 1, -1)];
|
||||
this.occlusions[2][2] = [new Vector3( 1, 1, 0), new Vector3( 1, 1, 1), new Vector3( 0, 1, 1)];
|
||||
this.occlusions[2][3] = [new Vector3( 1, 1, 0), new Vector3( 1, 1, -1), new Vector3( 0, 1, -1)];
|
||||
|
||||
this.occlusions[3][0] = [new Vector3(-1, -1, 0), new Vector3(-1, -1, -1), new Vector3( 0, -1, -1)];
|
||||
this.occlusions[3][1] = [new Vector3(-1, -1, 0), new Vector3(-1, -1, 1), new Vector3( 0, -1, 1)];
|
||||
this.occlusions[3][2] = [new Vector3( 1, -1, 0), new Vector3( 1, -1, -1), new Vector3( 0, -1, -1)];
|
||||
this.occlusions[3][3] = [new Vector3( 1, -1, 0), new Vector3( 1, -1, 1), new Vector3( 0, -1, 1)];
|
||||
|
||||
this.occlusions[4][0] = [new Vector3( 0, 1, 1), new Vector3( 1, 1, 1), new Vector3( 1, 0, 1)];
|
||||
this.occlusions[4][1] = [new Vector3( 0, -1, 1), new Vector3( 1, -1, 1), new Vector3( 1, 0, 1)];
|
||||
this.occlusions[4][2] = [new Vector3( 0, 1, 1), new Vector3(-1, 1, 1), new Vector3(-1, 0, 1)];
|
||||
this.occlusions[4][3] = [new Vector3( 0, -1, 1), new Vector3(-1, -1, 1), new Vector3(-1, 0, 1)];
|
||||
|
||||
this.occlusions[5][0] = [new Vector3( 0, 1, -1), new Vector3(-1, 1, -1), new Vector3(-1, 0, -1)];
|
||||
this.occlusions[5][1] = [new Vector3( 0, -1, -1), new Vector3(-1, -1, -1), new Vector3(-1, 0, -1)];
|
||||
this.occlusions[5][2] = [new Vector3( 0, 1, -1), new Vector3( 1, 1, -1), new Vector3( 1, 0, -1)];
|
||||
this.occlusions[5][3] = [new Vector3( 0, -1, -1), new Vector3( 1, -1, -1), new Vector3( 1, 0, -1)];
|
||||
|
||||
// Scale each Vector3 by voxelSize
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
for (let j = 0; j < 4; ++j) {
|
||||
for (let k = 0; k < 3; ++k) {
|
||||
this.occlusions[i][j][k] = Vector3.mulScalar(this.occlusions[i][j][k], voxelSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +198,7 @@ class Renderer {
|
||||
data.colour = [].concat(...new Array(numVertices).fill(this._strokeColour.toArray()));
|
||||
this._registerDebug.add(data);
|
||||
} else {
|
||||
this._register.add(data);
|
||||
this._registerDefault.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +237,7 @@ class Renderer {
|
||||
}
|
||||
|
||||
_drawBuffer(drawMode, buffer, shader, uniforms) {
|
||||
//console.log(shader);
|
||||
this._gl.useProgram(shader.program);
|
||||
twgl.setBuffersAndAttributes(this._gl, shader, buffer.buffer);
|
||||
twgl.setUniforms(shader, uniforms);
|
||||
@ -156,8 +245,20 @@ class Renderer {
|
||||
}
|
||||
|
||||
_getNewBuffers() {
|
||||
this._registerDebug = new SegmentedBuffer(16384, [{name: 'position', numComponents: 3}, {name: 'colour', numComponents: 3}]);
|
||||
this._register = new SegmentedBuffer(16384, [{name: 'position', numComponents: 3}, {name: 'normal', numComponents: 3}]);
|
||||
this._registerDebug = new SegmentedBuffer(16384, [
|
||||
{name: 'position', numComponents: 3},
|
||||
{name: 'colour', numComponents: 3}
|
||||
]);
|
||||
this._registerVoxels = new SegmentedBuffer(16384, [
|
||||
{name: 'position', numComponents: 3},
|
||||
{name: 'normal', numComponents: 3},
|
||||
{name: 'occlusion', numComponents: 4},
|
||||
{name: 'texcoord', numComponents: 2}
|
||||
]);
|
||||
this._registerDefault = new SegmentedBuffer(16384, [
|
||||
{name: 'position', numComponents: 3},
|
||||
{name: 'normal', numComponents: 3}
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,16 +14,13 @@ const shadedFragmentShader = getShader('shaded_fragment.fs');
|
||||
const debugVertexShader = getShader('debug_vertex.vs');
|
||||
const debugFragmentShader = getShader('debug_fragment.fs');
|
||||
|
||||
/*
|
||||
const shaded_vertex_shader = fs.readFileSync('./shaders/shaded_vertex.vs', 'utf8');
|
||||
const shaded_fragment_shader = fs.readFileSync('./shaders/shaded_fragment.fs', 'utf8');
|
||||
|
||||
const debug_vertex_shader = fs.readFileSync('./shaders/debug_vertex.vs', 'utf8');
|
||||
const debug_fragment_shader = fs.readFileSync('./shaders/debug_fragment.fs', 'utf8');
|
||||
*/
|
||||
const aoVertexShader = getShader('ao_vertex.vs');
|
||||
const aoFragmentShader = getShader('ao_fragment.fs');
|
||||
|
||||
const shadedProgram = twgl.createProgramInfo(gl, [shadedVertexShader, shadedFragmentShader]);
|
||||
const debugProgram = twgl.createProgramInfo(gl, [debugVertexShader, debugFragmentShader]);
|
||||
const aoProgram = twgl.createProgramInfo(gl, [aoVertexShader, aoFragmentShader]);
|
||||
|
||||
module.exports.shadedProgram = shadedProgram;
|
||||
module.exports.debugProgram = debugProgram;
|
||||
module.exports.aoProgram = aoProgram;
|
@ -76,6 +76,12 @@ class VoxelManager {
|
||||
);
|
||||
}
|
||||
|
||||
isVoxelAt(vec) {
|
||||
vec = Vector3.subScalar(vec, this._voxelSize / 2);
|
||||
const pos = this._voxelCentreToPosition(vec);
|
||||
return (this.voxelsHash.contains(pos));
|
||||
}
|
||||
|
||||
addVoxel(vec) {
|
||||
// (0.5, 0.5, 0.5) -> (0, 0, 0);
|
||||
vec = Vector3.subScalar(vec, this._voxelSize / 2);
|
||||
|
Loading…
Reference in New Issue
Block a user