UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

141 lines (131 loc) 4.77 kB
/** * Reads an attribute from a geometry and fills a texture with the values. * * @remarks * * This can be used to lookup geometry attributes inside a shader. * * */ import {TypedCopNode} from './_Base'; import {DataTexture, Mesh, Object3D, Texture} from 'three'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {NodeContext} from '../../poly/NodeContext'; import {CoreMask} from '../../../core/geometry/Mask'; import { textureFromAttributes, // textureFromAttributesMissingAttributes, textureFromAttributesTotalAttribSizes, } from '../../../core/geometry/operation/TextureFromAttribute'; import {CoreAttribute} from '../../../core/geometry/Attribute'; import {corePointClassFactory} from '../../../core/geometry/CoreObjectFactory'; class GeometryAttributeCopParamsConfig extends NodeParamsConfig { /** @param sop node */ node = ParamConfig.NODE_PATH('', { nodeSelection: { context: NodeContext.SOP, }, }); /** @param group to read the material from */ group = ParamConfig.STRING('', { objectMask: true, }); /** @param attribute name */ attribute = ParamConfig.STRING('P'); } const ParamsConfig = new GeometryAttributeCopParamsConfig(); export class GeometryAttributeCopNode extends TypedCopNode<GeometryAttributeCopParamsConfig> { override paramsConfig = ParamsConfig; static override type(): 'geometryAttribute' { return 'geometryAttribute'; } override async cook() { const geometryNode = this.pv.node.nodeWithContext(NodeContext.SOP, this.states.error); if (!geometryNode) { this.states.error.set(`node not found at path '${this.pv.node.path()}'`); return; } const container = await geometryNode.compute(); const coreGroup = container.coreContent(); if (!coreGroup) { this.states.error.set(`geometry invalid`); return; } const selectedObjects = CoreMask.filterThreejsObjects(coreGroup, this.pv); if (selectedObjects.length == 0) { this.states.error.set(`no object matching group`); return; } let texture: Texture | undefined; for (const selectedObject of selectedObjects) { const geometry = (selectedObject as Mesh).geometry; if (geometry) { texture = texture || this._textureFromGeometry(selectedObject); } } if (!texture) { this.cookController.endCook(); return; } this.setTexture(texture); } private _textureFromGeometry(object: Object3D): DataTexture | undefined { const corePointClass = corePointClassFactory(object); const geoAttribNames = corePointClass.attributeNames(object); const attribNames = CoreAttribute.attribNamesMatchingMask(this.pv.attribute, geoAttribNames); const geometry = (object as Mesh).geometry; if (!geometry) { return; } // the missing attributes is currently not working, since we use a mask check first // const missingAttributes = textureFromAttributesMissingAttributes(geometry, attribNames); // if (missingAttributes.length > 0) { // this.states.error.set(`missing attributes: ${missingAttributes.join(',')}`); // return; // } const totalSize = textureFromAttributesTotalAttribSizes(geometry, attribNames); if (totalSize > 4) { this.states.error.set(`total size of attributes is ${totalSize}, but maximum is 4`); return; } return textureFromAttributes(geometry, attribNames); // const position = geometry.attributes.position; // if (!(position instanceof BufferAttribute)) { // this.states.error.set('position is not a BufferAttribute'); // return; // } // const pointsCount = position.count; // const attributeName = CoreAttribute.remapName(this.pv.attribute); // const attribute = geometry.getAttribute(attributeName) as BufferAttribute; // if (!attribute) { // this.states.error.set(`attribute '${attributeName}' not found`); // return; // } // const attribSize = attribute.itemSize; // textureFromAttributeSize(geometry, textureSize); // const width = textureSize.x; // const height = textureSize.y; // const size = width * height * 4; // const pixelBuffer = new Float32Array(size); // const attribArray = attribute.array as number[]; // if (attribSize == 1) { // for (let i = 0; i < pointsCount; i++) { // pixelBuffer[i * 4] = attribArray[i]; // } // } else { // const vector = _vectorFromAttribSize(attribSize); // if (!vector) { // return; // } // for (let i = 0; i < pointsCount; i++) { // vector.fromArray(attribArray, i * attribSize); // vector.toArray(pixelBuffer, i * 4); // } // } // const texture = new DataTexture(pixelBuffer, width, height, RGBAFormat, FloatType); // texture.minFilter = texture.magFilter = NearestFilter; // texture.wrapS = texture.wrapT = RepeatWrapping; // texture.needsUpdate = true; // return texture; } }