You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
During the WebGPU adaptation of one of my WebGL2 examples, I noticed that wgsl does not understand DataTextures that use FloatType if they are passed to a texture_2d parameter.
Reproduction steps
Create a DataTexture with type "FloatType", in my case:
function GeneratePositions(g){
//g = geometry
let vertAmount = g.attributes.position.count;
let texWidth = Math.ceil(Math.sqrt(vertAmount));
let texHeight = Math.ceil(vertAmount / texWidth);
let data = new Float32Array(texWidth * texHeight * 4);
for(let i = 0; i < vertAmount; i++){
data[i * 4 + 0] = g.attributes.position.getX(i);
data[i * 4 + 1] = g.attributes.position.getY(i);
data[i * 4 + 2] = g.attributes.position.getZ(i);
data[i * 4 + 3] = 0;
}
let dataTexture = new THREE.DataTexture(
data,
texWidth,
texHeight,
THREE.RGBAFormat,
THREE.FloatType
);
dataTexture.needsUpdate = true;
return dataTexture;
}
Assign the DataTexture to a wgslFn with a texture_2d parameter. I have created a detailed codePen example.
Check line 162.
With line 164 you can use a testTexture to see what it should look like if the wgslFn function understood the DataTexture and took the vertex positions from the DataTexture instead of the position attribute. To do this, line 103 must be included and line 105 deactivated.
The testTexture only serves the purpose that the shader has a texture. The testTexture itself is meaningless and unsuitable for the application.
Code
import * as THREE from "three";
import {texture, MeshBasicNodeMaterial, attribute, uniform, 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';
const P = new THREE.Vector3();
const N1 = new THREE.Vector3();
const N2 = new THREE.Vector3();
const N3 = new THREE.Vector3();
const D1 = new THREE.Vector3();
const D2 = new THREE.Vector3();
let scene = new THREE.Scene();
scene.background = new THREE.Color(0x667799);
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);
camera.position.set(20, 20, -20);
let controls = new OrbitControls(camera, renderer.domElement);
controls.update();
init();
render();
function init() {
let params = {
resolution: 30,
width: 20,
}
const positions = [];
const vertexIndex = [];
const resolution = params.resolution;
const width = params.width;
const half = width / 2;
let idx = 0;
for (let x = 0; x <= resolution; x++) {
const xp = width * x / resolution;
for (let z = 0; z <= resolution; z++) {
const zp = width * z / resolution;
// Compute position
P.set(xp - half, 0, zp - half);
positions.push(P.x, P.y, P.z);
vertexIndex.push(idx);
idx += 1;
}
}
// Generate indices and normals
const indices = GenerateIndices(params);
const normals = GenerateNormals(positions, indices);
const bytesInFloat32 = 4;
const bytesInInt32 = 4;
const positionsArray = new Float32Array(new ArrayBuffer(bytesInFloat32 * positions.length));
const normalsArray = new Float32Array(new ArrayBuffer(bytesInFloat32 * normals.length));
const indicesArray = new Uint32Array(new ArrayBuffer(bytesInInt32 * indices.length));
const vIndicesArray = new Uint32Array(new ArrayBuffer(bytesInInt32 * vertexIndex.length));
positionsArray.set(positions, 0);
normalsArray.set(normals, 0);
indicesArray.set(indices, 0);
vIndicesArray.set(vertexIndex, 0);
const textureLoader = new THREE.TextureLoader();
const testTexture = textureLoader.load('https://picsum.photos/670/670'); //just a test texture
const WGSLVertexPosition = wgslFn(`
fn WGSLPosition(
vertexTexture: texture_2d<f32>,
position: vec3<f32>,
normal: vec3<f32>,
vindex: i32,
) -> vec4<f32> {
var idx: f32 = f32(vindex);
var texSize: vec2<u32> = textureDimensions(vertexTexture);
var texWidth: f32 = f32(texSize.x);
var texHeight: f32 = f32(texSize.y);
var colIdx: u32 = u32(floor(idx/texWidth));
var rowIdx: u32 = u32(idx % texHeight);
var texCoord: vec2<u32> = vec2<u32>(rowIdx, colIdx);
var positionD: vec3<f32> = textureLoad(vertexTexture, texCoord, 0).xyz;
//return vec4<f32>(positionD, 1.0); //Get vertice positions from the DataTexture instead of the position attribute. But line 162 must work for this
return vec4<f32>(position, 1.0);
}
`);
const WGSLFragmentColor = wgslFn(`
fn WGSLPosition(
position: vec3<f32>,
) -> vec4<f32> {
return vec4<f32>(position*0.1, 1.0);
}
`);
const wgslVertexParams = {
vertexTexture: texture(null),
position: attribute('position'),
normal: attribute('normal'),
vindex: attribute('vindex'),
}
const wgslFragmentParams = {
position: attribute('position'),
}
const nodeMaterial = new MeshBasicNodeMaterial();
nodeMaterial.colorNode = WGSLFragmentColor(wgslFragmentParams);
nodeMaterial.positionNode = WGSLVertexPosition(wgslVertexParams);
nodeMaterial.wireframe = true;
const geometry = new THREE.BufferGeometry();
const mesh = new THREE.Mesh(geometry, nodeMaterial);
mesh.castShadow = false;
mesh.receiveShadow = true;
mesh.frustumCulled = false;
mesh.position.set(0, 0, 0);
mesh.rotation.x = Math.PI;
scene.add(mesh);
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positionsArray, 3));
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normalsArray, 3));
geometry.setAttribute('vindex', new THREE.Int32BufferAttribute(vIndicesArray, 1));
geometry.setIndex(new THREE.BufferAttribute(indicesArray, 1));
geometry.attributes.position.needsUpdate = true;
geometry.attributes.normal.needsUpdate = true;
geometry.attributes.vindex.needsUpdate = true;
const VertexPositionsTexture = GeneratePositions(geometry);
//In my WebGL2 version it works with: mesh.material.uniforms.vertexTexture.value = VertexPositionsTexture;
mesh.material.positionNode.parameters.vertexTexture.value = VertexPositionsTexture; //I am not sure if there is a bug here. It works with non FloatType DataTexture but it also have to work with
//mesh.material.positionNode.parameters.vertexTexture.value = testTexture; //Just to test: I can assign a non FloatType texture.
}
function GenerateIndices(params) {
const resolution = params.resolution;
const indices = [];
for (let i = 0; i < resolution; i++) {
for (let j = 0; j < resolution; j++) {
indices.push(
i * (resolution + 1) + j,
(i + 1) * (resolution + 1) + j + 1,
i * (resolution + 1) + j + 1);
indices.push(
(i + 1) * (resolution + 1) + j,
(i + 1) * (resolution + 1) + j + 1,
i * (resolution + 1) + j);
}
}
return indices;
}
function GeneratePositions(g){
let vertAmount = g.attributes.position.count;
let texWidth = Math.ceil(Math.sqrt(vertAmount));
let texHeight = Math.ceil(vertAmount / texWidth);
let data = new Float32Array(texWidth * texHeight * 4);
for(let i = 0; i < vertAmount; i++){
data[i * 4 + 0] = g.attributes.position.getX(i);
data[i * 4 + 1] = g.attributes.position.getY(i);
data[i * 4 + 2] = g.attributes.position.getZ(i);
data[i * 4 + 3] = 0;
}
let dataTexture = new THREE.DataTexture(
data,
texWidth,
texHeight,
THREE.RGBAFormat,
THREE.FloatType //without this line wgsl understand the texture. But the FloatType is essential and works with WebGL2
);
dataTexture.needsUpdate = true;
return dataTexture;
}
function GenerateNormals(positions, indices) {
const normals = new Array(positions.length).fill(0.0);
for (let i = 0, n = indices.length; i < n; i+= 3) {
const i1 = indices[i] * 3;
const i2 = indices[i+1] * 3;
const i3 = indices[i+2] * 3;
N1.fromArray(positions, i1);
N2.fromArray(positions, i2);
N3.fromArray(positions, i3);
D1.subVectors(N3, N2);
D2.subVectors(N1, N2);
D1.cross(D2);
normals[i1] += D1.x;
normals[i2] += D1.x;
normals[i3] += D1.x;
normals[i1+1] += D1.y;
normals[i2+1] += D1.y;
normals[i3+1] += D1.y;
normals[i1+2] += D1.z;
normals[i2+2] += D1.z;
normals[i3+2] += D1.z;
}
return normals;
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
Description
During the WebGPU adaptation of one of my WebGL2 examples, I noticed that wgsl does not understand DataTextures that use FloatType if they are passed to a texture_2d parameter.
Reproduction steps
Check line 162.
With line 164 you can use a testTexture to see what it should look like if the wgslFn function understood the DataTexture and took the vertex positions from the DataTexture instead of the position attribute. To do this, line 103 must be included and line 105 deactivated.
The testTexture only serves the purpose that the shader has a texture. The testTexture itself is meaningless and unsuitable for the application.
Code
Live example
https://codepen.io/Spiri0/pen/qBQzJNr
Screenshots
No response
Version
155
Device
Desktop
Browser
Chrome
OS
Windows
The text was updated successfully, but these errors were encountered: