Instancing spheres on glb model on deferent meshes

Hello all , i try to make some thing similar to this image
image

so i search and found this example three.js examples

but i try to switch between the surface and mesh but it not work, actually i need to fill a multiple meshes on sphere like if i have a mickey mouse model , then can i traverse the model and fill it feets and hands on RANDOM spheres https://static.wikia.nocookie.net/disney/images/b/bf/Mickey_Mouse_Disney_1.png/revision/latest?cb=20180813011713
thanks

not sure i uderstand it right, i am guessing you want a bunch of meshes to form a clump. if yes, you can get something like this quite easily with a physics model and a basic force attractor pushing objects into the center: BestServedBold Christmas Baubles - CodeSandbox

2 Likes

Thank you , but how i can implement this on pure threejs !!

i posted it mostly because the math stays the same, it’s using cannon-es. after you’ve set this up it’s just about applyForce pushing objects to center. you will find lots of basic examples there: GitHub - pmndrs/cannon-es: 💣 A lightweight 3D physics engine written in JavaScript.

Thank you i’ll try :sob:

@drcmda it is right as a start ?

function initCannon() {
    world = new CANNON.World({
        gravity: new CANNON.Vec3(0, 0, 0), 
        iterations: 10,
        broadphase: new CANNON.SAPBroadphase(world)
    })
    const radius = 1 
    body = new CANNON.Body({
        mass: 1,
        shape: new CANNON.Sphere(radius),
    })
    body.position.set(0, 10, 0) 
    world.addBody(body)

}

yes, looking good. start by letting them drop on a plane or something just to confirm. if you have that implementing the applyForce isn’t much work. btw that picture you posted is almost too good looking, i think i’d try to make it as well if i find time. im using three in react though. we could still compare notes.

Yes i let them drop, thank you , actually the example that you posted it : BestServedBold Christmas Baubles - CodeSandbox
this is all i need more than my pic , so i will try to make it in threejs ! :joy:

@drcmda
Can i plz use react three function in pure js ??
sorry but it a bit hard to convert!

First time using of any physics engine, so would glad to hear advice of how to do it in correct way: https://7ckrtj.csb.app/

cannonspheres

1 Like

i’ve forked my baubles demo and made a simpler one: BestServedBold Christmas Baubles (forked) - CodeSandbox

the key is basically:

applyForce(currentPosition.normalize().multiplyScalar(-force).toArray(), [0, 0, 0]))

btw @prisoner849 since you’re here, in the sandbox above i forked the AO shader from threejs, do you know how i could make the AO red? black looks terrible. i know PP can do it, but they just refactored the entire api and i can’t get it to work no more.

Finaaaaaaly i can help in some thing
just replace the shader code in


import { Matrix4, Vector2 } from "three"

/**
 * References:
 * http://john-chapman-graphics.blogspot.com/2013/01/ssao-tutorial.html
 * https://learnopengl.com/Advanced-Lighting/SSAO
 * https://github.com/McNopper/OpenGL/blob/13f5149ea6407c11395760a7c22c628f75b642ef/Example28/shader/ssao.frag.glsl
 */

