Skip to content

Instantly share code, notes, and snippets.

@SuddenDevelopment
Last active May 6, 2024 21:08
Show Gist options
  • Save SuddenDevelopment/417468f7c12325ae68c7669dab3aaf5a to your computer and use it in GitHub Desktop.
Save SuddenDevelopment/417468f7c12325ae68c7669dab3aaf5a to your computer and use it in GitHub Desktop.
helper for an instance matrix using noise in three.js / react 3 fiber / web3d.
export function getInstanceMatrix(position, radius, spacing, objMap){
/*
const matrices = useMemo(() => {
return getInstanceMatrix([0, 0, 0], 10, 1, {
minNoise: -1,
maxNoise: 1,
getNoise: (x, y, z) => { return noise.GetNoise(x, y, z) }
});
}, [noise]); // Add any other dependencies here
position: [x,y,z] // center of the area
radius: number // radius of the area to get noise values around the position
spacing: number // spacing between instances, default 1
objMap={
meshName:{
minNoise:-1, // min value for spawning an instance
maxNoise:1, // max value for spawning an instance
getNoise: fn(x,y,z), // default [0,0,0]
getProbability: fn(x,y,z), // default 1
getRotation: fn(x,y,z), // default 0
getScale: fn(x,y,z), // default 1
getPosition: fn(x,y,z), // default [x,y,z]
}
}
return {
meshName: matrix4[] // array of matrices for each instance
}
<instancedMesh ref={ref} args={[noiseMap.geometry, noiseMap.material, matrices.length/16]}>
<instancedBufferAttribute ref={attrRef} attach="instanceMatrix" count={matrices.length/16} array={matrices} itemSize={16} />
</instancedMesh>
*/
// find the instance count based on the radius and spacing, this is a max instance count we dont have to populate them all
const instanceCount = Math.pow((radius*2)/spacing, 2);
const matrices = new Float32Array(instanceCount * 16);
// these are just template objects that get overwritten in a flywheel pattern
const tmpMatrix = new THREE.Matrix4();
const tmpVector = new THREE.Vector3();
const tmpQuaternion = new THREE.Quaternion();
const tmpScale = new THREE.Vector3();
//loop over the coordinates of radius around position
let index = 0;
for (let x = position[0]-radius; x < position[0]+radius; x+=spacing) {
for (let z = position[2]-radius; z < position[2]+radius; z+=spacing) {
//get the noise value at this position
const noiseValue = objMap.getNoise(x,z,position[1]);
//get the object to spawn based on the noise value
if (noiseValue >= objMap.minNoise && noiseValue <= objMap.maxNoise) {
// use probability to determine if it should spawn, if defined as a function call it, else use default of 1
const prob = typeof objMap.getProbability === 'function' ? objMap.getProbability(x,noiseValue,z) : 1;
if(prob > 0){
// Set position
const position = typeof objMap.getPosition === 'function' ? objMap.getPosition(x,noiseValue,z) : [x,noiseValue*10,z];
tmpVector.set(...position);
//tmpMatrix.makeTranslation(...position);
// Set rotation
const rotation = typeof objMap.getRotation === 'function' ? objMap.getRotation(x,noiseValue,z) : [0,0,0];
const euler = new THREE.Euler(rotation[0], rotation[1], rotation[2], 'XYZ');
tmpQuaternion.setFromEuler(euler);
// Set scale
const scale = typeof objMap.getScale === 'function' ? objMap.getScale(x,z,position[1]) : [1,1,1];
tmpScale.set(...scale);
//Update transformation matrix
tmpMatrix.compose(tmpVector, tmpQuaternion, tmpScale);
matrices.set(tmpMatrix.elements, index);
index += 16;
}
}
}
}
return matrices;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment