simple voxel chunk
This commit is contained in:
parent
e56adeeb10
commit
1bad7e46ab
@ -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
|
||||||
|
|
||||||
|
// Indices Buffer (EBO)
|
||||||
|
if (indices) {
|
||||||
|
let ebo = Mesh.loadToBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices))
|
||||||
|
mesh.ebo = ebo
|
||||||
mesh.indices = indices
|
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
215
src/engine/voxel/index.js
Normal 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 }
|
41
src/index.js
41
src/index.js
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user