const SSAOShader = {
  defines: {
    PERSPECTIVE_CAMERA: 1,
    KERNEL_SIZE: 32,
  },

  uniforms: {
    tDiffuse: { value: null },
    tNormal: { value: null },
    tDepth: { value: null },
    tNoise: { value: null },
    kernel: { value: null },
    cameraNear: { value: null },
    cameraFar: { value: null },
    resolution: { value: new Vector2() },
    cameraProjectionMatrix: { value: new Matrix4() },
    cameraInverseProjectionMatrix: { value: new Matrix4() },
    kernelRadius: { value: 8 },
    minDistance: { value: 0.005 },
    maxDistance: { value: 0.05 },
  },

  vertexShader: /* glsl */ `
		varying vec2 vUv;

		void main() {
			vUv = uv;
			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
		}`,

  fragmentShader: /* glsl */ `
		uniform sampler2D tDiffuse;
		uniform sampler2D tNormal;
		uniform sampler2D tDepth;
		uniform sampler2D tNoise;
		uniform vec3 kernel[ KERNEL_SIZE ];
		uniform vec2 resolution;
		uniform float cameraNear;
		uniform float cameraFar;
		uniform mat4 cameraProjectionMatrix;
		uniform mat4 cameraInverseProjectionMatrix;
		uniform float kernelRadius;
		uniform float minDistance; // avoid artifacts caused by neighbour fragments with minimal depth difference
		uniform float maxDistance; // avoid the influence of fragments which are too far away
		varying vec2 vUv;

		#include <packing>

		float getDepth( const in vec2 screenPosition ) {
			return texture2D( tDepth, screenPosition ).x;
		}

		float getLinearDepth( const in vec2 screenPosition ) {
			#if PERSPECTIVE_CAMERA == 1
				float fragCoordZ = texture2D( tDepth, screenPosition ).x;
				float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );
				return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );
			#else
				return texture2D( tDepth, screenPosition ).x;
			#endif
		}

		float getViewZ( const in float depth ) {
			#if PERSPECTIVE_CAMERA == 1
				return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
			#else
				return orthographicDepthToViewZ( depth, cameraNear, cameraFar );
			#endif
		}

		vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) {
			float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3];
			vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 );
			clipPosition *= clipW; // unprojection.
			return ( cameraInverseProjectionMatrix * clipPosition ).xyz;
		}

		vec3 getViewNormal( const in vec2 screenPosition ) {
			return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );
		}

		void main() {
			float depth = getDepth( vUv );
			float viewZ = getViewZ( depth );
			vec3 viewPosition = getViewPosition( vUv, depth, viewZ );
			vec3 viewNormal = getViewNormal( vUv );
			vec2 noiseScale = vec2( resolution.x / 4.0, resolution.y / 4.0 );
			vec3 random = vec3( texture2D( tNoise, vUv * noiseScale ).r );

			// compute matrix used to reorient a kernel vector

			vec3 tangent = normalize( random - viewNormal * dot( random, viewNormal ) );
			vec3 bitangent = cross( viewNormal, tangent );
			mat3 kernelMatrix = mat3( tangent, bitangent, viewNormal );
		 float occlusion = 0.0;

		 for ( int i = 0; i < KERNEL_SIZE; i ++ ) {
				vec3 sampleVector = kernelMatrix * kernel[ i ]; // reorient sample vector in view space
				vec3 samplePoint = viewPosition + ( sampleVector * kernelRadius ); // calculate sample point
				vec4 samplePointNDC = cameraProjectionMatrix * vec4( samplePoint, 1.0 ); // project point and calculate NDC
				samplePointNDC /= samplePointNDC.w;
				vec2 samplePointUv = samplePointNDC.xy * 0.5 + 0.5; // compute uv coordinates
				float realDepth = getLinearDepth( samplePointUv ); // get linear depth from depth texture
				float sampleDepth = viewZToOrthographicDepth( samplePoint.z, cameraNear, cameraFar ); // compute linear depth of the sample view Z value
				float delta = sampleDepth - realDepth;
				if ( delta > minDistance && delta < maxDistance ) { // if fragment is before sample point, increase occlusion
					occlusion += 2.0;
				}
			}
			occlusion = clamp( occlusion / float( KERNEL_SIZE ), 0.0, 1.0 );
			gl_FragColor = vec4( vec3( 1.0 , 1.0 - occlusion / 2.0 , 1.0 - occlusion / 2.0 ), 1.0 );
		}`,
}

