Better split into files
This commit is contained in:
parent
c941a65145
commit
a390a849a3
@ -1,4 +1,4 @@
|
|||||||
import { Node } from './mesh'
|
import { Node } from './components'
|
||||||
import { glMatrix, mat4, vec2, vec3 } from 'gl-matrix'
|
import { glMatrix, mat4, vec2, vec3 } from 'gl-matrix'
|
||||||
|
|
||||||
const SPEED = 100.0
|
const SPEED = 100.0
|
||||||
|
334
src/engine/components/index.js
Normal file
334
src/engine/components/index.js
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
import Resource from '../resource'
|
||||||
|
import { mat4, quat, vec3 } from 'gl-matrix'
|
||||||
|
import { Mesh } from '../mesh'
|
||||||
|
import { Material } from '../mesh/material'
|
||||||
|
|
||||||
|
let meshCache = {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an euler angle representation of a quaternion
|
||||||
|
* @param {vec3} out Euler angles, pitch-yaw-roll
|
||||||
|
* @param {quat} mat Quaternion
|
||||||
|
* @return {vec3} out
|
||||||
|
*/
|
||||||
|
quat.getEuler = function (out, quat) {
|
||||||
|
let x = quat[0]
|
||||||
|
let y = quat[1]
|
||||||
|
let z = quat[2]
|
||||||
|
let w = quat[3]
|
||||||
|
let x2 = x * x
|
||||||
|
let y2 = y * y
|
||||||
|
let z2 = z * z
|
||||||
|
let w2 = w * w
|
||||||
|
let unit = x2 + y2 + z2 + w2
|
||||||
|
let test = x * w - y * z
|
||||||
|
if (test > 0.499995 * unit) {
|
||||||
|
// singularity at the north pole
|
||||||
|
out[0] = Math.PI / 2
|
||||||
|
out[1] = 2 * Math.atan2(y, x)
|
||||||
|
out[2] = 0
|
||||||
|
} else if (test < -0.499995 * unit) {
|
||||||
|
// singularity at the south pole
|
||||||
|
out[0] = -Math.PI / 2
|
||||||
|
out[1] = 2 * Math.atan2(y, x)
|
||||||
|
out[2] = 0
|
||||||
|
} else {
|
||||||
|
out[0] = Math.asin(2 * (x * z - w * y))
|
||||||
|
out[1] = Math.atan2(2 * (x * w + y * z), 1 - 2 * (z2 + w2))
|
||||||
|
out[2] = Math.atan2(2 * (x * y + z * w), 1 - 2 * (y2 + z2))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
constructor (pos, scale, rotation) {
|
||||||
|
// Translation
|
||||||
|
this.pos = pos || [0.0, 0.0, 0.0]
|
||||||
|
|
||||||
|
// Scaling
|
||||||
|
this.scale = scale || [1.0, 1.0, 1.0]
|
||||||
|
|
||||||
|
// Rotation in Euler angles (yaw, pitch, roll) in radians
|
||||||
|
this.rotation = rotation || [0.0, 0.0, 0.0]
|
||||||
|
|
||||||
|
this.transform = mat4.create()
|
||||||
|
this.updateTransform()
|
||||||
|
|
||||||
|
this.parent = null
|
||||||
|
this.children = []
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTransform () {
|
||||||
|
let matrix = mat4.create()
|
||||||
|
|
||||||
|
// Set translation
|
||||||
|
mat4.translate(matrix, matrix, this.pos)
|
||||||
|
|
||||||
|
// Set scale
|
||||||
|
mat4.scale(matrix, matrix, this.scale)
|
||||||
|
|
||||||
|
// Set rotation
|
||||||
|
if (this.rotation[0] !== 0) {
|
||||||
|
mat4.rotateX(matrix, matrix, this.rotation[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.rotation[1] !== 0) {
|
||||||
|
mat4.rotateY(matrix, matrix, this.rotation[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.rotation[2] !== 0) {
|
||||||
|
mat4.rotateZ(matrix, matrix, this.rotation[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add parent node's transform
|
||||||
|
if (this.parent) {
|
||||||
|
mat4.add(matrix, this.parent.transform, matrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the matrix
|
||||||
|
this.transform = matrix
|
||||||
|
|
||||||
|
// Update children's transforms
|
||||||
|
for (let i in this.children) {
|
||||||
|
let child = this.children[i]
|
||||||
|
if (!(child instanceof Node)) continue
|
||||||
|
child.updateTransform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTransformation (transform) {
|
||||||
|
let quaternion = quat.create()
|
||||||
|
let translation = vec3.create()
|
||||||
|
let rotation = vec3.create()
|
||||||
|
let scale = vec3.create()
|
||||||
|
|
||||||
|
mat4.getTranslation(translation, transform)
|
||||||
|
mat4.getScaling(scale, transform)
|
||||||
|
mat4.getRotation(quaternion, transform)
|
||||||
|
|
||||||
|
quat.getEuler(rotation, quaternion)
|
||||||
|
|
||||||
|
this.rotation = rotation
|
||||||
|
this.pos = translation
|
||||||
|
this.scale = scale
|
||||||
|
|
||||||
|
this.updateTransform()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
setPosition (newPos) {
|
||||||
|
this.pos = newPos
|
||||||
|
this.updateTransform()
|
||||||
|
}
|
||||||
|
|
||||||
|
setTranslation (newTrans) {
|
||||||
|
this.setPosition(newTrans)
|
||||||
|
}
|
||||||
|
|
||||||
|
setScale (newScale) {
|
||||||
|
this.scale = newScale
|
||||||
|
this.updateTransform()
|
||||||
|
}
|
||||||
|
|
||||||
|
setRotation (newRotation) {
|
||||||
|
this.rotation = newRotation
|
||||||
|
this.updateTransform()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transforms
|
||||||
|
translate (pos) {
|
||||||
|
mat4.translate(this.transform, this.transform, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
scale (scale) {
|
||||||
|
mat4.scale(this.transform, this.transform, scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate (rot) {
|
||||||
|
if (rot[0] !== 0) {
|
||||||
|
mat4.rotateX(this.transform, this.transform, rot[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rot[1] !== 0) {
|
||||||
|
mat4.rotateY(this.transform, this.transform, rot[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rot[2] !== 0) {
|
||||||
|
mat4.rotateZ(this.transform, this.transform, rot[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
get position () {
|
||||||
|
return this.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
get translation () {
|
||||||
|
return this.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw base
|
||||||
|
draw (gl, shader) {
|
||||||
|
// Set model transform matrix uniform
|
||||||
|
const transformLocation = shader.getUniformLocation(gl, 'uModelMatrix')
|
||||||
|
gl.uniformMatrix4fv(transformLocation, false, this.transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild (ch) {
|
||||||
|
if (!(ch instanceof Node)) return
|
||||||
|
this.children.push(ch)
|
||||||
|
this.updateTransform()
|
||||||
|
}
|
||||||
|
|
||||||
|
setParent (p) {
|
||||||
|
if (!(p instanceof Node)) return
|
||||||
|
this.parent = p
|
||||||
|
this.updateTransform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MeshInstance extends Node {
|
||||||
|
constructor (mesh, pos, scale, rot) {
|
||||||
|
super(pos, scale, rot)
|
||||||
|
this.mesh = mesh
|
||||||
|
}
|
||||||
|
|
||||||
|
static async loadFile (gl, file, pos) {
|
||||||
|
file = '/assets/models/' + file + '.json'
|
||||||
|
|
||||||
|
// Ensure each mesh file is loaded only once
|
||||||
|
if (meshCache[file]) return meshCache[file].length > 1 ? meshCache[file] : meshCache[file][0]
|
||||||
|
|
||||||
|
let dat = await Resource.GET({ type: 'json', url: file })
|
||||||
|
if (!dat.meshes) throw new Error('No meshes defined in file.')
|
||||||
|
|
||||||
|
let cleaned = []
|
||||||
|
let materials = []
|
||||||
|
for (let mi in dat.meshes) {
|
||||||
|
let mesh = dat.meshes[mi]
|
||||||
|
let material
|
||||||
|
|
||||||
|
if (mesh.materialindex != null && dat.materials && dat.materials.length) {
|
||||||
|
// Ensure we don't re-create materials with the same index
|
||||||
|
if (materials[mesh.materialindex]) {
|
||||||
|
material = materials[mesh.materialindex]
|
||||||
|
} else {
|
||||||
|
// Load a new material
|
||||||
|
material = new Material()
|
||||||
|
let matdata = dat.materials[mesh.materialindex].properties
|
||||||
|
|
||||||
|
// Parse material information
|
||||||
|
for (let pi in matdata) {
|
||||||
|
let property = matdata[pi]
|
||||||
|
if (!property || !property.key) continue
|
||||||
|
if (property.key === '?mat.name') material.name = property.value
|
||||||
|
else if (property.key.indexOf('$clr.') === 0) {
|
||||||
|
let dproperty = property.key.substr(5)
|
||||||
|
switch (dproperty) {
|
||||||
|
case 'specular':
|
||||||
|
case 'diffuse':
|
||||||
|
case 'shininess':
|
||||||
|
case 'ambient':
|
||||||
|
case 'reflective':
|
||||||
|
material[dproperty] = property.value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (property.key.indexOf('$tex.file') === 0) {
|
||||||
|
if (!material.textures) {
|
||||||
|
material.textures = []
|
||||||
|
}
|
||||||
|
|
||||||
|
material.textures.push(property.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
materials[mesh.materialindex] = material
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned.push({
|
||||||
|
vertices: mesh.vertices,
|
||||||
|
indices: [].concat.apply([], mesh.faces),
|
||||||
|
uv: mesh.texturecoords ? mesh.texturecoords[0] : null,
|
||||||
|
normals: mesh.normals ? mesh.normals : null,
|
||||||
|
material
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load everything
|
||||||
|
let loadComplete = []
|
||||||
|
for (let i in cleaned) {
|
||||||
|
let meshdata = cleaned[i]
|
||||||
|
let mesh = Mesh.construct(gl, meshdata.vertices, meshdata.indices,
|
||||||
|
meshdata.uv, meshdata.normals)
|
||||||
|
|
||||||
|
// Initialize the material's texture if present
|
||||||
|
if (meshdata.material) {
|
||||||
|
mesh.material = meshdata.material
|
||||||
|
|
||||||
|
// Ensure all textures get loaded before finishing
|
||||||
|
if (meshdata.material.textures) {
|
||||||
|
await meshdata.material.loadTextures(gl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadComplete.push(mesh)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we need to give the meshes the appropriate parents and transforms.
|
||||||
|
let finished = []
|
||||||
|
function setChildren (parent, chMeshes) {
|
||||||
|
let meshIndex = chMeshes.meshes[0]
|
||||||
|
let mesh = loadComplete[meshIndex]
|
||||||
|
let meshInstance = new MeshInstance(mesh, parent == null ? pos : null)
|
||||||
|
|
||||||
|
meshInstance.mesh = mesh
|
||||||
|
|
||||||
|
if (chMeshes.children) {
|
||||||
|
for (let i in chMeshes.children) {
|
||||||
|
if (!chMeshes.children[i].meshes) continue
|
||||||
|
setChildren(meshInstance, chMeshes.children[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meshInstance.name = chMeshes.name
|
||||||
|
|
||||||
|
if (parent == null) {
|
||||||
|
finished.push(meshInstance)
|
||||||
|
} else {
|
||||||
|
parent.children.push(meshInstance)
|
||||||
|
meshInstance.parent = parent
|
||||||
|
meshInstance.setTransformation(chMeshes.transformation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rootchildren = dat.rootnode.children
|
||||||
|
for (let j in rootchildren) {
|
||||||
|
if (!rootchildren[j].meshes) continue
|
||||||
|
setChildren(null, rootchildren[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the mesh
|
||||||
|
meshCache[file] = finished
|
||||||
|
|
||||||
|
return finished.length > 1 ? finished : finished[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
draw (gl, shader) {
|
||||||
|
// Set model transform uniform
|
||||||
|
super.draw(gl, shader)
|
||||||
|
|
||||||
|
// Draw the mesh
|
||||||
|
this.mesh.prepare(gl, shader)
|
||||||
|
this.mesh.draw(gl, shader)
|
||||||
|
|
||||||
|
// Invoke children's draw methods
|
||||||
|
for (let i in this.children) {
|
||||||
|
let child = this.children[i]
|
||||||
|
if (!(child instanceof Mesh)) continue
|
||||||
|
child.draw(gl, shader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Node, MeshInstance }
|
@ -1,4 +1,5 @@
|
|||||||
import { Mesh, Node } from '../../mesh'
|
import { Node } from '../'
|
||||||
|
import { Mesh } from '../../mesh'
|
||||||
|
|
||||||
class Terrain extends Node {
|
class Terrain extends Node {
|
||||||
constructor (pos, sWidth, sHeight) {
|
constructor (pos, sWidth, sHeight) {
|
||||||
@ -60,6 +61,8 @@ class Terrain extends Node {
|
|||||||
draw (gl, shader) {
|
draw (gl, shader) {
|
||||||
if (!this.mesh) return
|
if (!this.mesh) return
|
||||||
super.draw(gl, shader)
|
super.draw(gl, shader)
|
||||||
|
|
||||||
|
this.mesh.prepare(gl, shader)
|
||||||
this.mesh.draw(gl, shader)
|
this.mesh.draw(gl, shader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
import { Mesh, Node } from './index'
|
|
||||||
|
|
||||||
// Entity is just a Mesh with extra functionality.
|
|
||||||
class Entity extends Node {
|
|
||||||
constructor (mesh, pos, scale, rotation) {
|
|
||||||
super(pos, scale, rotation)
|
|
||||||
this.mesh = mesh
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drawing related
|
|
||||||
update (dt) {
|
|
||||||
// Override this!
|
|
||||||
}
|
|
||||||
|
|
||||||
draw (gl, shader) {
|
|
||||||
// Set model transform matrix uniform
|
|
||||||
const modelloc = shader.getUniformLocation(gl, 'uModelMatrix')
|
|
||||||
gl.uniformMatrix4fv(modelloc, false, this.transform)
|
|
||||||
|
|
||||||
// Draw the mesh
|
|
||||||
this.mesh.draw(gl, shader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generators
|
|
||||||
static async createEntity (gl, meshName, pos) {
|
|
||||||
let mesh = await Mesh.loadFile(gl, meshName)
|
|
||||||
let entity = new Entity(mesh, pos)
|
|
||||||
return entity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Entity
|
|
@ -1,192 +1,5 @@
|
|||||||
import Resource from '../resource'
|
|
||||||
import { Texture, Material } from './material'
|
|
||||||
import { mat4, quat, vec3 } from 'gl-matrix'
|
|
||||||
|
|
||||||
let meshCache = {}
|
class Mesh {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an euler angle representation of a quaternion
|
|
||||||
* @param {vec3} out Euler angles, pitch-yaw-roll
|
|
||||||
* @param {quat} mat Quaternion
|
|
||||||
* @return {vec3} out
|
|
||||||
*/
|
|
||||||
quat.getEuler = function (out, quat) {
|
|
||||||
let x = quat[0]
|
|
||||||
let y = quat[1]
|
|
||||||
let z = quat[2]
|
|
||||||
let w = quat[3]
|
|
||||||
let x2 = x * x
|
|
||||||
let y2 = y * y
|
|
||||||
let z2 = z * z
|
|
||||||
let w2 = w * w
|
|
||||||
let unit = x2 + y2 + z2 + w2
|
|
||||||
let test = x * w - y * z
|
|
||||||
if (test > 0.499995 * unit) {
|
|
||||||
// singularity at the north pole
|
|
||||||
out[0] = Math.PI / 2
|
|
||||||
out[1] = 2 * Math.atan2(y, x)
|
|
||||||
out[2] = 0
|
|
||||||
} else if (test < -0.499995 * unit) {
|
|
||||||
// singularity at the south pole
|
|
||||||
out[0] = -Math.PI / 2
|
|
||||||
out[1] = 2 * Math.atan2(y, x)
|
|
||||||
out[2] = 0
|
|
||||||
} else {
|
|
||||||
out[0] = Math.asin(2 * (x * z - w * y))
|
|
||||||
out[1] = Math.atan2(2 * (x * w + y * z), 1 - 2 * (z2 + w2))
|
|
||||||
out[2] = Math.atan2(2 * (x * y + z * w), 1 - 2 * (y2 + z2))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
class Node {
|
|
||||||
constructor (pos, scale, rotation) {
|
|
||||||
// Translation
|
|
||||||
this.pos = pos || [0.0, 0.0, 0.0]
|
|
||||||
|
|
||||||
// Scaling
|
|
||||||
this.scale = scale || [1.0, 1.0, 1.0]
|
|
||||||
|
|
||||||
// Rotation in Euler angles (yaw, pitch, roll) in radians
|
|
||||||
this.rotation = rotation || [0.0, 0.0, 0.0]
|
|
||||||
|
|
||||||
this.transform = mat4.create()
|
|
||||||
this.updateTransform()
|
|
||||||
|
|
||||||
this.parent = null
|
|
||||||
this.children = []
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTransform () {
|
|
||||||
let matrix = mat4.create()
|
|
||||||
|
|
||||||
// Set translation
|
|
||||||
mat4.translate(matrix, matrix, this.pos)
|
|
||||||
|
|
||||||
// Set scale
|
|
||||||
mat4.scale(matrix, matrix, this.scale)
|
|
||||||
|
|
||||||
// Set rotation
|
|
||||||
if (this.rotation[0] !== 0) {
|
|
||||||
mat4.rotateX(matrix, matrix, this.rotation[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.rotation[1] !== 0) {
|
|
||||||
mat4.rotateY(matrix, matrix, this.rotation[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.rotation[2] !== 0) {
|
|
||||||
mat4.rotateZ(matrix, matrix, this.rotation[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add parent node's transform
|
|
||||||
if (this.parent) {
|
|
||||||
mat4.add(matrix, this.parent.transform, matrix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the matrix
|
|
||||||
this.transform = matrix
|
|
||||||
|
|
||||||
// Update children's transforms
|
|
||||||
for (let i in this.children) {
|
|
||||||
let child = this.children[i]
|
|
||||||
if (!(child instanceof Node)) continue
|
|
||||||
child.updateTransform()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTransformation (transform) {
|
|
||||||
let quaternion = quat.create()
|
|
||||||
let translation = vec3.create()
|
|
||||||
let rotation = vec3.create()
|
|
||||||
let scale = vec3.create()
|
|
||||||
|
|
||||||
mat4.getTranslation(translation, transform)
|
|
||||||
mat4.getScaling(scale, transform)
|
|
||||||
mat4.getRotation(quaternion, transform)
|
|
||||||
|
|
||||||
quat.getEuler(rotation, quaternion)
|
|
||||||
|
|
||||||
this.rotation = rotation
|
|
||||||
this.pos = translation
|
|
||||||
this.scale = scale
|
|
||||||
|
|
||||||
this.updateTransform()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setters
|
|
||||||
setPosition (newPos) {
|
|
||||||
this.pos = newPos
|
|
||||||
this.updateTransform()
|
|
||||||
}
|
|
||||||
|
|
||||||
setTranslation (newTrans) {
|
|
||||||
this.setPosition(newTrans)
|
|
||||||
}
|
|
||||||
|
|
||||||
setScale (newScale) {
|
|
||||||
this.scale = newScale
|
|
||||||
this.updateTransform()
|
|
||||||
}
|
|
||||||
|
|
||||||
setRotation (newRotation) {
|
|
||||||
this.rotation = newRotation
|
|
||||||
this.updateTransform()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transforms
|
|
||||||
translate (pos) {
|
|
||||||
mat4.translate(this.transform, this.transform, pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
scale (scale) {
|
|
||||||
mat4.scale(this.transform, this.transform, scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
rotate (rot) {
|
|
||||||
if (rot[0] !== 0) {
|
|
||||||
mat4.rotateX(this.transform, this.transform, rot[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rot[1] !== 0) {
|
|
||||||
mat4.rotateY(this.transform, this.transform, rot[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rot[2] !== 0) {
|
|
||||||
mat4.rotateZ(this.transform, this.transform, rot[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
get position () {
|
|
||||||
return this.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
get translation () {
|
|
||||||
return this.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw base
|
|
||||||
draw (gl, shader) {
|
|
||||||
// Set model transform matrix uniform
|
|
||||||
const transformLocation = shader.getUniformLocation(gl, 'uModelMatrix')
|
|
||||||
gl.uniformMatrix4fv(transformLocation, false, this.transform)
|
|
||||||
}
|
|
||||||
|
|
||||||
addChild (ch) {
|
|
||||||
if (!(ch instanceof Node)) return
|
|
||||||
this.children.push(ch)
|
|
||||||
this.updateTransform()
|
|
||||||
}
|
|
||||||
|
|
||||||
setParent (p) {
|
|
||||||
if (!(p instanceof Node)) return
|
|
||||||
this.parent = p
|
|
||||||
this.updateTransform()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Mesh extends Node {
|
|
||||||
static construct (gl, vertices, indices, uvs, normals) {
|
static construct (gl, vertices, indices, uvs, normals) {
|
||||||
// VBO for model vertices
|
// VBO for model vertices
|
||||||
let pos = gl.createBuffer()
|
let pos = gl.createBuffer()
|
||||||
@ -224,124 +37,6 @@ class Mesh extends Node {
|
|||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
static async loadFile (gl, file) {
|
|
||||||
file = '/assets/models/' + file + '.json'
|
|
||||||
|
|
||||||
// Ensure each mesh file is loaded only once
|
|
||||||
if (meshCache[file]) return meshCache[file].length > 1 ? meshCache[file] : meshCache[file][0]
|
|
||||||
|
|
||||||
let dat = await Resource.GET({ type: 'json', url: file })
|
|
||||||
if (!dat.meshes) throw new Error('No meshes defined in file.')
|
|
||||||
|
|
||||||
let cleaned = []
|
|
||||||
let materials = []
|
|
||||||
for (let mi in dat.meshes) {
|
|
||||||
let mesh = dat.meshes[mi]
|
|
||||||
let material
|
|
||||||
|
|
||||||
if (mesh.materialindex != null && dat.materials && dat.materials.length) {
|
|
||||||
// Ensure we don't re-create materials with the same index
|
|
||||||
if (materials[mesh.materialindex]) {
|
|
||||||
material = materials[mesh.materialindex]
|
|
||||||
} else {
|
|
||||||
// Load a new material
|
|
||||||
material = new Material()
|
|
||||||
let matdata = dat.materials[mesh.materialindex].properties
|
|
||||||
|
|
||||||
// Parse material information
|
|
||||||
for (let pi in matdata) {
|
|
||||||
let property = matdata[pi]
|
|
||||||
if (!property || !property.key) continue
|
|
||||||
if (property.key === '?mat.name') material.name = property.value
|
|
||||||
else if (property.key.indexOf('$clr.') === 0) {
|
|
||||||
let dproperty = property.key.substr(5)
|
|
||||||
switch (dproperty) {
|
|
||||||
case 'specular':
|
|
||||||
case 'diffuse':
|
|
||||||
case 'shininess':
|
|
||||||
case 'ambient':
|
|
||||||
case 'reflective':
|
|
||||||
material[dproperty] = property.value
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else if (property.key.indexOf('$tex.file') === 0) {
|
|
||||||
if (!material.textures) {
|
|
||||||
material.textures = []
|
|
||||||
}
|
|
||||||
|
|
||||||
material.textures.push(property.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
materials[mesh.materialindex] = material
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleaned.push({
|
|
||||||
vertices: mesh.vertices,
|
|
||||||
indices: [].concat.apply([], mesh.faces),
|
|
||||||
uv: mesh.texturecoords ? mesh.texturecoords[0] : null,
|
|
||||||
normals: mesh.normals ? mesh.normals : null,
|
|
||||||
material
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load everything
|
|
||||||
let loadComplete = []
|
|
||||||
for (let i in cleaned) {
|
|
||||||
let meshdata = cleaned[i]
|
|
||||||
let mesh = Mesh.construct(gl, meshdata.vertices, meshdata.indices,
|
|
||||||
meshdata.uv, meshdata.normals)
|
|
||||||
|
|
||||||
// Initialize the material's texture if present
|
|
||||||
if (meshdata.material) {
|
|
||||||
mesh.material = meshdata.material
|
|
||||||
|
|
||||||
// Ensure all textures get loaded before finishing
|
|
||||||
if (meshdata.material.textures) {
|
|
||||||
await meshdata.material.loadTextures(gl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadComplete.push(mesh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we need to give the meshes the appropriate parents and transforms.
|
|
||||||
let finished = []
|
|
||||||
function setChildren (parent, chMeshes) {
|
|
||||||
let meshIndex = chMeshes.meshes[0]
|
|
||||||
let mesh = loadComplete[meshIndex]
|
|
||||||
|
|
||||||
if (chMeshes.children) {
|
|
||||||
for (let i in chMeshes.children) {
|
|
||||||
if (!chMeshes.children[i].meshes) continue
|
|
||||||
setChildren(mesh, chMeshes.children[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh.name = chMeshes.name
|
|
||||||
|
|
||||||
if (parent == null) {
|
|
||||||
finished.push(mesh)
|
|
||||||
} else {
|
|
||||||
parent.children.push(mesh)
|
|
||||||
mesh.parent = parent
|
|
||||||
mesh.setTransformation(chMeshes.transformation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rootchildren = dat.rootnode.children
|
|
||||||
for (let j in rootchildren) {
|
|
||||||
if (!rootchildren[j].meshes) continue
|
|
||||||
setChildren(null, rootchildren[j])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the mesh
|
|
||||||
meshCache[file] = finished
|
|
||||||
|
|
||||||
return finished.length > 1 ? finished : finished[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
bindBuffers (gl, shader) {
|
bindBuffers (gl, shader) {
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer)
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer)
|
||||||
shader.setAttribute(gl, 'aVertexPosition', 3, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0)
|
shader.setAttribute(gl, 'aVertexPosition', 3, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0)
|
||||||
@ -359,10 +54,7 @@ class Mesh extends Node {
|
|||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ebo)
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ebo)
|
||||||
}
|
}
|
||||||
|
|
||||||
draw (gl, shader) {
|
prepare (gl, shader) {
|
||||||
// Set model transform uniform
|
|
||||||
super.draw(gl, shader)
|
|
||||||
|
|
||||||
// Bind attrib arrays
|
// Bind attrib arrays
|
||||||
this.bindBuffers(gl, shader)
|
this.bindBuffers(gl, shader)
|
||||||
|
|
||||||
@ -370,16 +62,11 @@ class Mesh extends Node {
|
|||||||
if (this.material) {
|
if (this.material) {
|
||||||
this.material.apply(gl, shader)
|
this.material.apply(gl, shader)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw (gl, shader) {
|
||||||
gl.drawElements(gl.TRIANGLES, this.indices, gl.UNSIGNED_SHORT, 0)
|
gl.drawElements(gl.TRIANGLES, this.indices, gl.UNSIGNED_SHORT, 0)
|
||||||
|
|
||||||
// Invoke children's draw methods
|
|
||||||
for (let i in this.children) {
|
|
||||||
let child = this.children[i]
|
|
||||||
if (!(child instanceof Mesh)) continue
|
|
||||||
child.draw(gl, shader)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Node, Mesh, Texture, Material }
|
export { Mesh }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Engine from './engine'
|
import Engine from './engine'
|
||||||
import Camera from './engine/camera'
|
import Camera from './engine/camera'
|
||||||
import Entity from './engine/mesh/entity'
|
import { MeshInstance } from './engine/components'
|
||||||
|
|
||||||
import { Environment } from './engine/environment'
|
import { Environment } from './engine/environment'
|
||||||
import { Terrain } from './engine/components/terrain'
|
import { Terrain } from './engine/components/terrain'
|
||||||
@ -11,12 +11,10 @@ let game = new Engine()
|
|||||||
let env = new Environment()
|
let env = new Environment()
|
||||||
|
|
||||||
async function pipeline () {
|
async function pipeline () {
|
||||||
let entity = await Entity.createEntity(game.gl, 'test', [0.0, 0.0, -6.0])
|
let entity = await MeshInstance.loadFile(game.gl, 'test', [0.0, 0.0, 0.0])
|
||||||
let shader = await game.shaders.createShaderFromFiles(game.gl, 'basic', false)
|
let shader = await game.shaders.createShaderFromFiles(game.gl, 'basic', false)
|
||||||
let terrainShader = await game.shaders.createShaderFromFiles(game.gl, 'terrain', false)
|
let terrainShader = await game.shaders.createShaderFromFiles(game.gl, 'terrain', false)
|
||||||
|
|
||||||
console.log(entity.mesh)
|
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user