simple voxel chunk

This commit is contained in:
Evert Prants 2020-01-05 17:13:55 +02:00
parent e56adeeb10
commit 1bad7e46ab
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
3 changed files with 251 additions and 22 deletions

View File

@ -11,15 +11,20 @@ class Mesh {
// VBO for model vertices // VBO for model vertices
let pos = Mesh.loadToBuffer(gl, gl.ARRAY_BUFFER, new Float32Array(vertices)) let pos = Mesh.loadToBuffer(gl, gl.ARRAY_BUFFER, new Float32Array(vertices))
// Indices Buffer
let ebo = Mesh.loadToBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices))
// Create the mesh, as we have the most important data already buffered // Create the mesh, as we have the most important data already buffered
let mesh = new Mesh() let mesh = new Mesh()
mesh.posBuffer = pos mesh.posBuffer = pos
mesh.ebo = ebo
mesh.vertices = vertices mesh.vertices = vertices
mesh.indices = indices
// Indices Buffer (EBO)
if (indices) {
let ebo = Mesh.loadToBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices))
mesh.ebo = ebo
mesh.indices = indices
} else {
mesh.vertexCount = vertices.length / 3
mesh.vertexLayout = 3
}
// VBO for model UVs // VBO for model UVs
if (uvs) { if (uvs) {
@ -114,7 +119,7 @@ class Mesh {
// Make sure no data floats around in memory // Make sure no data floats around in memory
dispose (gl) { dispose (gl) {
gl.deleteBuffer(this.posBuffer) gl.deleteBuffer(this.posBuffer)
gl.deleteBuffer(this.ebo) this.ebo && gl.deleteBuffer(this.ebo)
this.uvs && gl.deleteBuffer(this.uvs) this.uvs && gl.deleteBuffer(this.uvs)
this.nms && gl.deleteBuffer(this.nms) this.nms && gl.deleteBuffer(this.nms)
this.vertices = null this.vertices = null

215
src/engine/voxel/index.js Normal file
View File

@ -0,0 +1,215 @@
import { Mesh } from '../mesh'
import { MeshInstance } from '../components'
import { addv3, crossv3, subv3 } from '../utility'
const FACE_VERTEX = [
// Bottom
[
[1.0, 0.0, 0.0],
[1.0, 0.0, 1.0],
[0.0, 0.0, 1.0],
[0.0, 0.0, 0.0]
],
// Top
[
[0.0, 1.0, 0.0],
[0.0, 1.0, 1.0],
[1.0, 1.0, 1.0],
[1.0, 1.0, 0.0]
],
// Left
[
[0.0, 0.0, 1.0],
[0.0, 1.0, 1.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 0.0]
],
// Right
[
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[1.0, 1.0, 1.0],
[1.0, 0.0, 1.0]
],
// Front
[
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0],
[0.0, 0.0, 1.0]
],
// Back
[
[0.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[1.0, 1.0, 0.0],
[1.0, 0.0, 0.0]
]
]
const FACE_BOTTOM = 0
const FACE_TOP = 1
const FACE_LEFT = 2
const FACE_RIGHT = 3
const FACE_FRONT = 4
const FACE_BACK = 5
class Voxel {
constructor (id) {
this.id = id
}
get solid () {
return this.id !== 0
}
}
const AIR_VOXEL = new Voxel(0)
class VoxelChunk extends MeshInstance {
constructor (pos, size = 16) {
super(null, pos)
this.size = size
this.array = {}
this.mesh = null
this.dirty = true
}
getVoxel (x, y, z) {
if (x < 0 || x >= this.size || y < 0 || y >= this.size || z < 0 || z >= this.size) return AIR_VOXEL
return this.array[x][y][z]
}
generate (noise) {
this.array = {}
for (let x = 0; x < this.size; x++) {
if (!this.array[x]) this.array[x] = {}
for (let y = 0; y < this.size; y++) {
if (!this.array[x][y]) this.array[x][y] = {}
for (let z = 0; z < this.size; z++) {
if (!this.array[x][y][z]) this.array[x][y][z] = {}
let solid = y < (noise.getHeight(x + this.pos[0], z + this.pos[2]) + 10)
this.array[x][y][z] = new Voxel(solid ? 1 : 0)
}
}
}
}
// Programmatically generate a voxel face
// Returns the position, normal and texture coordinates for each vertex in this face
createFace (verts, pos, face) {
let posi = [
addv3(pos, FACE_VERTEX[face][0]), addv3(pos, FACE_VERTEX[face][1]),
addv3(pos, FACE_VERTEX[face][2]), addv3(pos, FACE_VERTEX[face][3])
]
let normal = crossv3(subv3(posi[2], posi[0]), subv3(posi[3], posi[1]))
verts.push([posi[0], normal, [0.0, 1.0]])
verts.push([posi[1], normal, [0.0, 0.0]])
verts.push([posi[2], normal, [1.0, 0.0]])
verts.push([posi[0], normal, [0.0, 1.0]])
verts.push([posi[2], normal, [1.0, 0.0]])
verts.push([posi[3], normal, [1.0, 1.0]])
}
createMesh (gl) {
this.dirty = false
if (this.mesh) {
this.mesh.dispose(gl)
}
let points = []
for (let x = 0; x < this.size; x++) {
for (let y = 0; y < this.size; y++) {
for (let z = 0; z < this.size; z++) {
if (!this.getVoxel(x, y, z).solid) continue
let faceLeft = true
if (x > 0) {
faceLeft = !this.getVoxel(x - 1, y, z).solid
}
let faceRight = true
if (x < this.size - 1) {
faceRight = !this.getVoxel(x + 1, y, z).solid
}
let faceBottom = true
if (y > 0) {
faceBottom = !this.getVoxel(x, y - 1, z).solid
}
let faceTop = true
if (y < this.size - 1) {
faceTop = !this.getVoxel(x, y + 1, z).solid
}
let faceBack = true
if (z > 0) {
faceBack = !this.getVoxel(x, y, z - 1).solid
}
let faceFront = true
if (z < this.size - 1) {
faceFront = !this.getVoxel(x, y, z + 1).solid
}
let cellPos = [x, y, z]
if (faceBottom) {
this.createFace(points, cellPos, FACE_BOTTOM)
}
if (faceTop) {
this.createFace(points, cellPos, FACE_TOP)
}
if (faceLeft) {
this.createFace(points, cellPos, FACE_LEFT)
}
if (faceRight) {
this.createFace(points, cellPos, FACE_RIGHT)
}
if (faceFront) {
this.createFace(points, cellPos, FACE_FRONT)
}
if (faceBack) {
this.createFace(points, cellPos, FACE_BACK)
}
}
}
}
if (points.length === 0) {
return
}
let vertices = []
let normals = []
let uvs = []
for (let i in points) {
let vert = points[i]
vertices.push(vert[0][0])
vertices.push(vert[0][1])
vertices.push(vert[0][2])
normals.push(vert[1][0])
normals.push(vert[1][1])
normals.push(vert[1][2])
uvs.push(vert[2][0])
uvs.push(vert[2][1])
}
this.mesh = Mesh.construct(gl, vertices, null, uvs, normals)
}
update (dt) {
}
}
export { Voxel, VoxelChunk }

View File

@ -13,6 +13,7 @@ import { SimplexHeightMap } from './engine/components/terrain/heightmap'
import { Material, Texture } from './engine/mesh/material' import { Material, Texture } from './engine/mesh/material'
import { GUIRenderer, GUIImage, Dim4 } from './engine/gui' import { GUIRenderer, GUIImage, Dim4 } from './engine/gui'
import { FontRenderer, GUIText, Font } from './engine/gui/font' import { FontRenderer, GUIText, Font } from './engine/gui/font'
import { VoxelChunk } from './engine/voxel'
let game = Engine let game = Engine
let env = new Environment() let env = new Environment()
@ -21,10 +22,10 @@ let fnt = new FontRenderer()
let prt = new ParticleRenderer() let prt = new ParticleRenderer()
async function pipeline () { async function pipeline () {
let entity = await loadMesh(game.gl, 'test') // let entity = await loadMesh(game.gl, 'test')
let terrainShader = await game.shaders.createShaderFromFiles(game.gl, 'terrain', false) let terrainShader = await game.shaders.createShaderFromFiles(game.gl, 'terrain', false)
let skyboxShader = await game.shaders.createShaderFromFiles(game.gl, 'skybox', false) let skyboxShader = await game.shaders.createShaderFromFiles(game.gl, 'skybox', false)
/*
entity.setRotation([0.0, 0.0, -90.0]) entity.setRotation([0.0, 0.0, -90.0])
// Initialize water // Initialize water
@ -33,7 +34,7 @@ async function pipeline () {
await waterRenderer.initialize(game) await waterRenderer.initialize(game)
await waterRenderer.useDUDVMap(game.gl, 'dudv') await waterRenderer.useDUDVMap(game.gl, 'dudv')
await waterRenderer.useNormalMap(game.gl, 'normalmap') await waterRenderer.useNormalMap(game.gl, 'normalmap')
*/
let arialFont = await Font.fromFile('arial') let arialFont = await Font.fromFile('arial')
await arialFont.loadTextures(game.gl) await arialFont.loadTextures(game.gl)
@ -58,14 +59,14 @@ async function pipeline () {
// Create a height map based on OpenSimplex noise // Create a height map based on OpenSimplex noise
let hmap = new SimplexHeightMap(1, 1, 256, 50) let hmap = new SimplexHeightMap(1, 1, 256, 50)
/*
// Create a terrain instance // Create a terrain instance
let terrain = new LODTerrain([0.0, 0.0, 0.0], 1024, 1024, 850, 4) let terrain = new LODTerrain([0.0, 0.0, 0.0], 1024, 1024, 850, 4)
*/
// Terrain material // Terrain material
let material = new Material(['grass-1024.jpg']) let material = new Material(['grass-1024.jpg'])
await material.loadTextures(game.gl) await material.loadTextures(game.gl)
/*
// test code // test code
for (let i in entity.children) { for (let i in entity.children) {
entity.children[i].mesh.material = material entity.children[i].mesh.material = material
@ -74,9 +75,9 @@ async function pipeline () {
// Set generator and material for terrain // Set generator and material for terrain
terrain.setGenerator(hmap) terrain.setGenerator(hmap)
terrain.setMaterial(material) terrain.setMaterial(material)
*/
// Create and initialize the camera // Create and initialize the camera
let cam = new Camera([-32.0, 100.0, -32.0], [0.8, -0.6, 0.0]) let cam = new Camera([-16.0, 25.0, -16.0], [0.8, -0.6, 0.0])
cam.updateProjection(game.gl) cam.updateProjection(game.gl)
// Create skybox // Create skybox
@ -85,6 +86,12 @@ async function pipeline () {
// Load textures and generate a mesh // Load textures and generate a mesh
await skybox.initialize(game.gl) await skybox.initialize(game.gl)
// Voxel test
let chunk = new VoxelChunk([0.0, 0.0, 0.0])
chunk.generate(hmap)
chunk.createMesh(game.gl)
chunk.mesh.material = material
// Update function for camera and terrain // Update function for camera and terrain
let fpsTimer = 0 let fpsTimer = 0
game.addUpdateFunction(function (dt) { game.addUpdateFunction(function (dt) {
@ -119,11 +126,11 @@ async function pipeline () {
} }
// Update detail levels // Update detail levels
terrain.update(game.gl, cam) // terrain.update(game.gl, cam)
terrain.updateLODMesh(game.gl) // terrain.updateLODMesh(game.gl)
// Ripple water // Ripple water
waterRenderer.update(dt) // waterRenderer.update(dt)
// Set text to FPS // Set text to FPS
fpsTimer++ fpsTimer++
@ -147,19 +154,21 @@ async function pipeline () {
// Set the viewport uniforms // Set the viewport uniforms
cam.draw(gl, terrainShader) cam.draw(gl, terrainShader)
// Draw terrain // Draw terrain
terrain.draw(gl, terrainShader) // terrain.draw(gl, terrainShader)
entity.draw(gl, terrainShader) // entity.draw(gl, terrainShader)
chunk.draw(gl, terrainShader)
} }
// Render function for the triangle // Render function for the triangle
game.addRenderFunction(function (gl) { game.addRenderFunction(function (gl) {
waterRenderer.reflect(gl, cam, drawEverything) // waterRenderer.reflect(gl, cam, drawEverything)
waterRenderer.refract(gl, cam, drawEverything) // waterRenderer.refract(gl, cam, drawEverything)
drawEverything(gl) drawEverything(gl)
waterRenderer.draw(gl, [water], cam, env.sun) // waterRenderer.draw(gl, [water], cam, env.sun)
// Draw particles // Draw particles
particleSystem.draw(gl, cam) particleSystem.draw(gl, cam)