const SSAODepthShader = {
  defines: {
    PERSPECTIVE_CAMERA: 1,
  },

  uniforms: {
    tDepth: { value: null },
    cameraNear: { value: null },
    cameraFar: { value: null },
  },

  vertexShader: `varying vec2 vUv;
		void main() {
			vUv = uv;
			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
		}`,

  fragmentShader: `uniform sampler2D tDepth;
		uniform float cameraNear;
		uniform float cameraFar;
		varying vec2 vUv;

		#include <packing>

		float getLinearDepth( const in vec2 screenPosition ) {

			#if PERSPECTIVE_CAMERA == 1
				float fragCoordZ = texture2D( tDepth, screenPosition ).x;
				float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );
				return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );
			#else
				return texture2D( tDepth, screenPosition ).x;
			#endif
		}

		void main() {
			float depth = getLinearDepth( vUv );
			gl_FragColor = vec4( vec3( 1.0 - depth ), 1.0 );
		}`,
}

const SSAOBlurShader = {
  uniforms: {
    tDiffuse: { value: null },
    resolution: { value: new Vector2() },
  },

  vertexShader: `varying vec2 vUv;
		void main() {
			vUv = uv;
			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
		}`,

  fragmentShader: `uniform sampler2D tDiffuse;
		uniform vec2 resolution;
		varying vec2 vUv;

		void main() {
			vec2 texelSize = ( 1.0 / resolution );
			float result = 0.0;
			for ( int i = - 2; i <= 2; i ++ ) {
				for ( int j = - 2; j <= 2; j ++ ) {
					vec2 offset = ( vec2( float( i ), float( j ) ) ) * texelSize;
					result += texture2D( tDiffuse, vUv + offset ).r;
				}
			}
			gl_FragColor = vec4( vec3( 1.0 / ( 5.0 * 5.0 ) ,result / ( 5.0 * 5.0 ),result / ( 5.0 * 5.0 )), 1.0 );
		}`,
}

export { SSAOShader, SSAODepthShader, SSAOBlurShader }

THank you

Thank you for help MR , you are amazing

thank you! :grin:

1 Like

But a question , we have all spheres in the center cuz we have a gravity in 0,0,0 right ?
if we want to make a multiple groups of spheres then all of them return on center point
we have to set multiple worlds
one it’s gravity on 0,0,0
second it’s gravity on 1,1,0
third it’s gravity on 1,0,0
and so on
to get a deferent sets on center point ???
what do you think @drcmda

multiple worlds wouldn’t work because spheres would just pierce through one another. gravity is 0 anyway if you want spheres to float. what you can quite easily do is apply more or less force to specific spheres. the more force the faster they rush to center point. in the baubles demo above i do something like that, by multiplying the size of the sphere to the force.

1 Like

I’m not sure in correctness of my approach, but I get red AO just by modifying blurMaterial only of SSAOPass, with .onBeforeCompile(), like for any other material, and I got this: https://99rjuc.csb.app/

Tell me, if it’s the desired result :sweat_smile:

3 Likes

Plz , i try to set

        spT.applyForce(v3.copy(spT.position).normalize().multiplyScalar(-50).toArray(),[0,0,0]);

while spT = sphere[i]

v3 = vec3
but get the error

relativePoint.cross is not a function
    at Body.applyForce

ive updated the box above with instancing BestServedBold Christmas Baubles (forked) - CodeSandbox

    for (let i = 0; i < 40; i++) {
      instances.getMatrixAt(i, m)
      bodies[i].applyForce(v3.setFromMatrixPosition(m).normalize().multiplyScalar(-50).toArray(), [0, 0, 0])
    }

but again, it’s hard for me to go back to vanilla. physics especially. if you have the body you take the current position of it, normalize it and multiply with a negative force, that will push the object back to center. i am not 100% sure if cannon takes THREE.Vector3 i think it has its own vectors. in the abstraction i am using all of this has been taken care of, it’s integrated into threejs fully.

Thank you , yes sure i see,
thank you for help
but the cuz that i am use vec3
is the error when i use [0,0,0]

Uncaught TypeError: relativePoint.cross is not a function