polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
105 lines (104 loc) • 4.06 kB
JavaScript
import {WebGLRenderTarget as WebGLRenderTarget2} from "three/src/renderers/WebGLRenderTarget";
import {Vector2 as Vector22} from "three/src/math/Vector2";
import {LinearFilter, NearestFilter, RGBAFormat, FloatType, NoToneMapping, LinearEncoding} from "three/src/constants";
import {NodeContext as NodeContext2} from "../../../../poly/NodeContext";
export class RaycastGPUController {
constructor(_node) {
this._node = _node;
this._resolved_material = null;
this._restore_context = {
scene: {
overrideMaterial: null
},
renderer: {
toneMapping: -1,
outputEncoding: -1
}
};
this._mouse = new Vector22();
this._mouse_array = [0, 0];
this._read = new Float32Array(4);
this._param_read = [0, 0, 0, 0];
}
update_mouse(context) {
const canvas = context.viewer?.canvas();
if (!(canvas && context.event)) {
return;
}
if (context.event instanceof MouseEvent) {
this._mouse.x = context.event.offsetX / canvas.offsetWidth;
this._mouse.y = 1 - context.event.offsetY / canvas.offsetHeight;
this._mouse.toArray(this._mouse_array);
this._node.p.mouse.set(this._mouse_array);
}
}
process_event(context) {
const canvas = context.viewer?.canvas();
if (!(canvas && context.cameraNode)) {
return;
}
const camera_node = context.cameraNode;
const renderer_controller = camera_node.renderController;
if (renderer_controller) {
this._render_target = this._render_target || new WebGLRenderTarget2(canvas.offsetWidth, canvas.offsetHeight, {
minFilter: LinearFilter,
magFilter: NearestFilter,
format: RGBAFormat,
type: FloatType
});
if (!this._resolved_material) {
this.update_material();
console.warn("no material found");
return;
}
const threejs_camera = camera_node;
const scene = renderer_controller.resolved_scene || camera_node.scene().threejsScene();
const renderer = renderer_controller.renderer(canvas);
this._modify_scene_and_renderer(scene, renderer);
renderer.setRenderTarget(this._render_target);
renderer.clear();
renderer.render(scene, threejs_camera.object);
renderer.setRenderTarget(null);
this._restore_scene_and_renderer(scene, renderer);
renderer.readRenderTargetPixels(this._render_target, Math.round(this._mouse.x * canvas.offsetWidth), Math.round(this._mouse.y * canvas.offsetHeight), 1, 1, this._read);
this._param_read[0] = this._read[0];
this._param_read[1] = this._read[1];
this._param_read[2] = this._read[2];
this._param_read[3] = this._read[3];
this._node.p.pixelValue.set(this._param_read);
if (this._node.pv.pixelValue.x > this._node.pv.hitThreshold) {
this._node.trigger_hit(context);
} else {
this._node.trigger_miss(context);
}
}
}
_modify_scene_and_renderer(scene, renderer) {
this._restore_context.scene.overrideMaterial = scene.overrideMaterial;
this._restore_context.renderer.outputEncoding = renderer.outputEncoding;
this._restore_context.renderer.toneMapping = renderer.toneMapping;
scene.overrideMaterial = this._resolved_material;
renderer.toneMapping = NoToneMapping;
renderer.outputEncoding = LinearEncoding;
}
_restore_scene_and_renderer(scene, renderer) {
scene.overrideMaterial = this._restore_context.scene.overrideMaterial;
renderer.outputEncoding = this._restore_context.renderer.outputEncoding;
renderer.toneMapping = this._restore_context.renderer.toneMapping;
}
update_material() {
const node = this._node.p.material.found_node();
if (node) {
if (node.nodeContext() == NodeContext2.MAT) {
this._resolved_material = node.material;
} else {
this._node.states.error.set("target is not an obj");
}
} else {
this._node.states.error.set("no target found");
}
}
static PARAM_CALLBACK_update_material(node) {
node.gpu_controller.update_material();
}
}