Files
Kepler/engine/mesh.js
2025-11-17 17:18:43 +01:00

739 lines
20 KiB
JavaScript
Executable File

/*
* Copyright 2013, kaj dijkstra ,
* Author, Kaj Dijkstra.
* All rights reserved.
*
*/
import subMesh from './subMesh.js';
import boundingBox from './boundingBox.js';
/**
* Mesh object
**/
class mesh{
constructor( ){
this.gl = gl;
this._className = 'mesh';
this.fileName;
this.name = "new";
this.shaderName;
this.vertexIndexBuffer;
this.vertexPositionBuffer;
this.vertexNormalBuffer;
this.textureCoordBuffer;
this.binormalBuffer = false;
this.tangentBuffer = false;
this.materials = [];
this.subMeshes = [];
this.jsonStruture;
this.shader;
this.forwardShader;
this.renderType = "indexed";
this.materialName;
this.materialId = 1.0;
this.useParallax = false;
this.colorInfoShader;
this.infoShader;
this.materialName;
//this.customShader = new shader();
//this.customShader.createLibraryFomFile("shaders/custom.default.shader");
this.heightmap;
this.useNormal = false;
this.draw_type = gl.TRIANGLES;
this.shape = 3;
this.entityID = 0;
};
/**
* set viewport
* @param {(viewport)} viewport
**/
setViewport( viewport ){
this.viewport = viewport;
this.gl = viewport.gl;
}
/**
* Set custom shader (Not yet in use)
* @param {(String)} name
**/
setCustomShader( name ) {
this.customShader = new shader();
this.customShader.createLibraryFomFile("shaders/custom."+name+".shader");
}
/**
* Set custom shader (Not yet in use)
* @param {(String)} name
**/
addHeightmap( heightmap ) {
this.heightmap = heightmap;
this.colorInfoShader.setUniform("heightmap", heightmap );
this.infoShader.setUniform("heightmap", heightmap );
}
/**
* set material id
* @param {(int)} material id
**/
setMaterialId( id ) {
this.materialId = id;
//this.colorInfoShader.setUniform("materialId", this.materialId / 256 );
}
/**
* Load mesh from file
* @param {(String)} url to file
**/
loadMeshFromFile( url ) {
this.jsonStruture = JSON.parse(kepler.loadTextFileSynchronous('media/models/'+url));
this.fileName = url;
this.parseLoadedMesh();
}
/**
* Combine displacement and normal data in one texture
* @param {(Array)} displacement data
* @param {(Array)} normal data
* @return {(Sampler)} sampler
**/
combineDisplacementNormal( displacement, normal ) {
var displacementImage = displacement.data;
var normalImage = normal.data;
var canvas = document.createElement('Canvas');
var width = displacement.width;
var height = displacement.height;
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(displacementImage, 0, 0, width, height);
var displacementpixelData = canvas.getContext('2d').getImageData(0, 0, width, height).data;
canvas.getContext('2d').drawImage(normalImage, 0, 0, width, height);
var normalpixelData = canvas.getContext('2d').getImageData(0, 0, width, height).data;
var dataArray = [];
for(var x = 0; x<width; x++) {
for(var y = 0; y<height; y++) {
var index = (x + (y * height) ) * 4;
dataArray.push(normalpixelData[index] / 255);
dataArray.push(normalpixelData[index+1] / 255);
dataArray.push(normalpixelData[index+2] / 255);
dataArray.push(displacementpixelData[index] / 255);
}
}
var text = kepler.textureFromArray(dataArray, width, height, true);
var sampler = new sampler2D();
sampler.texture = dataArray;
return sampler;
}
/**
* Create tangent and binormal vectors (* This is slow!!)
**/
createTangentAndBinormal( ) {
var bn = this.viewport.primitives.createTangentsAndBinormals( this.vertexPositionBuffer,
this.vertexNormalBuffer,
this.textureCoordBuffer,
this.vertexIndexBuffer );
if(bn.tangent) {
var tangentArray = this.viewport.primitives.layoutArray(bn.tangent);
var binormalArray = this.viewport.primitives.layoutArray(bn.binormal);
this.binormalBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.binormalBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(binormalArray), this.gl.STATIC_DRAW);
this.binormalBuffer.itemSize = 3;
this.binormalBuffer.numItems = binormalArray.length / 3;
this.binormalBuffer.data = binormalArray;
this.tangentBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.tangentBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(tangentArray), this.gl.STATIC_DRAW);
this.tangentBuffer.itemSize = 3;
this.tangentBuffer.numItems = tangentArray.length / 3;
this.tangentBuffer.data = tangentArray;
}
}
/**
* set mesh name based on the material types that are used
* @param {(MaterialObject)} Material
**/
setName( material ) {
var name = this.name;
if(material.normals.length > 0)
name += "_normal";
if(material.useParallax)
name += "_parallax";
if(material.textures.length > 0)
name += "_texture";
if(material.transparencyMaps.length > 0)
name += "_transparent";
if(material.specularMaps.length > 0)
name += "_specular";
this.shaderName = name;
}
/**
* add material to mesh
* @param {(MaterialObject)} Material
**/
addMaterial( material ) {
if(!material.created) {
material.create();
}
this.material = material;
this.material.setViewport( this.viewport );
this.material.entityID = this.entityID;
/*
this.shader = new shader();
this.shader.definePragma("TEXTURE", (material.textures.length > 0) ? 1.0 : 0.0 );
this.shader.definePragma("NORMAL_MAP", (material.normals.length > 0) ? 1.0 : 0.0 );
this.shader.definePragma("ROUGHNESS_MAP", (material.roughnessMaps.length > 0) ? 1.0 : 0.0 );
this.shader.definePragma("SHADING_MODEL_ID", material.shadingModelID );
this.shader.definePragma("PARALLAX", (material.useParallax) ? 1.0 : 0.0 );
this.shader.definePragma("DEFERRED", 1.0 );
this.shader.createFomFile("shaders/color.shader");
this.updateShader(material, this.shader);
this.forwardShader = new shader();
this.forwardShader.definePragma("TEXTURE", (material.textures.length > 0) ? 1.0 : 0.0 );
this.forwardShader.definePragma("NORMAL_MAP", (material.normals.length > 0) ? 1.0 : 0.0 );
this.forwardShader.definePragma("ROUGHNESS_MAP", (material.roughnessMaps.length > 0) ? 1.0 : 0.0 );
this.forwardShader.definePragma("SHADING_MODEL_ID", material.shadingModelID );
this.forwardShader.definePragma("PARALLAX", (material.useParallax) ? 1.0 : 0.0 );
this.forwardShader.definePragma("DEFERRED", 0 );
this.forwardShader.createFomFile("shaders/color.shader");
this.updateShader(material, this.forwardShader);
//forwardShader
this.updateMaterial();
*/
}
updateShader( material, shader ) {
shader.setUniform("far", kepler.mainCamera.far );
//this.shader = kepler.resources.getShader("shaders/color.shader");
shader.setUniform("reflectionSampler", kepler.system.reflectionSampler );
if( material.textures.length > 0 ) {
material.textures[0].anisotropic = 4;
if( material.textures.length > 0 ) {
shader.setUniform("diffuseSampler", material.textures[0] );
}
if( material.transparencyMaps.length > 0 ) {
shader.setUniform("transparencyMapSampler", material.transparencyMaps[0] );
}
if( material.normals.length > 0 ) {
shader.setUniform("normalSampler", material.normals[0] );
}
if( material.roughnessMaps.length > 0 ) {
shader.setUniform("normalSampler", material.roughnessMaps[0] );
}
if( material.displacementMaps.length > 0 ) {
shader.setUniform("heightSampler", material.displacementMaps[0]);
}
} else {
shader.setUniform("diffuseColor", material.diffuseColor );
//var color = material.color;
//this.shader.setUniform("rgb", color );
}
shader.setUniform("roughness", material.roughness );
shader.setUniform("id", material.id );
shader.setUniform("clearCoat", 1 );
shader.setUniform("clearCoatThickness", 1 );
shader.setUniform("clearCoatIOR", 1 );
shader.setUniform("anisotropy", 1 );
shader.setUniform("lightIntensity", 2);
shader.setUniform("environmentLuminance", 1 );
shader.setUniform("lightGeometry", [1,1,1] );
shader.setUniform("clearCoatColor", [1,1,1] );
shader.setUniform("lightColor", [1,1,1] );
var sphericalHarmonics = [];
for(var c = 0; c<8; c++) {
sphericalHarmonics.push([1,1,1]);
}
shader.setUniform("sphericalHarmonics", sphericalHarmonics );
}
updateMaterial( ) {
this.shader.setUniform("roughness", this.material.roughness );
this.forwardShader.setUniform("roughness", this.material.roughness );
this.forwardShader.setUniform("alpha", this.material.alpha );
console.log("roughness", this.material.roughness,this.shader );
}
/**
* load object from file >?>
* @param {(string)} url
**/
loadObjFromFile( url ) {
var objText = kepler.loadTextFileSynchronous(url);
var obj = {};
var vertexMatches = objText.match(/^v( -?\d+(\.\d+)?){3}$/gm);
if (vertexMatches)
{
console.log(obj.vertices = vertexMatches.map(function(vertex)
{
var vertices = vertex.split(" ");
vertices.shift();
return vertices;
}));
}
}
/**
* parse mesh, load extra mesh data into buffers
* @param {(string)} url
**/
parseLoadedMesh( url ) {
var subMeshObject = new subMeshObject();
if(this.jsonStruture.indices) {
this.renderType = "indexed";
subMeshObject.indices = this.jsonStruture.indices;
this.vertexIndexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.vertexIndexBuffer);
//if(kepler.extensions.elementIndexUint)
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(subMeshObject.indices), this.gl.STATIC_DRAW);
//else
// this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(subMeshObject.indices), this.gl.STATIC_DRAW);
this.vertexIndexBuffer.itemSize = 3;
this.vertexIndexBuffer.numItems = subMeshObject.indices.length;
this.vertexIndexBuffer.data = subMeshObject.indices;
} else {
this.renderType = "array";
}
subMeshObject.vertices = this.jsonStruture.positions;
this.vertexPositionBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexPositionBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(subMeshObject.vertices), this.gl.STATIC_DRAW);
this.vertexPositionBuffer.itemSize = 3;
this.vertexPositionBuffer.numItems = subMeshObject.vertices.length / 3;
this.vertexPositionBuffer.data = subMeshObject.vertices;
if(this.jsonStruture.uv) {
subMeshObject.textcoords = this.jsonStruture.uv;
this.textureCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureCoordBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(subMeshObject.textcoords), this.gl.STATIC_DRAW);
this.textureCoordBuffer.itemSize = 2;
this.textureCoordBuffer.numItems = subMeshObject.textcoords.length / 2;
this.textureCoordBuffer.data = subMeshObject.textcoords;
}
if(this.jsonStruture.normals) {
subMeshObject.normals = this.jsonStruture.normals;
this.vertexNormalBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexNormalBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(subMeshObject.normals), this.gl.STATIC_DRAW);
this.vertexNormalBuffer.itemSize = 3;
this.vertexNormalBuffer.numItems = subMeshObject.normals.length / 3;
this.vertexNormalBuffer.data = subMeshObject.normals;
}
this.subMeshes.push(subMeshObject);
}
copyMesh( mesh ) {
this.createdBuffers = false;
this.indices = mesh.indices;
this.vertices = mesh.vertices;
this.normals = mesh.normals;
this.textureCoordinates = mesh.textureCoordinates;
this.tangents = mesh.tangents;
this.binormals = mesh.binormals;
}
/**
* Create mesh from arrays
* @param {(array)} indices
* @param {(array)} vertices
* @param {(array)} normals
* @param {(array)} uvs
* @param {(array)} tangents
* @param {(array)} binormals
**/
createMeshFromArrays( indices, vertices, normals, textureCoordinates, tangents, binormals ) {
//todo: loop trough sub meshes
//var subMeshObject = new subMesh();
this.createdBuffers = false;
this.indices = indices;
this.vertices = vertices;
this.normals = normals;
this.textureCoordinates = textureCoordinates;
this.tangents = tangents;
this.binormals = binormals;
/*
if(indices) {
this.renderType = "indexed";
//subMeshObject.indices = indices;
this.vertexIndexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.vertexIndexBuffer);
//if(kepler.extensions.elementIndexUint)
// this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(subMeshObject.indices), this.gl.STATIC_DRAW);
//else
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(indices), this.gl.STATIC_DRAW);
this.vertexIndexBuffer.itemSize = 3;
this.vertexIndexBuffer.numItems = indices.length;
this.vertexIndexBuffer.data = indices;
} else {
this.renderType = "array";
}
//subMeshObject.vertices = vertices;
this.vertexPositionBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexPositionBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
this.vertexPositionBuffer.itemSize = 3;
this.vertexPositionBuffer.numItems = vertices.length / 3;
this.vertexPositionBuffer.data = vertices;
if(uvs) {
//subMeshObject.textcoords = uvs;
this.textureCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureCoordBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(uvs), this.gl.STATIC_DRAW);
this.textureCoordBuffer.itemSize = 2;
this.textureCoordBuffer.numItems = uvs.length / 2;
this.textureCoordBuffer.data = uvs;
}
if(normals) {
//subMeshObject.normals = normals;
this.vertexNormalBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexNormalBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(normals), this.gl.STATIC_DRAW);
this.vertexNormalBuffer.itemSize = 3;
this.vertexNormalBuffer.numItems = normals.length / 3;
this.vertexNormalBuffer.data = normals;
}
if(tangents) {
//subMeshObject.tangents = tangents;
this.tangentBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.tangentBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(tangents), this.gl.STATIC_DRAW);
this.tangentBuffer.itemSize = 3;
this.tangentBuffer.numItems = tangents.length / 3;
this.tangentBuffer.data = tangents;
} else {
this.createTangentAndBinormal();
}
if(binormals) {
this.binormalBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.binormalBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(binormals), this.gl.STATIC_DRAW);
this.binormalBuffer.itemSize = 3;
this.binormalBuffer.numItems = binormals.length / 3;
this.binormalBuffer.data = binormals;
}
*/
//this.subMeshes.push(subMeshObject);
this.boundingBox = new boundingBox();
this.boundingBox.fitBoxToPoints_( vertices );
}
createBuffers() {
if(!this.createdBuffers) {
if(this.indices) {
this.renderType = "indexed";
this.vertexIndexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.vertexIndexBuffer);
//if(kepler.extensions.elementIndexUint)
// this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(subMeshObject.indices), this.gl.STATIC_DRAW);
//else
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(this.indices), this.gl.STATIC_DRAW);
this.vertexIndexBuffer.itemSize = this.shape;
this.vertexIndexBuffer.numItems = this.indices.length;
this.vertexIndexBuffer.data = this.indices;
} else {
this.renderType = "array";
}
this.vertexPositionBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexPositionBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.vertices), this.gl.STATIC_DRAW);
this.vertexPositionBuffer.itemSize = 3;
this.vertexPositionBuffer.numItems = this.vertices.length / 3;
this.vertexPositionBuffer.data = this.vertices;
if(this.textureCoordinates) {
this.textureCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureCoordBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.textureCoordinates), this.gl.STATIC_DRAW);
this.textureCoordBuffer.itemSize = 2;
this.textureCoordBuffer.numItems = this.textureCoordinates.length / 2;
this.textureCoordBuffer.data = this.textureCoordinates;
}
if(this.normals) {
this.vertexNormalBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexNormalBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.normals), this.gl.STATIC_DRAW);
this.vertexNormalBuffer.itemSize = 3;
this.vertexNormalBuffer.numItems = this.normals.length / 3;
this.vertexNormalBuffer.data = this.normals;
}
if(this.tangents) {
this.tangentBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.tangentBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.tangents), this.gl.STATIC_DRAW);
this.tangentBuffer.itemSize = 3;
this.tangentBuffer.numItems = this.tangents.length / 3;
this.tangentBuffer.data = this.tangents;
} else {
if(this.draw_type != this.gl.LINES)
this.createTangentAndBinormal();
}
if(this.binormals) {
this.binormalBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.binormalBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.binormals), this.gl.STATIC_DRAW);
this.binormalBuffer.itemSize = 3;
this.binormalBuffer.numItems = this.binormals.length / 3;
this.binormalBuffer.data = this.binormals;
}
this.createdBuffers = true;
}
}
/**
* write content to ext console
* @param {(string)} content
**/
writeConsole(content) {
top.consoleRef=window.open('','myconsole',
'width=350,height=250'
+',menubar=0'
+',toolbar=1'
+',status=0'
+',scrollbars=1'
+',resizable=1')
top.consoleRef.document.writeln(
'<html><head><title>Console</title></head>'
+'<body bgcolor=white onLoad="self.focus()">'
+content
+'</body></html>'
)
top.consoleRef.document.close()
}
/**
* Show tangent
* @param {(subMeshObject)}
**/
showTangent( subMeshObject ) {
writeConsole( this.fileName + ' Tangent ' + JSON.stringify(this.tangentBuffer.data) );
}
/**
* Show Binormal
* @param {(subMeshObject)}
**/
showBinormal( subMeshObject ) {
var tangentArray = this.binormalBuffer.data;
var a = [];
for(var c = 0; c<tangentArray.length;c++){
var s = tangentArray[c];
a[c] = parseFloat(s.toFixed(5));
}
writeConsole( this.fileName + ' binormal ' + JSON.stringify(a) );
}
/**
* add subMeshObject to mesh
* @param {(subMeshObject)}
**/
addsubMeshObject( subMeshObject ) {
this.vertexIndexBuffer = subMeshObject.indexBuffer;
this.vertexPositionBuffer = subMeshObject.vertexBuffer;
this.vertexNormalBuffer = subMeshObject.normalBuffer;
this.textureCoordBuffer = subMeshObject.uvBuffer;
this.tangentBuffer = subMeshObject.tangentBuffer;
this.binormalBuffer = subMeshObject.binormalBuffer;
this.subMeshes.push(subMeshObject);
}
}
export {mesh as default};