Hi there! I’m trying to write my first GPGPU particle simulation following the amazing tutorial by Yuri.
I am getting stuck right after declaring my THREE.DataTexture and passing it into my THREE.ShaderMaterial as a texture argument. Nothing gets displayed. When I feed it a regular .jpg image it gets displayed without a problem.
I am using an M3 MacBook Pro (I wonder if it might be a hardware limitation about floatTextures). I’ve tried firefox and safari and the problem persists. I’ve read elsewhere that you need to activate floatTexture capability on the GL context. I’ve tried this too but I wonder if I’m doing it incorrectly
Here’s the code. Any help would be incredible. Cheers!
import * as THREE from 'three';
// import{ OrbitControls } from "three/addons/controls/OrbitControls.js";
// Load Shaders
const defaultVert = await (await fetch('./shaders/defaultVert.glsl')).text();
const defaultFrag = await (await fetch('./shaders/defaultFrag.glsl')).text();
const simVert = await (await fetch('./shaders/simVert.glsl')).text();
const simFrag = await (await fetch('./shaders/simFrag.glsl')).text();
const tex = new THREE.TextureLoader().load('./tex/img0.jpg' );
// Init Funcs
setupFBO();
// Basic Scene Setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const clock = new THREE.Clock();
const renderer = new THREE.WebGLRenderer();
var gl = renderer.getContext('webgl');
gl.getExtension("OES_texture_float");
renderer.setClearColor(0x000000f,1)
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const geometry = new THREE.PlaneGeometry( 5, 5);
const mat = new THREE.ShaderMaterial({
uniforms:{
u_time:{value:0},
},
vertexShader:defaultVert,
fragmentShader:defaultFrag
});
const plane = new THREE.Mesh( geometry, mat );
scene.add(plane);
camera.position.z = 5;
// Animation Loop
function animate() {
// renderer.render( scene, camera );
renderer.setRenderTarget(null);
renderer.render(fboScene,fboCamera);
plane.rotation.x = Math.sin(clock.getElapsedTime()*1.)*.3;
plane.rotation.y = Math.sin(clock.getElapsedTime()*1.)*.3;
}
renderer.setAnimationLoop( animate );
// Functions
function getRenderTarget() {
const renderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight,{
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat,
type: THREE.FloatType
});
return renderTarget;
}
function setupFBO(){
globalThis.size = 128;
globalThis.fbo = getRenderTarget();
globalThis.fbo1 = getRenderTarget();
globalThis.fboScene = new THREE.Scene();
globalThis.fboCamera = new THREE.OrthographicCamera(-1,1,1,-1,-1,1);
fboCamera.position.set(0,0,0.5);
fboCamera.lookAt(0,0,0);
let geo = new THREE.PlaneGeometry(2,2);
globalThis.data = new Float32Array(size*size*4);
for(let i = 0; i<size;i++){
for(let j =0; j<size; j++){
let index = (i + j * size) * 4;
let theta = Math.random() * Math.PI * 2;
let r = 0.5 + 0.5 * Math.random();
data[index + 0] = r*Math.cos(theta);
data[index + 1] = r*Math.sin(theta);
data[index + 2] = 1;
data[index + 3] = 0;
}
}
globalThis.fboTexture = new THREE.DataTexture(data,size,size,THREE.RGBAFormat,THREE.FloatType);
fboTexture.magFilter = THREE.NearestFilter;
fboTexture.minFilter = THREE.NearestFilter;
fboTexture.needsUpdate = true;
globalThis.fboMaterial = new THREE.ShaderMaterial({
uniforms:{
uPositions: {value: fboTexture},
u_time: {value:0},
},
vertexShader:simVert,
fragmentShader:simFrag
});
// fboMaterial.uniforms.uPositions.value = tex;
// globalThis.fboMaterial = new THREE.MeshBasicMaterial();
// fboMaterial.map = fboTexture;
globalThis.fboMesh = new THREE.Mesh(geo,fboMaterial)
fboScene.add(fboMesh)
}