Skip to content

Instantly share code, notes, and snippets.

@andreasplesch
Last active April 27, 2024 02:58
Show Gist options
  • Save andreasplesch/1ee775f917593af42d0bb42a2c7f01ff to your computer and use it in GitHub Desktop.
Save andreasplesch/1ee775f917593af42d0bb42a2c7f01ff to your computer and use it in GitHub Desktop.
InstancedShapeProto test
<X3D ondownloadsfinished='init()'>
<!--head>
<meta content='Prototype_DiffuseApp.x3d' name='title'/>
<meta content='X3D encodings example: defining a Prototype, demonstration of IS/connect definitions.' name='description'/>
<meta content='Andreas Plesch' name='creator'/>
<meta content='21 July 2020' name='created'/>
<meta content='BSD' name='license'/>
</head-->
<Scene>
<ProtoDeclare name="InstancedShape">
<ProtoInterface>
<field accessType="initializeOnly" type="MFNode" name="shapes" value="NULL" />
<field accessType="inputOutput" type="MFVec3f" name="translations" value="" />
<field accessType="inputOutput" type="MFVec3f" name="scales" value="" />
<field accessType="inputOutput" type="MFRotation" name="rotations" value="" />
</ProtoInterface>
<ProtoBody>
<Group>
<IS>
<connect nodeField="children" protoField="shapes" />
</IS>
</Group>
</ProtoBody>
</ProtoDeclare>
<ExternProtoDeclare name="Teapot" url='"https://raw.githubusercontent.com/x3dom/x3dom/master/test/functional/protos/castle/teapot_fallback_implementation.x3d#Teapot"'>
<field accessType="inputOutput" type="SFNode" name="metadata" />
<field accessType="initializeOnly" type="SFVec3f" name="size" />
<field accessType="initializeOnly" type="SFBool" name="solid" />
<field accessType="initializeOnly" type="SFBool" name="manifold" />
<field accessType="inputOutput" type="SFNode" name="texCoord" />
</ExternProtoDeclare>
<InstancedShape
translations='1 0 0, 0 1 0'>
<Shape>
<Appearance>
<Material diffuseColor='0.34 0 0.26' specularColor='1 1 1' shininess='1.6' />
</Appearance>
<Teapot />
</Shape>
</InstancedShape>
<!-- script for gpu instances -->
<script type="text/javascript">
var makeInstances = function() {
var instanceGroup = document.querySelector('InstancedShape')._x3domNode;
var shape = instanceGroup._cf.shapes.nodes[0];
var translations = instanceGroup._vf.translations;
var scales = instanceGroup._vf.scales;
var rotations = instanceGroup._vf.rotations;
var trafos = translations.map(function(t, i) {
return x3dom.fields.SFMatrix4f.fromRotationTranslationScale(rotations[i], translations[i], scales[i]);
});
//positions
var instances = translations.length;
var positions = shape._webgl.positions[0];
var posVec3f = x3dom.fields.MFVec3f.parse(positions.join());
var transformedPositions = trafos.map(function(trafo) {
return new x3dom.fields.MFVec3f(posVec3f.map(function(v, i) {
return trafo.multMatrixPnt(v);
})).toGL()
});
//var positions2 = positions.map( function (v) { return v + 1; } );
//shape._webgl.positions[0] = [].concat(...translatedPositions);
//shape._webgl.positions[0] = flatten(translatedPositions);
shape._webgl.positions[0] = flatten(transformedPositions);
//indices
var indices = shape._webgl.indexes[0];
var indices2 = translations.map(function(t, i) {
return indices.map(function(v) {
return v + i * positions.length / 3;
})
});
//shape._webgl.indexes[0] = [].concat(...indices2);
//shape._webgl.indexes[0] = flatten(indices2);
let ind32 = new Uint32Array( indices.length * instances );
indices2.forEach( function (ind, i) {
ind32.set(ind, i * indices.length );
});
shape._webgl.indexes[0] = ind32;
//normals
//use transpose of inverse
var normals = shape._webgl.normals[0];
var normalsVec3f = x3dom.fields.MFVec3f.parse(normals.join());
//var zeroVec3f = new x3dom.fields.SFVec3f();
var xNormals = trafos.map(function(trafo) {
//trafo.setTranslate( zeroVec3f );
var normalTrafo = trafo.inverse().transpose();
return new x3dom.fields.MFVec3f(normalsVec3f.map(function(n) {
return normalTrafo.multMatrixVec(n);
})).toGL()
});
//shape._webgl.normals[0] = [].concat(...normals2);
shape._webgl.normals[0] = flatten(xNormals);
//texcoords
var texcoords = shape._webgl.texcoords[0];
let tex32 = new Uint32Array( texcoords.length * instances );
//var texcoords2 = translations.map(function(v, i) {
// return texcoords;
//});
//shape._webgl.texcoords[0] = [].concat(...texcoords2);
//shape._webgl.texcoords[0] = flatten(texcoords2);
translations.forEach( function (v, i) {
tex32.set(texcoords, i * texcoords.length );
});
shape._webgl.texcoords[0] = tex32;
shape.setAllDirty();
shape.invalidateVolume();
shape._cf.geometry.node.invalidateVolume();
//debugger;
function flatten(a) {
var out = [];
a.forEach(function(s) {
out.push(...s)
});
return out;
}
};
var init = function() {
makeInstances();
fitscene();
// defined in Viewer
};
//generate translations
var num_instances = 5000
, size = 3;
var dim = size * Math.sqrt(num_instances);
var instanceGroup = document.querySelector('InstancedShape');
var translations = new Array(num_instances).fill(0).map(function(v) {
return [(Math.random() * dim).toFixed(5), 0, (Math.random() * dim).toFixed(5)].join()
});
//instanceGroup.setFieldValue('translations', x3dom.fields.MFVec3f.parse(translations.join()));
instanceGroup.setAttribute('translations', translations.join());
var scales = translations.map(function(v) {
return "1 " + (0.5 + Math.random()).toFixed(3) + " 1"
});
//instanceGroup.setFieldValue('scales', x3dom.fields.MFVec3f.parse(scales.join()));
instanceGroup.setAttribute('scales', scales.join());
var rotations = translations.map(function(v) {
return "0 1 0 " + (Math.random() * 6.283).toFixed(5)
});
//instanceGroup.setFieldValue('rotations', x3dom.fields.MFRotation.parse(rotations.join()));
instanceGroup.setAttribute('rotations', rotations.join());
//makeInstances();
</script>
</Scene>
</X3D>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment