개발 · 컴퓨터공학/Physical Simulation

three.js GPGPU SPH - GLSL 1 version shader

2024. 10. 22. 11:27
728x90
반응형

 

glsl version 1 shader 

precision mediump float;

struct Particle{
    float pressure;
    float density;
    vec3 currentForce;
    vec3 velocity;
    vec3 position;
};

uniform float particleMass;
uniform float viscosity;
uniform float gasConstant;
uniform float restDensity;
uniform float boundDamping;
uniform float radius;
uniform float radius2;
uniform float radius3;
uniform float radius4;
uniform float radius5;
uniform float pi;
uniform int particleLength;
uniform float timestep;
uniform vec3 boxSize;

uniform Particle _particles[100];  // WebGL의 경우 배열 크기 명시 필요

void main() {
    int id = int(gl_FragCoord.x);  // 각 픽셀은 파티클 ID와 매핑

    if (id >= particleLength) {
        gl_FragColor = vec4(0.0);  // 범위 밖일 경우 아무런 작업도 하지 않음
        return;
    }

    Particle particle = _particles[id];

    vec3 vel = particle.velocity + ((particle.currentForce / particleMass) * timestep);
    vec3 newPosition = particle.position + vel * timestep;

    vec3 topRight = boxSize / 2.0;
    vec3 bottomLeft = -boxSize / 2.0;

    // Min Boundary Enforcements
    if (newPosition.x - radius < bottomLeft.x) {
        vel.x *= boundDamping;
        newPosition.x = bottomLeft.x + radius;
    }
    if (newPosition.y - radius < bottomLeft.y) {
        vel.y *= boundDamping;
        newPosition.y = bottomLeft.y + radius;
    }
    if (newPosition.z - radius < bottomLeft.z) {
        vel.z *= boundDamping;
        newPosition.z = bottomLeft.z + radius;
    }

    // Max Boundary Enforcements
    if (newPosition.x + radius > topRight.x) {
        vel.x *= boundDamping;
        newPosition.x = topRight.x - radius;
    }
    if (newPosition.y + radius > topRight.y) {
        vel.y *= boundDamping;
        newPosition.y = topRight.y - radius;
    }
    if (newPosition.z + radius > topRight.z) {
        vel.z *= boundDamping;
        newPosition.z = topRight.z - radius;
    }

    // 속도와 위치 업데이트
    gl_FragColor = vec4(newPosition, 1.0);  // 위치 데이터를 RGBA 형태로 저장
}

glsl 1 버전으로 작성한 위 코드는 

컴파일 했을 때 에러가 나진 않는다.

 

uniform 변수 전달하기 

shader의 uniform 변수들에 fluid constants 상수 값을 전달하도록 하자.

유니티에서는 hlsl을 사용하므로 kernel을 지정하는데.

 

흠.. 이건 glsl 1.0 에서는 각 커널에 해당하는 스크립트를 따로 만들고 gpu compute를 하는게 좋을 것 같다.

 

이렇게 각 shader의 상수들에 값을 넣어주는 경우. 

 

this.textureVariable = this.gpuCompute.addVariable('textureData', computefragment, this.textureData);
this.gpuCompute.setVariableDependencies(this.textureVariable, [this.textureVariable]);

this.textureVariable.material.uniforms.particleLength = { value: this.totalParticles };
this.textureVariable.material.uniforms.particleMass = { value: 1.0 };
this.textureVariable.material.uniforms.viscosity = { value: 0.01 };
this.textureVariable.material.uniforms.gasConstant = { value: 1.4 };
this.textureVariable.material.uniforms.restDensity = { value: 1000.0 };
this.textureVariable.material.uniforms.boundDamping = { value: 0.9 };
this.textureVariable.material.uniforms.pi = { value: Math.PI };
this.textureVariable.material.uniforms.boxSize = { value: new THREE.Vector3(10, 10, 10) };

this.textureVariable.material.uniforms.radius = { value: this.particleRadius };
this.textureVariable.material.uniforms.radius2 = { value: Math.pow(this.particleRadius, 2) };
this.textureVariable.material.uniforms.radius3 = { value: Math.pow(this.particleRadius, 3) };
this.textureVariable.material.uniforms.radius4 = { value: Math.pow(this.particleRadius, 4) };
this.textureVariable.material.uniforms.radius5 = { value: Math.pow(this.particleRadius, 5) };

this.textureVariable.material.uniforms.timestep = { value: 0.016 };

three.js에서는 uniform 변수로 선언했으므로 uniform 데이터에 넣어준다. 

일단 임시 데이터로 처리를 해놨는데 정상 동작하면 변경하자.

 

compute를 하고 나서 결과 texture를 받으면 다시 compute shader에 넣고 계속해서 update해주어야한다.

근데 문제는 현재 shader코드이다.

 

uniform Particle _particles[100];  // WebGL의 경우 배열 크기 명시 필요

이렇게 uniform으로 선언이 되어있으면 CPU로 내보낼 수가 없으므로, 

구조체 배열 형태인 particle을 어떻게 output할지가 관건이다. 

 

glsl 1버전에서는 gl_FragColor로 output을 해야하는데,

그러면 한 스레드에서 vec4 형태로 밖에 꺼내지 못한다.

 

즉 particle 구조체의 형태로 데이터를 CPU로 전달하지 못한다는 것이다. 

이러면 좀 곤란하다;;

 

구조체를 GPU에서 CPU로 넘기기

glsl 1버전에서는 gl_FragColor로 꺼내야하는데, 이게 vec4 형태로 제한되어있다.

compute에서 연산되는 particle 구조체 값을 어떻게 꺼내야할까...

 

심지어는 shader에서 texture도 하나만 return할 수 있는 것 같다.

이거 gpu computation renderer에서 glsl 3 버전을 쓸 수 있는 방법을 찾는게 더 빠를려나..

 

728x90
반응형