Skip to content

Commit

Permalink
addressed some pull request comments. cleaned up some comments and he…
Browse files Browse the repository at this point in the history
…lpers.
  • Loading branch information
likangning93 committed Jun 20, 2016
1 parent ebe5471 commit 9efcfbd
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 56 deletions.
39 changes: 25 additions & 14 deletions lib/NodeHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,32 +132,43 @@ function getLocalMatrix4(node, result) {
return Matrix4.fromTranslationQuaternionRotationScale(translation, rotation, scale, result);
}

var packedParametersScratch = {
meshes : undefined,
parameters : undefined,
primitiveFunction : undefined
};

// Perform an operation on each primitive in a scene.
// PrimitiveFunction should expect primitive, a meshPrimitiveID, some parameters, and the node itself
// Requires parameters to contain gltf.meshes and the primitive function.
function forEachPrimitiveInScene(gltf, scene, parameters) {
function forEachPrimitiveInScene(gltf, scene, primitiveFunction, parameters) {
var rootNodeNames = scene.nodes;
var allNodes = gltf.nodes;
packedParametersScratch.meshes = gltf.meshes;
packedParametersScratch.parameters = parameters;
packedParametersScratch.primitiveFunction = primitiveFunction;
for (var nodeID in rootNodeNames) {
if (rootNodeNames.hasOwnProperty(nodeID)) {
var rootNodeName = rootNodeNames[nodeID];
depthFirstTraversal(allNodes[rootNodeName], allNodes, forEachPrimitiveInNode, parameters);
depthFirstTraversal(allNodes[rootNodeName], allNodes, forEachPrimitiveInNode, packedParametersScratch);
}
}
}

function forEachPrimitiveInNode(parameters, node) {
function forEachPrimitiveInNode(packedParameters, node) {
var meshes = packedParameters.meshes;
var parameters = packedParameters.parameters;
var primitiveFunction = packedParameters.primitiveFunction;

var meshIDs = node.meshes;
for (var meshIndex in meshIDs) {
if (meshIDs.hasOwnProperty(meshIndex)) {
var meshID = meshIDs[meshIndex];
var meshData = parameters.meshes[meshID];
var primitives = meshData.primitives;
for (var primitiveID in primitives) {
if (primitives.hasOwnProperty(primitiveID)) {
parameters.primitiveFunction(primitives[primitiveID], meshID + '_' + primitiveID, parameters, node);
}
}
if (!defined(meshIDs)) {
return;
}
for (var i = 0; i < meshIDs.length; i++) {
var meshID = meshIDs[i];
var meshData = meshes[meshID];
var primitives = meshData.primitives;
for (var j = 0; j < primitives.length; j++) {
primitiveFunction(primitives[j], meshID + '_' + j, parameters, node);
}
}
}
61 changes: 32 additions & 29 deletions lib/bakeAmbientOcclusion.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var Cartesian3 = Cesium.Cartesian3;
var Matrix3 = Cesium.Matrix3;
var Matrix4 = Cesium.Matrix4;
var Quaternion = Cesium.Quaternion;
var WebGLConstants = Cesium.WebGLConstants;
var Jimp = require('jimp');

var Ray = Cesium.Ray;
Expand All @@ -33,30 +34,29 @@ var quaternionScratch = new Quaternion();
var matrix3Scratch = new Matrix3();

function bakeAmbientOcclusion(gltf, options) {
// requires each mesh to occur only once in the scene
// Requires each mesh to occur only once in the scene
var sceneID = defaultValue(options.scene, gltf.scene);
if (!defined(sceneID)) {
sceneID = Object.keys(gltf.scenes)[0];
}
var scene = gltf.scenes[sceneID];

// generate triangle soup
// Generate triangle soup
var raytracerScene = generateRaytracerScene(gltf, scene, options);

// Raytrace to a new texture for each primitive
var parameters = {
meshes: gltf.meshes,
raytracerScene: raytracerScene,
resolution: options.resolution,
primitiveFunction: raytracePrimitiveTexels
resolution: options.resolution
};
NodeHelpers.forEachPrimitiveInScene(gltf, scene, raytracePrimitiveTexels, parameters);

// raytrace to a new texture for each primitive
NodeHelpers.forEachPrimitiveInScene(gltf, scene, parameters);

////////// add to the gltf //////////
// Add to the gltf
bakeToDiffuse(gltf, scene, options.resolution, raytracerScene);
}

////////// adding to the gltf //////////

function bakeToDiffuse(gltf, scene, resolution, raytracerScene) {
// find material with a diffuse texture parameter to clone as needed
var materials = gltf.materials;
Expand Down Expand Up @@ -94,13 +94,11 @@ function bakeToDiffuse(gltf, scene, resolution, raytracerScene) {
exampleImageID: exampleImageID,
resolution: resolution,
gltf: gltf,
meshes: gltf.meshes,
raytracerScene: raytracerScene,
primitiveFunction: addAoToImage
raytracerScene: raytracerScene
};

// Bake AO for each primitive in the scene
NodeHelpers.forEachPrimitiveInScene(gltf, scene, parameters);
NodeHelpers.forEachPrimitiveInScene(gltf, scene, addAoToImage, parameters);
}

function addAoToImage(primitive, meshPrimitiveID, parameters) {
Expand Down Expand Up @@ -131,7 +129,7 @@ function addAoToImage(primitive, meshPrimitiveID, parameters) {
}

function postProcessAO(aoBuffer, dataResolution, goalResolution, jimpAO) {
// copy the data over to the jimp
// Copy the data over to the jimp
var value = 0.0;
jimpAO.resize(dataResolution, dataResolution);
for (var x = 0; x < dataResolution; x++) {
Expand All @@ -141,7 +139,7 @@ function postProcessAO(aoBuffer, dataResolution, goalResolution, jimpAO) {
jimpAO.bitmap.data[(dataResolution * y + x) * 4 + 3] = value;
}
}
// resize the data to match the goal resolution
// Resize the data to match the goal resolution
jimpAO.resize(goalResolution, goalResolution, Jimp.RESIZE_BEZIER);
}

Expand Down Expand Up @@ -183,18 +181,18 @@ function ensureImageUniqueness(gltf, primitive, meshPrimitiveID, state) {
var allTextures = gltf.textures;
var allImages = gltf.images;

// generate some new IDs
// Generate some new IDs
var newMaterialID = meshPrimitiveID + '_AO_material';
var newTextureID = meshPrimitiveID + '_AO_texture';
var newImageID = meshPrimitiveID + '_AO_image';

// grab the existing material
// Grab the existing material
var materialID = primitive.material;
var material = allMaterials[materialID];
var values = material.values;
var diffuse = values.diffuse;

// check if the material has a diffuse texture material. if not,
// Check if the material has a diffuse texture material. if not,
// - clone the example material
// - clone the example texture
// - clone the example image. resize to resolution and set to diffuse color, if any
Expand Down Expand Up @@ -260,7 +258,7 @@ function ensureImageUniqueness(gltf, primitive, meshPrimitiveID, state) {
////////// loading //////////

function generateRaytracerScene(gltf, scene, options) {
// set up data we need for sampling. generate "triangle soup" over the whole scene.
// Set up data we need for sampling. generate "triangle soup" over the whole scene.
var accessors = gltf.accessors;

// read all accessors in one go to avoid repeated read-and-conversion
Expand Down Expand Up @@ -288,23 +286,26 @@ function generateRaytracerScene(gltf, scene, options) {
NodeHelpers.computeFlatTransformScene(scene, gltf.nodes);

var parameters = {
meshes: gltf.meshes,
resolution: options.resolution,
raytracerScene: raytracerScene,
primitiveFunction: processPrimitive
raytracerScene: raytracerScene
};

NodeHelpers.forEachPrimitiveInScene(gltf, scene, parameters);
NodeHelpers.forEachPrimitiveInScene(gltf, scene, processPrimitive, parameters);

return raytracerScene;
}

function processPrimitive(primitive, meshPrimitiveID, parameters, node) {
// AO only works with triangles
if (defined(primitive.mode) && primitive.mode !== WebGLConstants.TRIANGLES) {
throw new DeveloperError('In stage bakeAmbientOcclusion: baking AO only supports triangle primitives.');
}

var raytracerScene = parameters.raytracerScene;
var bufferDataByAccessor = raytracerScene.bufferDataByAccessor;
var indices = bufferDataByAccessor[primitive.indices].data;
var positions = bufferDataByAccessor[primitive.attributes.POSITION].data;
var numTriangles = indices.length / 3;
var numberTriangles = indices.length / 3;
var transform = node.extras._pipeline.flatTransform;

var resolution = parameters.resolution;
Expand All @@ -316,7 +317,7 @@ function processPrimitive(primitive, meshPrimitiveID, parameters, node) {
};

// Read each triangle's Cartesian3s using the index buffer
for (var i = 0; i < numTriangles; i++) {
for (var i = 0; i < numberTriangles; i++) {
var index0 = indices[i * 3];
var index1 = indices[i * 3 + 1];
var index2 = indices[i * 3 + 2];
Expand All @@ -339,6 +340,8 @@ function processPrimitive(primitive, meshPrimitiveID, parameters, node) {
}
}

////////// rendering //////////

function raytracePrimitiveTexels(primitive, meshPrimitiveID, parameters, node) {
var raytracerScene = parameters.raytracerScene;
var bufferDataByAccessor = raytracerScene.bufferDataByAccessor;
Expand Down Expand Up @@ -443,7 +446,7 @@ function computeAmbientOcclusionAt(position, normal, numberSamples, sqrtNumberSa
}

function naiveRaytrace(triangleSoup, ray, nearCull) {
// check ray against every triangle in the soup. return the nearest intersection.
// Check ray against every triangle in the soup. return the nearest intersection.
var minIntersect = Number.POSITIVE_INFINITY;
for (var triangleSoupIndex = 0; triangleSoupIndex < triangleSoup.length; triangleSoupIndex++) {
var positions = triangleSoup[triangleSoupIndex].positions;
Expand All @@ -464,7 +467,7 @@ function generateJitteredRay(position, normal, sampleNumber, sqrtNumberSamples)
var s = (sampleNumber % sqrtNumberSamples) * cellWidth + (Math.random() / sqrtNumberSamples);
var t = Math.floor(sampleNumber / sqrtNumberSamples) * cellWidth + (Math.random() / sqrtNumberSamples);

// generate ray on a y-up hemisphere with cosine weighting (more rays around the normal)
// Generate ray on a y-up hemisphere with cosine weighting (more rays around the normal)
var u = 2.0 * Math.PI * s;
var v = Math.sqrt(1.0 - t);

Expand All @@ -473,7 +476,7 @@ function generateJitteredRay(position, normal, sampleNumber, sqrtNumberSamples)
randomDirection.y = t;
randomDirection.z = v * Math.sin(u);

// orient with texel's normal in world space
// Orient with texel's normal in world space
var theta = Math.acos(normal.y); // dot product of normal with y-up is normal.y
var axis = Cartesian3.cross(randomDirection, normal, cartesian3Scratch1);
var rotation = Quaternion.fromAxisAngle(axis, theta, quaternionScratch);
Expand All @@ -484,7 +487,7 @@ function generateJitteredRay(position, normal, sampleNumber, sqrtNumberSamples)
return scratchRay;
}

// borrowed straight from Cesium/Source/Core/IntersectionTests
// Borrowed straight from Cesium/Source/Core/IntersectionTests
var scratchEdge0 = new Cartesian3();
var scratchEdge1 = new Cartesian3();
var scratchPVec = new Cartesian3();
Expand Down
10 changes: 4 additions & 6 deletions specs/lib/bakeAmbientOcclusionSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,13 +479,11 @@ describe('bakeAmbientOcclusion', function() {
var meshes = boxOverGroundGltfClone.meshes;

var scene = boxOverGroundGltfClone.scenes[boxOverGroundGltfClone.scene];
var parameters = {
meshes : boxOverGroundGltfClone.meshes,
primitiveFunction : function(primitive) {
primitive.material = materialID;
}
var primitiveFunction = function(primitive) {
primitive.material = materialID;
};
NodeHelpers.forEachPrimitiveInScene(boxOverGroundGltfClone, scene, parameters);

NodeHelpers.forEachPrimitiveInScene(boxOverGroundGltfClone, scene, primitiveFunction);

var options = {
numberSamples: 1,
Expand Down
14 changes: 7 additions & 7 deletions specs/lib/nodeHelpersSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,18 +181,18 @@ describe('NodeHelpers', function() {
var scene = gltf.scenes[gltf.scene];

var functionParameters = {
meshes: gltf.meshes,
primitiveFunction: function(primitive, meshPrimitiveID, parameters) {
parameters.numberPrimitives++;
parameters.primitiveMeshIDs.push(meshPrimitiveID);
parameters.materialIDs.push(primitive.material);
},
numberPrimitives: 0,
primitiveMeshIDs: [],
materialIDs: []
};

NodeHelpers.forEachPrimitiveInScene(gltf, scene, functionParameters);
var primitiveFunction = function(primitive, meshPrimitiveID, parameters) {
parameters.numberPrimitives++;
parameters.primitiveMeshIDs.push(meshPrimitiveID);
parameters.materialIDs.push(primitive.material);
};

NodeHelpers.forEachPrimitiveInScene(gltf, scene, primitiveFunction, functionParameters);

expect(functionParameters.numberPrimitives).toEqual(5);
expect(functionParameters.primitiveMeshIDs[0]).toEqual('meshTest_0');
Expand Down

0 comments on commit 9efcfbd

Please sign in to comment.