Public
Edited
Dec 5, 2022
Fork of gltf Whale
2 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
indices = whale.scenes[0].children[1].children[1].geometry.index.array
Insert cell
positions = whale.scenes[0].children[1].children[1].geometry.attributes.position.array//num components 3
Insert cell
normals = whale.scenes[0].children[1].children[1].geometry.attributes.normal.array //num components 3
Insert cell
uvs = whale.scenes[0].children[1].children[1].geometry.attributes.uv.array //num components 2
Insert cell
skinWeights = whale.scenes[0].children[1].children[1].geometry.attributes.skinWeight.array //num components 4
Insert cell
skinIndices = whale.scenes[0].children[1].children[1].geometry.attributes.skinIndex.array //num components 4
Insert cell
Insert cell
gl = {
const myCanvas = DOM.canvas(720, 480);
const gl = myCanvas.getContext("webgl2");
gl.enable(gl.DEPTH_TEST);
gl.clearColor(.8,.8,1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
return gl;
}
Insert cell
Insert cell
shaders = ({
vs: `#version 300 es
precision mediump float;
in vec3 position;
in vec3 normal;
in vec4 skinWeights;
in uvec4 skinIndices;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 bonesMatrix[1];
out vec3 fragNormal;
out vec3 fragPosition;
void main () {
vec4 newPosition =
(
bonesMatrix[skinIndices[0]] * vec4(position,1.0) * skinWeights[0] +
bonesMatrix[skinIndices[1]] * vec4(position,1.0) * skinWeights[1] +
bonesMatrix[skinIndices[2]] * vec4(position,1.0) * skinWeights[2] +
bonesMatrix[skinIndices[3]] * vec4(position,1.0) * skinWeights[3]
);

mat4 skinMatrix = (
skinWeights.x * bonesMatrix[int(skinIndices.x)] +
skinWeights.y * bonesMatrix[int(skinIndices.y)] +
skinWeights.z * bonesMatrix[int(skinIndices.z)] +
skinWeights.w * bonesMatrix[int(skinIndices.w)]
);
fragPosition = newPosition.xyz;

// gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4(position,1);

mat4 normalMatrix = transpose(inverse(modelMatrix));
fragNormal = normalize((normalMatrix*vec4(normal,0)).xyz);

gl_Position = projectionMatrix * viewMatrix * modelMatrix * skinMatrix * vec4(position, 1.0);
}`,

fs: `#version 300 es
precision mediump float;
in vec3 fragNormal;
in vec3 fragPosition;

uniform vec4 light;
uniform vec4 material;

out vec4 outColor;
void main () {
vec3 N = normalize(fragNormal);
vec3 L;
if(light.w == 0.0){
L = normalize(light.xyz);
}else{
L = normalize(light.xyz - fragPosition);
}

vec3 color = material.rgb * clamp(dot(N,L), 0.0, 1.0);//Compute color
// vec3 color = vec3(1,1,1);
outColor = vec4(color, material.a);

}`
});
Insert cell
errorBlock = html`<textarea style="height : 20px; width : ${width}px; font-size: 0.8em; display: block"></textarea>`
Insert cell
programInfo = {
errorBlock.style.height = "20px";
errorBlock.innerHTML = "Program Shader compilation successful";
return twgl.createProgramInfo(gl, [shaders.vs, shaders.fs], (message) => {
errorBlock.style.height = "400px";
errorBlock.innerHTML = "Program Shader compilation error\n" + message;
});
}
Insert cell
Insert cell
bufferInfo = twgl.createBufferInfoFromArrays(gl, vertexAttributes);
Insert cell
lookAtPosition = [0,0,0]
Insert cell
eyePosition = [-3.37,6.47,1.29]
Insert cell
transformedEyePosition = m4.transformPoint(m4.multiply(m4.rotationY(viewParameters.yAngle*Math.PI/180),m4.rotationX(viewParameters.xAngle*Math.PI/180)), eyePosition)
Insert cell
fov = 55;
Insert cell
uniforms = ({
light: [1,1,3,0],
projectionMatrix: m4.perspective(viewParameters.fov * Math.PI/180, gl.canvas.width/gl.canvas.height, 0.01,200),
viewMatrix: m4.inverse( m4.lookAt(transformedEyePosition, lookAtPosition, [0,1,0])),
modelMatrix: m4.identity(),
eyePosition: eyePosition,
material: [1, 1, 1, 0.5],
bonesMatrix: bonesUniform
})
Insert cell
Insert cell
whale = {
const gltfLoader = new THREE.GLTFLoader();
const blob = await FileAttachment("whale.CYCLES.glb").blob();
const url = URL.createObjectURL(blob);

const dracoLoader = new THREE.DRACOLoader();
dracoLoader.setDecoderPath("https://www.gstatic.com/draco/v1/decoders/")
gltfLoader.setDRACOLoader( dracoLoader );

const gltf = await new Promise( resolve => gltfLoader.load(url, gltf => resolve(gltf) ));
const whale = gltf;

return whale;
}
Insert cell
Insert cell
numBones = 6;
Insert cell
Insert cell
cubeInverseBindMatrices = whale.scenes[0].children[1].children[1].skeleton.boneInverses

Insert cell
Insert cell
cubeJointListFlat = {
const cubeJointListFlat = []
for(let i = 0; i < numBones; i++){
const currentJoint = createJoint(cubeSkeleton, cubeInverseBindMatrices, i);
cubeJointListFlat.push(currentJoint);
}
return cubeJointListFlat;
}
Insert cell
Insert cell
{
cubeJointListFlat[0].arrIndex = 0
cubeJointListFlat[0].parentArrIndex = -1

cubeJointListFlat[1].arrIndex = 1
cubeJointListFlat[1].parentArrIndex = 0

cubeJointListFlat[2].arrIndex = 2
cubeJointListFlat[2].parentArrIndex = 0
cubeJointListFlat[3].arrIndex = 3
cubeJointListFlat[3].parentArrIndex = 0

cubeJointListFlat[4].arrIndex = 4
cubeJointListFlat[4].parentArrIndex = 3

cubeJointListFlat[5].arrIndex = 5
cubeJointListFlat[5].parentArrIndex = 4
}
Insert cell
Insert cell
function updateWorldMatrices() {
for(let i = 0; i < 6; i++){
if(cubeJointListFlat[i].parentArrIndex != -1){
m4.multiply(
cubeJointListFlat[cubeJointListFlat[i].parentArrIndex].worldMatrix,
cubeJointListFlat[i].localMatrix,
cubeJointListFlat[i].worldMatrix //dst
)
} else {
m4.copy(cubeJointListFlat[i].localMatrix, cubeJointListFlat[i].worldMatrix)
}
}
}
Insert cell
updateWorldMatrices()
Insert cell
Insert cell
// {
// for(let i = 0; i < 6; i++){
// m4.copy(cubeJointListFlat[i].worldMatrix, cubeJointListFlat[i].bindMatrix)
// }
// }
Insert cell
Insert cell
bonesUniform = [
m4.identity(),
m4.identity(),
m4.identity(),
m4.identity(),
m4.identity(),
m4.identity()
]
Insert cell
Insert cell
function updateBonesUniform(params) {
for(let i = 0; i < 6; i++){
m4.multiply(cubeJointListFlat[i].worldMatrix, cubeJointListFlat[i].inverseBindMatrix, bonesUniform[i])
}
}
Insert cell
Insert cell
Insert cell
THREE = {
const THREE = window.THREE = await require('three');
await require('three/examples/js/loaders/GLTFLoader.js').catch(() => {});
await require('three/examples/js/loaders/DRACOLoader.js').catch(() => {});
return THREE;
}
Insert cell
twgl = require("twgl.js")
Insert cell
m4 = twgl.m4;
Insert cell
import {columns} from "@bcardiff/observable-columns"
Insert cell
import {slider, radio} from "@jashkenas/inputs"
Insert cell
import {node, composeMatrix, composeMatrixQuat} from "@dboyd/scene-graph-functions"
Insert cell
function getParentIndex(joint, jointList)
{
for(let i = 0; i < numBones; i++){
if(jointList[i].name == joint.futureParent){
return jointList[i].index;
} else {
return null;
}
}
}

Insert cell
function createJoint(skeleton, inverseBindMatrices, i) {
let parent = null;
if(skeleton.bones[i].parent.type == "Bone"){
parent = skeleton.bones[i].parent.name;
}
let currentJoint = ({
index: i,
arrIndex: -1,
parentArrIndex: -1,
name: skeleton.bones[i].name,
futureParent: parent,
parent: null,
children: [],
position:
[
cubeSkeleton.bones[i].position.x,
cubeSkeleton.bones[i].position.y,
cubeSkeleton.bones[i].position.z
],
rotation:
[
cubeSkeleton.bones[i].rotation._x,
cubeSkeleton.bones[i].rotation._y,
cubeSkeleton.bones[i].rotation._z
],
rotationQuat:
[
cubeSkeleton.bones[i].quaternion._x,
cubeSkeleton.bones[i].quaternion._y,
cubeSkeleton.bones[i].quaternion._z,
cubeSkeleton.bones[i].quaternion._w
],
scale: [1,1,1],
localMatrix: m4.identity(),
worldMatrix: m4.identity(),
bindMatrix: m4.identity(),
inverseBindMatrix: cubeInverseBindMatrices[i].elements
})

composeMatrixQuat(currentJoint.position, currentJoint.rotationQuat, currentJoint.scale, currentJoint.localMatrix);

return currentJoint;

}
Insert cell
function createJointTree(inputJointList)
{
let jointList = inputJointList;
for(let i = 0; i < numBones; i++){
if(getParentIndex(jointList[i], jointList)){
jointList[getParentIndex(jointList[i], jointList)].children.push(jointList[i])
}
}
return jointList[0]
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more