-
-
Notifications
You must be signed in to change notification settings - Fork 36k
Description
Description
If I write a compute shader that store textures, I can load and use those textures in another compute Shader.
But when I try to pass a texture to a compute shader that I previously created with the same shader, then I get these warnings and it doesn't work:
Tint WGSL reader failure: :64:43 error: type mismatch for argument 3 in call to 'computeWGSL', expected 'texture_2d<f32>', got 'texture_storage_2d<rgba8unorm, write>'
computeWGSL( nodeUniform0, nodeUniform1, nodeUniform0, instanceIndex, 512.0, 0.01, 250.0, f32( true ) );
^^^^^^^^^^^^
- While validating [ShaderModuleDescriptor "compute"]
- While calling [Device].CreateShaderModule([ShaderModuleDescriptor "compute"]).
[127.0.0.1/:1](http://127.0.0.1/:1) 1 error(s) generated while compiling the shader:
:64:43 error: type mismatch for argument 3 in call to 'computeWGSL', expected 'texture_2d<f32>', got 'texture_storage_2d<rgba8unorm, write>'
computeWGSL( nodeUniform0, nodeUniform1, nodeUniform0, instanceIndex, 512.0, 0.01, 250.0, f32( true ) );
^^^^^^^^^^^^
166[Invalid ShaderModule "compute"] is invalid.
- While validating compute stage ([Invalid ShaderModule "compute"], entryPoint: main).
- While calling [Device].CreateComputePipeline([ComputePipelineDescriptor]).
166[Invalid ComputePipeline] is invalid.
- While encoding [ComputePassEncoder].SetPipeline([Invalid ComputePipeline]).
166[Invalid CommandBuffer] is invalid.
- While calling [Queue].Submit([[Invalid CommandBuffer]])
[127.0.0.1/:1](http://127.0.0.1/:1) Tint WGSL reader failure: :64:43 error: type mismatch for argument 3 in call to 'computeWGSL', expected 'texture_2d<f32>', got 'texture_storage_2d<rgba8unorm, write>'
computeWGSL( nodeUniform0, nodeUniform1, nodeUniform1, instanceIndex, 512.0, 0.01, 250.0, f32( false ) );
^^^^^^^^^^^^
- While validating [ShaderModuleDescriptor "compute"]
- While calling [Device].CreateShaderModule([ShaderModuleDescriptor "compute"]).
[127.0.0.1/:1](http://127.0.0.1/:1) 1 error(s) generated while compiling the shader:
:64:43 error: type mismatch for argument 3 in call to 'computeWGSL', expected 'texture_2d<f32>', got 'texture_storage_2d<rgba8unorm, write>'
computeWGSL( nodeUniform0, nodeUniform1, nodeUniform1, instanceIndex, 512.0, 0.01, 250.0, f32( false ) );
^^^^^^^^^^^^
[127.0.0.1/:1](http://127.0.0.1/:1) WebGPU: too many warnings, no more warnings will be reported to the console for this GPUDevice.
Reproduction steps
1.) Create a compute shader that stores a texture and reads a texture.
2.) In the first run, use an initial texture for the texture input of the compute shader.
3.) In the next run, pass the texture created by the compute shader itself to the texture input of the compute shader.
Unfortunately, in the CodePen example that I created, I only get a white image so far.
Since I can use a texture created by another computer shader, I suspect that it might have something to do with the bindings and locations.
The compute shaders are really great for IFFT (inverse fast Fourier transformations). IFFT requires computer shaders that can load their own previously created textures. Considering that the textureStorage function is brand new in 3js, it runs very satisfactorily.
Code
import * as THREE from "three";
import {texture, textureStore, instanceIndex, MeshBasicNodeMaterial, attribute, uniform, vec2, vec3, vec4, wgslFn } from 'three/nodes';
import {OrbitControls} from "three/addons/controls/OrbitControls.js";
import Stats from "three/addons/libs/stats.module.js";
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
import {EffectComposer} from "three/addons/postprocessing/EffectComposer.js";
import {RenderPass} from "three/addons/postprocessing/RenderPass.js";
import {ShaderPass} from "three/addons/postprocessing/ShaderPass.js";
const initialSpectrumWGSL = wgslFn(`
fn computeWGSL(
storageTex: texture_storage_2d<rgba8unorm, write>,
index: u32,
resolution: f32,
L: f32,
wind: vec2<f32>
) -> void {
let posX = index % u32(resolution);
let posY = index / u32(resolution);
let indexUV = vec2u( posX, posY );
let uv = vec2f( f32( posX ) / resolution, f32( posY ) / resolution );
let K: vec2<f32> = (2 * PI * (uv - vec2<f32>(0.5))) / L;
let k: f32 = length(K);
let l_wind: f32 = length(wind);
let Omega: f32 = 0.84;
let kp: f32 = g * square(Omega/l_wind);
let c: f32 = omega(k)/k;
let cp: f32 = omega(kp)/kp;
let Lpm: f32 = exp(-1.25 * square(kp/k));
let gamma: f32 = 1.7;
let sigma: f32 = 0.08 * (1 + 4*pow(Omega, -3));
let Gamma: f32 = exp(-square(sqrt(k/kp) - 1)/2 * square(sigma));
let Jp: f32 = pow(gamma, Gamma);
let Fp: f32 = Lpm * Jp * exp(-Omega/sqrt(10) * (sqrt(k/kp) - 1));
let alphap: f32 = 0.006*sqrt(Omega);
let Bl: f32 = 0.5*alphap*cp/c*Fp;
let z0: f32 = 0.000037 * square(l_wind)/g*pow(l_wind/cp, 0.9);
let uStar: f32 = 0.41*l_wind/log(10.0/z0);
let alpham: f32 = alphaM(uStar);
let Fm: f32 = exp(-0.25*square(k/KM-1.0));
let Bh: f32 = 0.5*alpham*CM/c*Fm*Lpm;
let a0: f32 = log(2.0)/4.0;
let am: f32 = 0.13*uStar/CM;
let Delta: f32 = tanH(a0+4.0*pow(c/cp, 2.5)+am*pow(CM/c, 2.5));
let cosPhi: f32 = dot(normalize(wind), normalize(K));
let S: f32 = (1.0/(2.0*PI))*pow(k,-4.0)*(Bl+Bh)*(1.0+Delta*(2.0*cosPhi*cosPhi-1.0));
let dk: f32 = 2.0*PI/L;
let h: f32 = spectrum( S, K, dk );
textureStore( storageTex, indexUV, vec4f( h, 0, 0, 0 ) );
}
const PI: f32 = 3.141592653;
const g: f32 = 9.81;
const KM: f32 = 370;
const CM: f32 = 0.23;
fn square( x: f32 ) -> f32 {
return x * x;
}
fn omega( k: f32 ) -> f32 {
return sqrt(g * k * (1 + square(k / KM)));
}
fn tanH( x: f32 ) -> f32 {
return (1 - exp(-2 * x)) / (1 + exp(-2 * x));
}
fn alphaM( uStar: f32 ) -> f32 {
if(uStar < CM){
return 0.01 * (1.0+log(uStar/CM));
}
else{
return 0.01 * (1.0+3.0*log(uStar/CM));
}
}
fn spectrum( S: f32, K: vec2<f32>, dk: f32 ) -> f32 {
if(K.x == 0 && K.y == 0){
return 0;
}
else{
return sqrt(S/2.0)*dk;
}
}
`);
const phaseWGSL = wgslFn(`
fn computeWGSL(
storageTexPing: texture_storage_2d<rgba8unorm, write>,
storageTexPong: texture_storage_2d<rgba8unorm, write>,
phase: texture_2d<f32>,
index: u32,
resolution: f32,
time: f32,
L: f32,
pingPhase: f32
) -> void {
let posX = index % u32(resolution);
let posY = index / u32(resolution);
let indexUV = vec2u( posX, posY );
let uv = vec2f( f32( posX ) / resolution, f32( posY ) / resolution );
let K: vec2<f32> = (2 * PI * (uv - vec2<f32>(0.5))) / L;
let ph = textureLoad(phase, indexUV, 0).r;
let dph = omega(length(K)) * time;
let new_ph = (ph + dph) % (2.0 * PI);
if(u32(pingPhase) == 1){
textureStore(storageTexPong, indexUV, vec4f(new_ph, 0, 0, 0));
}
if(u32(pingPhase) == 0){
textureStore(storageTexPing, indexUV, vec4f(new_ph, 0, 0, 0));
}
}
const PI: f32 = 3.141592653;
const g: f32 = 9.81;
const KM: f32 = 370.0;
fn omega(k: f32) -> f32 {
return sqrt(g*k*(1.0+k*k/KM*KM));
}
`);
let scene = new THREE.Scene();
scene.background = new THREE.Color(0x00001f);
let renderer = new WebGPURenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
let camera = new THREE.PerspectiveCamera(50.0, window.innerWidth/window.innerHeight, 0.5, 10000);
let composer = new EffectComposer(renderer);
composer.setSize(window.innerWidth,window.innerHeight);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
camera.position.set(3, 3, 3);
let controls = new OrbitControls(camera, renderer.domElement);
window.addEventListener("resize", onWindowResize, false);
var changed = true;
var initial = true;
var pingPhase = true;
var initialSpectrumMaterial = new MeshBasicNodeMaterial();
var pingMaterial = new MeshBasicNodeMaterial();
var pongMaterial = new MeshBasicNodeMaterial();
init();
render();
var initialSpectrumParams, initialSpectrumTexture, initialSpectrumCall;
var phaseParams, pingTexture, pongTexture, phaseCall, computePhase;
function init() {
initialSpectrumParams = {
resolution: 512,
workgroup_size: [8, 8, 1],
L: 100,
wind: vec2(10, 10)
}
initialSpectrumTexture = new THREE.Texture();
initialSpectrumTexture.image = {width: initialSpectrumParams.resolution, height: initialSpectrumParams.resolution};
initialSpectrumTexture.magFilter = initialSpectrumTexture.minFilter = THREE.NearestFilter;
initialSpectrumCall = initialSpectrumWGSL({
storageTex: textureStore(initialSpectrumTexture),
index: instanceIndex,
resolution: initialSpectrumParams.resolution,
L: initialSpectrumParams.L,
wind: initialSpectrumParams.wind,
});
phaseParams = {
resolution: 512,
workgroup_size: [8, 8, 1],
time: 0,
L: 250,
}
pingTexture = new THREE.Texture();
pongTexture = new THREE.Texture();
pingTexture.image = {width: phaseParams.resolution, height: phaseParams.resolution};
pongTexture.image = {width: phaseParams.resolution, height: phaseParams.resolution};
pingTexture.magFilter = pingTexture.minFilter = THREE.NearestFilter;
pongTexture.magFilter = pongTexture.minFilter = THREE.NearestFilter;
phaseCall = phaseWGSL({
storageTexPing: textureStore(pingTexture),
storageTexPong: textureStore(pongTexture),
index: instanceIndex,
resolution: phaseParams.resolution,
phase: null,
time: phaseParams.time,
L: phaseParams.L,
pingPhase: pingPhase
});
computePhase = phaseCall.compute(phaseParams.resolution * phaseParams.resolution);
const geometry = new THREE.PlaneGeometry( 1, 1 );
const plane = new THREE.Mesh( geometry, initialSpectrumMaterial );
scene.add( plane );
}
function update() {
if(changed) {
var computeInitialSpectrum = initialSpectrumCall.compute(initialSpectrumParams.resolution * initialSpectrumParams.resolution);
renderer.compute(computeInitialSpectrum, initialSpectrumParams.workgroup_size);
changed = false;
}
if(initial) {
computePhase.computeNode.parameters.phase = texture(InitPhaseDataTexture());
initial = false;
}
else{
//computePhase.computeNode.parameters.phase = pingPhase ? texture(pingTexture) : texture(pongTexture); //here i get strange warnings and it doesn't work
computePhase.computeNode.parameters.phase = texture(initialSpectrumTexture); //this works (just for test)
}
computePhase.computeNode.parameters.time.value = 0.01;
computePhase.computeNode.parameters.pingPhase.value = pingPhase;
computePhase = phaseCall.compute(phaseParams.resolution * phaseParams.resolution);
renderer.compute(computePhase, phaseParams.workgroup_size);
pingPhase = !pingPhase;
initialSpectrumMaterial.colorNode = texture(InitPhaseDataTexture());
}
function render() {
requestAnimationFrame(render);
update();
renderer.render(scene, camera);
//composer.render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function InitPhaseDataTexture(){
var Res = 512;
let phaseArray = new Float32Array(Res * Res * 4);
for (let y = 0; y < Res; y++) {
for (let x = 0; x < Res; x++) {
phaseArray[y*Res*4 + x*4] = Math.random() * 2.0 * Math.PI;
phaseArray[y*Res*4 + x*4+1] = 0.0;
phaseArray[y*Res*4 + x*4+2] = 0.0;
phaseArray[y*Res*4 + x*4+3] = 0.0;
}
}
const pingPhaseTexture = new THREE.DataTexture(phaseArray, Res, Res, THREE.RGBAFormat, THREE.FloatType);
pingPhaseTexture.minFilter = THREE.NearestFilter;
pingPhaseTexture.magFilter = THREE.NearestFilter;
pingPhaseTexture.wrapS = THREE.ClampToEdgeWrapping;
pingPhaseTexture.wrapT = THREE.ClampToEdgeWrapping;
pingPhaseTexture.needsUpdate = true;
return pingPhaseTexture;
}
Live example
https://codepen.io/Spiri0/pen/abPwOoG
Screenshots
No response
Version
156
Device
Desktop
Browser
Chrome
OS
Windows