Camera-based subdivision

This commit is contained in:
Evert Prants 2019-03-01 12:37:30 +02:00
parent 1acddf4074
commit 7502888d03
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
3 changed files with 82 additions and 11 deletions

View File

@ -1,5 +1,6 @@
import { Mesh } from '../../mesh'
import { mat4 } from 'gl-matrix'
import { BoundingBox } from '../../mesh/aabb'
import { mat4, vec3 } from 'gl-matrix'
import { subv3, mulv3, addv3, normalv3, crossv3 } from '../../utility'
const lodMax = 8
@ -28,10 +29,6 @@ class CubeFace {
this.position = subv3(this.position, mulv3(this.left, this.radius / 2))
this.position = subv3(this.position, mulv3(this.forward, this.radius / 2))
if (this.parent) {
this.transform = this.parent.transform
}
this.generate()
}
@ -88,6 +85,7 @@ class CubeFace {
}
this.mesh = Mesh.construct(window.gl, vertices, indices, textureCoords)
this.bounds = BoundingBox.fromMesh(this.mesh)
this.generated = true
}
@ -139,10 +137,6 @@ class CubeFace {
return
}
// Set model transform matrix uniform
const transformLocation = shader.getUniformLocation(gl, 'uModelMatrix')
gl.uniformMatrix4fv(transformLocation, false, this.transform)
this.mesh.prepare(gl, shader)
this.mesh.draw(gl, shader)
}
@ -174,7 +168,43 @@ class CubePlanet {
this.faces[0].children[0].subdivide()
}
getActiveQuadTreeFaces (face, active) {
if (!face.children.length) {
active.push(face)
} else {
for (let f = 0; f < face.children.length; f++) {
this.getActiveQuadTreeFaces(face.children[f], active)
}
}
}
update (f, camera) {
let activeTree = []
this.getActiveQuadTreeFaces(this.faces[f], activeTree)
for (let a = 0; a < activeTree.length; a++) {
let dist = vec3.distance(camera.pos, activeTree[a].bounds.center)
if (dist > activeTree[a].radius) {
if (dist <= this.radius * 2.0 || activeTree[a].parent === this) {
activeTree[a].merge()
activeTree[a].generate()
} else {
activeTree[a].merge()
activeTree[a].parent.merge()
activeTree[a].parent.generate()
}
} else if (activeTree[a].radius > this.resolution && activeTree[a].level < lodMax) {
activeTree[a].subdivide()
}
}
}
draw (gl, shader) {
// Set model transform matrix uniform
const transformLocation = shader.getUniformLocation(gl, 'uModelMatrix')
gl.uniformMatrix4fv(transformLocation, false, this.transform)
for (let i in this.faces) {
this.faces[i].draw(gl, shader)
}

37
src/engine/mesh/aabb.js Normal file
View File

@ -0,0 +1,37 @@
class BoundingBox {
constructor (min, max) {
this.min = min
this.max = max
this.calculateSphere()
}
static fromMesh (mesh) {
let min = [0, 0, 0]
let max = [0, 0, 0]
for (let v = 0; v < mesh.vertices.length; v += 3) {
let vertex = [mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]]
// X
if (vertex[0] > max[0]) max[0] = vertex[0]
if (vertex[0] < min[0]) min[0] = vertex[0]
// Y
if (vertex[1] > max[1]) max[1] = vertex[1]
if (vertex[1] < min[1]) min[1] = vertex[1]
// Z
if (vertex[2] > max[2]) max[2] = vertex[2]
if (vertex[2] < min[2]) min[2] = vertex[2]
}
return new BoundingBox(min, max)
}
calculateSphere () {
this.center = [
this.min[0] + (this.max[0] - this.min[0]) / 2,
this.min[1] + (this.max[1] - this.min[1]) / 2,
this.min[2] + (this.max[2] - this.min[2]) / 2
]
this.radius = Math.max((this.max[0] - this.min[0]) / 2, (this.max[1] - this.min[1]) / 2, (this.max[2] - this.min[2]) / 2)
}
}
export { BoundingBox }

View File

@ -38,9 +38,10 @@ async function pipeline () {
cam.updateProjection(game.gl)
// Planet test
let planet = new CubePlanet([0.0, 0.0, 0.0], 16, 128)
let planet = new CubePlanet([0.0, 0.0, 0.0], 16, 512)
// Update function for camera
let face = 0
game.addUpdateFunction(function (dt) {
if (game.input.isDown('w')) {
cam.processKeyboard(0, dt)
@ -61,6 +62,8 @@ async function pipeline () {
// TESTING: Move model forward
// t = t + 0.1
// entity.setPosition([t, 0.0, 0.0])
planet.update(face++, cam)
if (face > 5) face = 0
})
// Render function for the triangle
@ -69,7 +72,7 @@ async function pipeline () {
cam.draw(gl, shader)
entity.draw(gl, shader)
planet.draw(gl, shader)
/*
// Use terrain shader
terrainShader.use(gl)
@ -81,6 +84,7 @@ async function pipeline () {
// Draw terrain
terrain.draw(gl, terrainShader)
*/
})
game.startGameLoop()