UNPKG

@polygonjs/polygonjs

Version:

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

124 lines (123 loc) 4.13 kB
"use strict"; import { TypedSopNode } from "./_Base"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { NodeContext } from "../../poly/NodeContext"; import { InputCloneMode } from "../../poly/InputCloneMode"; import { CoreImage } from "../../../core/Image"; import { Attribute } from "../../../core/geometry/Attribute"; import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory"; class HeightMapSopParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param texture node to load the heightmap from */ this.texture = ParamConfig.NODE_PATH("", { nodeSelection: { context: NodeContext.COP } }); /** @param values multiplier */ this.mult = ParamConfig.FLOAT(1); } } const ParamsConfig = new HeightMapSopParamsConfig(); export class HeightMapSopNode extends TypedSopNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; } static type() { return "heightMap"; } initializeNode() { this.io.inputs.setCount(1); this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE); } async cook(inputCoreGroups) { const coreGroup = inputCoreGroups[0]; const node = this.pv.texture.nodeWithContext(NodeContext.COP, this.states.error); if (node) { const node_context = node.context(); if (node_context == NodeContext.COP) { const texture_node = node; const container = await texture_node.compute(); const texture = container.texture(); const objects2 = coreGroup.allObjects(); for (const object of objects2) { this._setPositionFromDataTexture(object, texture); } } else { this.states.error.set("found node is not a texture"); } } const objects = coreGroup.threejsObjectsWithGeo(); for (const object of objects) { object.geometry.computeVertexNormals(); } this.setCoreGroup(coreGroup); } _setPositionFromDataTexture(object, texture) { const textureData = this._dataFromTexture(texture); if (!textureData) { return; } const { data, resx, resy } = textureData; const texture_component_size = data.length / (resx * resy); const corePointClass = corePointClassFactory(object); const positions = corePointClass.attribute(object, Attribute.POSITION).array; const uvAttrib = corePointClass.attribute(object, Attribute.UV); const normalAttrib = corePointClass.attribute(object, Attribute.NORMAL); if (uvAttrib == null) { this.states.error.set("uvs are required"); return; } if (normalAttrib == null) { this.states.error.set("normals are required"); return; } const uvs = uvAttrib.array; const normals = normalAttrib.array; const points_count = positions.length / 3; let uv_stride, uvx, uvy, x, y, j, val; let index = 0; for (let i = 0; i < points_count; i++) { uv_stride = i * 2; uvx = uvs[uv_stride]; uvy = uvs[uv_stride + 1]; x = Math.floor((resx - 1) * uvx); y = Math.floor((resy - 1) * (1 - uvy)); j = y * resx + x; val = data[texture_component_size * j]; index = i * 3; positions[index + 0] += normals[index + 0] * val * this.pv.mult; positions[index + 1] += normals[index + 1] * val * this.pv.mult; positions[index + 2] += normals[index + 2] * val * this.pv.mult; } } _dataFromTexture(texture) { if (texture.image) { if (texture.image.data) { return this._dataFromDataTexture(texture); } return this._dataFromDefaultTexture(texture); } } _dataFromDefaultTexture(texture) { const resx = texture.image.width; const resy = texture.image.height; const image_data = CoreImage.data_from_image(texture.image); const data = image_data.data; return { data, resx, resy }; } _dataFromDataTexture(texture) { const data = texture.image.data; const resx = texture.image.width; const resy = texture.image.height; return { data, resx, resy }; } }