未验证 提交 813daf1f 编写于 作者: S sunag 提交者: GitHub

NodeEditor: Preview (#23508)

* add ViewHelper to examples

* fix type conversion

* cleanup

* fix initial value

* fix toggle flipY

* add PreviewEditor

* fix change parent connections
上级 be9ead22
import { UIPanel } from './libs/ui.js';
import * as THREE from 'three';
import { ViewHelper as ViewHelperBase } from '../../examples/jsm/helpers/ViewHelper.js';
class ViewHelper extends THREE.Object3D {
class ViewHelper extends ViewHelperBase {
constructor( editorCamera, container ) {
super();
this.animating = false;
this.controls = null;
super( editorCamera, container.dom );
const panel = new UIPanel();
panel.setId( 'viewHelper' );
......@@ -19,13 +16,11 @@ class ViewHelper extends THREE.Object3D {
panel.setHeight( '128px' );
panel.setWidth( '128px' );
const scope = this;
panel.dom.addEventListener( 'pointerup', function ( event ) {
panel.dom.addEventListener( 'pointerup', ( event ) => {
event.stopPropagation();
scope.handleClick( event );
this.handleClick( event );
} );
......@@ -37,280 +32,8 @@ class ViewHelper extends THREE.Object3D {
container.add( panel );
const color1 = new THREE.Color( '#ff3653' );
const color2 = new THREE.Color( '#8adb00' );
const color3 = new THREE.Color( '#2c8fff' );
const interactiveObjects = [];
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const dummy = new THREE.Object3D();
const camera = new THREE.OrthographicCamera( - 2, 2, 2, - 2, 0, 4 );
camera.position.set( 0, 0, 2 );
const geometry = new THREE.BoxGeometry( 0.8, 0.05, 0.05 ).translate( 0.4, 0, 0 );
const xAxis = new THREE.Mesh( geometry, getAxisMaterial( color1 ) );
const yAxis = new THREE.Mesh( geometry, getAxisMaterial( color2 ) );
const zAxis = new THREE.Mesh( geometry, getAxisMaterial( color3 ) );
yAxis.rotation.z = Math.PI / 2;
zAxis.rotation.y = - Math.PI / 2;
this.add( xAxis );
this.add( zAxis );
this.add( yAxis );
const posXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1, 'X' ) );
posXAxisHelper.userData.type = 'posX';
const posYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2, 'Y' ) );
posYAxisHelper.userData.type = 'posY';
const posZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3, 'Z' ) );
posZAxisHelper.userData.type = 'posZ';
const negXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1 ) );
negXAxisHelper.userData.type = 'negX';
const negYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2 ) );
negYAxisHelper.userData.type = 'negY';
const negZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3 ) );
negZAxisHelper.userData.type = 'negZ';
posXAxisHelper.position.x = 1;
posYAxisHelper.position.y = 1;
posZAxisHelper.position.z = 1;
negXAxisHelper.position.x = - 1;
negXAxisHelper.scale.setScalar( 0.8 );
negYAxisHelper.position.y = - 1;
negYAxisHelper.scale.setScalar( 0.8 );
negZAxisHelper.position.z = - 1;
negZAxisHelper.scale.setScalar( 0.8 );
this.add( posXAxisHelper );
this.add( posYAxisHelper );
this.add( posZAxisHelper );
this.add( negXAxisHelper );
this.add( negYAxisHelper );
this.add( negZAxisHelper );
interactiveObjects.push( posXAxisHelper );
interactiveObjects.push( posYAxisHelper );
interactiveObjects.push( posZAxisHelper );
interactiveObjects.push( negXAxisHelper );
interactiveObjects.push( negYAxisHelper );
interactiveObjects.push( negZAxisHelper );
const point = new THREE.Vector3();
const dim = 128;
const turnRate = 2 * Math.PI; // turn rate in angles per second
this.render = function ( renderer ) {
this.quaternion.copy( editorCamera.quaternion ).invert();
this.updateMatrixWorld();
point.set( 0, 0, 1 );
point.applyQuaternion( editorCamera.quaternion );
if ( point.x >= 0 ) {
posXAxisHelper.material.opacity = 1;
negXAxisHelper.material.opacity = 0.5;
} else {
posXAxisHelper.material.opacity = 0.5;
negXAxisHelper.material.opacity = 1;
}
if ( point.y >= 0 ) {
posYAxisHelper.material.opacity = 1;
negYAxisHelper.material.opacity = 0.5;
} else {
posYAxisHelper.material.opacity = 0.5;
negYAxisHelper.material.opacity = 1;
}
if ( point.z >= 0 ) {
posZAxisHelper.material.opacity = 1;
negZAxisHelper.material.opacity = 0.5;
} else {
posZAxisHelper.material.opacity = 0.5;
negZAxisHelper.material.opacity = 1;
}
//
const x = container.dom.offsetWidth - dim;
renderer.clearDepth();
renderer.setViewport( x, 0, dim, dim );
renderer.render( this, camera );
};
const targetPosition = new THREE.Vector3();
const targetQuaternion = new THREE.Quaternion();
const q1 = new THREE.Quaternion();
const q2 = new THREE.Quaternion();
let radius = 0;
this.handleClick = function ( event ) {
if ( this.animating === true ) return false;
const rect = container.dom.getBoundingClientRect();
const offsetX = rect.left + ( container.dom.offsetWidth - dim );
const offsetY = rect.top + ( container.dom.offsetHeight - dim );
mouse.x = ( ( event.clientX - offsetX ) / ( rect.width - offsetX ) ) * 2 - 1;
mouse.y = - ( ( event.clientY - offsetY ) / ( rect.bottom - offsetY ) ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects( interactiveObjects );
if ( intersects.length > 0 ) {
const intersection = intersects[ 0 ];
const object = intersection.object;
prepareAnimationData( object, this.controls.center );
this.animating = true;
return true;
} else {
return false;
}
};
this.update = function ( delta ) {
const step = delta * turnRate;
const focusPoint = this.controls.center;
// animate position by doing a slerp and then scaling the position on the unit sphere
q1.rotateTowards( q2, step );
editorCamera.position.set( 0, 0, 1 ).applyQuaternion( q1 ).multiplyScalar( radius ).add( focusPoint );
// animate orientation
editorCamera.quaternion.rotateTowards( targetQuaternion, step );
if ( q1.angleTo( q2 ) === 0 ) {
this.animating = false;
}
};
function prepareAnimationData( object, focusPoint ) {
switch ( object.userData.type ) {
case 'posX':
targetPosition.set( 1, 0, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI * 0.5, 0 ) );
break;
case 'posY':
targetPosition.set( 0, 1, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( - Math.PI * 0.5, 0, 0 ) );
break;
case 'posZ':
targetPosition.set( 0, 0, 1 );
targetQuaternion.setFromEuler( new THREE.Euler() );
break;
case 'negX':
targetPosition.set( - 1, 0, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, - Math.PI * 0.5, 0 ) );
break;
case 'negY':
targetPosition.set( 0, - 1, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( Math.PI * 0.5, 0, 0 ) );
break;
case 'negZ':
targetPosition.set( 0, 0, - 1 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI, 0 ) );
break;
default:
console.error( 'ViewHelper: Invalid axis.' );
}
//
radius = editorCamera.position.distanceTo( focusPoint );
targetPosition.multiplyScalar( radius ).add( focusPoint );
dummy.position.copy( focusPoint );
dummy.lookAt( editorCamera.position );
q1.copy( dummy.quaternion );
dummy.lookAt( targetPosition );
q2.copy( dummy.quaternion );
}
function getAxisMaterial( color ) {
return new THREE.MeshBasicMaterial( { color: color, toneMapped: false } );
}
function getSpriteMaterial( color, text = null ) {
const canvas = document.createElement( 'canvas' );
canvas.width = 64;
canvas.height = 64;
const context = canvas.getContext( '2d' );
context.beginPath();
context.arc( 32, 32, 16, 0, 2 * Math.PI );
context.closePath();
context.fillStyle = color.getStyle();
context.fill();
if ( text !== null ) {
context.font = '24px Arial';
context.textAlign = 'center';
context.fillStyle = '#000000';
context.fillText( text, 32, 41 );
}
const texture = new THREE.CanvasTexture( canvas );
return new THREE.SpriteMaterial( { map: texture, toneMapped: false } );
}
}
}
ViewHelper.prototype.isViewHelper = true;
export { ViewHelper };
import * as THREE from 'three';
const vpTemp = new THREE.Vector4();
class ViewHelper extends THREE.Object3D {
constructor( editorCamera, dom ) {
super();
this.animating = false;
this.controls = null;
const color1 = new THREE.Color( '#ff3653' );
const color2 = new THREE.Color( '#8adb00' );
const color3 = new THREE.Color( '#2c8fff' );
const interactiveObjects = [];
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const dummy = new THREE.Object3D();
const camera = new THREE.OrthographicCamera( - 2, 2, 2, - 2, 0, 4 );
camera.position.set( 0, 0, 2 );
const geometry = new THREE.BoxGeometry( 0.8, 0.05, 0.05 ).translate( 0.4, 0, 0 );
const xAxis = new THREE.Mesh( geometry, getAxisMaterial( color1 ) );
const yAxis = new THREE.Mesh( geometry, getAxisMaterial( color2 ) );
const zAxis = new THREE.Mesh( geometry, getAxisMaterial( color3 ) );
yAxis.rotation.z = Math.PI / 2;
zAxis.rotation.y = - Math.PI / 2;
this.add( xAxis );
this.add( zAxis );
this.add( yAxis );
const posXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1, 'X' ) );
posXAxisHelper.userData.type = 'posX';
const posYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2, 'Y' ) );
posYAxisHelper.userData.type = 'posY';
const posZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3, 'Z' ) );
posZAxisHelper.userData.type = 'posZ';
const negXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1 ) );
negXAxisHelper.userData.type = 'negX';
const negYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2 ) );
negYAxisHelper.userData.type = 'negY';
const negZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3 ) );
negZAxisHelper.userData.type = 'negZ';
posXAxisHelper.position.x = 1;
posYAxisHelper.position.y = 1;
posZAxisHelper.position.z = 1;
negXAxisHelper.position.x = - 1;
negXAxisHelper.scale.setScalar( 0.8 );
negYAxisHelper.position.y = - 1;
negYAxisHelper.scale.setScalar( 0.8 );
negZAxisHelper.position.z = - 1;
negZAxisHelper.scale.setScalar( 0.8 );
this.add( posXAxisHelper );
this.add( posYAxisHelper );
this.add( posZAxisHelper );
this.add( negXAxisHelper );
this.add( negYAxisHelper );
this.add( negZAxisHelper );
interactiveObjects.push( posXAxisHelper );
interactiveObjects.push( posYAxisHelper );
interactiveObjects.push( posZAxisHelper );
interactiveObjects.push( negXAxisHelper );
interactiveObjects.push( negYAxisHelper );
interactiveObjects.push( negZAxisHelper );
const point = new THREE.Vector3();
const dim = 128;
const turnRate = 2 * Math.PI; // turn rate in angles per second
this.render = function ( renderer ) {
this.quaternion.copy( editorCamera.quaternion ).invert();
this.updateMatrixWorld();
point.set( 0, 0, 1 );
point.applyQuaternion( editorCamera.quaternion );
if ( point.x >= 0 ) {
posXAxisHelper.material.opacity = 1;
negXAxisHelper.material.opacity = 0.5;
} else {
posXAxisHelper.material.opacity = 0.5;
negXAxisHelper.material.opacity = 1;
}
if ( point.y >= 0 ) {
posYAxisHelper.material.opacity = 1;
negYAxisHelper.material.opacity = 0.5;
} else {
posYAxisHelper.material.opacity = 0.5;
negYAxisHelper.material.opacity = 1;
}
if ( point.z >= 0 ) {
posZAxisHelper.material.opacity = 1;
negZAxisHelper.material.opacity = 0.5;
} else {
posZAxisHelper.material.opacity = 0.5;
negZAxisHelper.material.opacity = 1;
}
//
const x = dom.offsetWidth - dim;
renderer.clearDepth();
renderer.getViewport( vpTemp );
renderer.setViewport( x, 0, dim, dim );
renderer.render( this, camera );
renderer.setViewport( vpTemp.x, vpTemp.y, vpTemp.z, vpTemp.w );
};
const targetPosition = new THREE.Vector3();
const targetQuaternion = new THREE.Quaternion();
const q1 = new THREE.Quaternion();
const q2 = new THREE.Quaternion();
let radius = 0;
this.handleClick = function ( event ) {
if ( this.animating === true ) return false;
const rect = dom.getBoundingClientRect();
const offsetX = rect.left + ( container.dom.offsetWidth - dim );
const offsetY = rect.top + ( container.dom.offsetHeight - dim );
mouse.x = ( ( event.clientX - offsetX ) / ( rect.width - offsetX ) ) * 2 - 1;
mouse.y = - ( ( event.clientY - offsetY ) / ( rect.bottom - offsetY ) ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects( interactiveObjects );
if ( intersects.length > 0 ) {
const intersection = intersects[ 0 ];
const object = intersection.object;
prepareAnimationData( object, this.controls.center );
this.animating = true;
return true;
} else {
return false;
}
};
this.update = function ( delta ) {
const step = delta * turnRate;
const focusPoint = this.controls.center;
// animate position by doing a slerp and then scaling the position on the unit sphere
q1.rotateTowards( q2, step );
editorCamera.position.set( 0, 0, 1 ).applyQuaternion( q1 ).multiplyScalar( radius ).add( focusPoint );
// animate orientation
editorCamera.quaternion.rotateTowards( targetQuaternion, step );
if ( q1.angleTo( q2 ) === 0 ) {
this.animating = false;
}
};
function prepareAnimationData( object, focusPoint ) {
switch ( object.userData.type ) {
case 'posX':
targetPosition.set( 1, 0, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI * 0.5, 0 ) );
break;
case 'posY':
targetPosition.set( 0, 1, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( - Math.PI * 0.5, 0, 0 ) );
break;
case 'posZ':
targetPosition.set( 0, 0, 1 );
targetQuaternion.setFromEuler( new THREE.Euler() );
break;
case 'negX':
targetPosition.set( - 1, 0, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, - Math.PI * 0.5, 0 ) );
break;
case 'negY':
targetPosition.set( 0, - 1, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( Math.PI * 0.5, 0, 0 ) );
break;
case 'negZ':
targetPosition.set( 0, 0, - 1 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI, 0 ) );
break;
default:
console.error( 'ViewHelper: Invalid axis.' );
}
//
radius = editorCamera.position.distanceTo( focusPoint );
targetPosition.multiplyScalar( radius ).add( focusPoint );
dummy.position.copy( focusPoint );
dummy.lookAt( editorCamera.position );
q1.copy( dummy.quaternion );
dummy.lookAt( targetPosition );
q2.copy( dummy.quaternion );
}
function getAxisMaterial( color ) {
return new THREE.MeshBasicMaterial( { color: color, toneMapped: false } );
}
function getSpriteMaterial( color, text = null ) {
const canvas = document.createElement( 'canvas' );
canvas.width = 64;
canvas.height = 64;
const context = canvas.getContext( '2d' );
context.beginPath();
context.arc( 32, 32, 16, 0, 2 * Math.PI );
context.closePath();
context.fillStyle = color.getStyle();
context.fill();
if ( text !== null ) {
context.font = '24px Arial';
context.textAlign = 'center';
context.fillStyle = '#000000';
context.fillText( text, 32, 41 );
}
const texture = new THREE.CanvasTexture( canvas );
return new THREE.SpriteMaterial( { map: texture, toneMapped: false } );
}
}
}
ViewHelper.prototype.isViewHelper = true;
export { ViewHelper };
......@@ -22,6 +22,7 @@ import { NormalMapEditor } from './display/NormalMapEditor.js';
import { UVEditor } from './accessors/UVEditor.js';
import { PositionEditor } from './accessors/PositionEditor.js';
import { NormalEditor } from './accessors/NormalEditor.js';
import { PreviewEditor } from './utils/PreviewEditor.js';
import { TimerEditor } from './utils/TimerEditor.js';
import { OscillatorEditor } from './utils/OscillatorEditor.js';
import { SplitEditor } from './utils/SplitEditor.js';
......@@ -178,6 +179,11 @@ export const NodeList = [
name: 'Utils',
icon: 'apps',
children: [
{
name: 'Preview',
icon: 'square-check',
nodeClass: PreviewEditor
},
{
name: 'Timer',
icon: 'clock',
......
......@@ -134,7 +134,7 @@ export class TextureEditor extends BaseNode {
texture.wrapS = Number( this.wrapSInput.getValue() );
texture.wrapT = Number( this.wrapTInput.getValue() );
texture.flipY = this.flipYInput.getValue();
texture.needsUpdate = true;
texture.dispose();
this.invalidate();
......
......@@ -22,7 +22,7 @@ export class Vector4Editor extends BaseNode {
const fieldX = new NumberInput().setTagColor( 'red' ).onChange( onUpdate );
const fieldY = new NumberInput().setTagColor( 'green' ).onChange( onUpdate );
const fieldZ = new NumberInput().setTagColor( 'blue' ).onChange( onUpdate );
const fieldW = new NumberInput().setTagColor( 'white' ).onChange( onUpdate );
const fieldW = new NumberInput( 1 ).setTagColor( 'white' ).onChange( onUpdate );
this.add( new LabelElement( 'XYZW' )
.add( fieldX )
......
import { ColorInput, SliderInput, LabelElement } from '../../libs/flow.module.js';
import { BaseNode } from '../core/BaseNode.js';
import { MeshBasicNodeMaterial } from '../../renderers/nodes/Nodes.js';
import * as THREE from 'three';
import { MathUtils } from 'three';
export class BasicMaterialEditor extends BaseNode {
......@@ -68,7 +68,7 @@ export class BasicMaterialEditor extends BaseNode {
// TODO: Fix on NodeMaterial System
material.customProgramCacheKey = () => {
return THREE.MathUtils.generateUUID();
return MathUtils.generateUUID();
};
......
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { ViewHelper } from 'three/addons/helpers/ViewHelper.js';
import { Element, LabelElement, SelectInput } from '../../libs/flow.module.js';
import { BaseNode } from '../core/BaseNode.js';
import { MeshBasicNodeMaterial, FloatNode } from '../../renderers/nodes/Nodes.js';
import { WebGLRenderer, PerspectiveCamera, Scene, Mesh, DoubleSide, SphereGeometry, BoxGeometry, PlaneGeometry, TorusKnotGeometry } from 'three';
const nullValue = new FloatNode().setConst( true );
const sceneDict = {};
const getScene = ( name ) => {
let scene = sceneDict[ name ];
if ( scene === undefined ) {
scene = new Scene();
if ( name === 'box' ) {
const box = new Mesh( new BoxGeometry( 1.3, 1.3, 1.3 ) );
scene.add( box );
} else if ( name === 'sphere' ) {
const sphere = new Mesh( new SphereGeometry( 1, 32, 16 ) );
scene.add( sphere );
} else if ( name === 'plane' || name === 'sprite' ) {
const plane = new Mesh( new PlaneGeometry( 2, 2 ) );
scene.add( plane );
} else if ( name === 'torus' ) {
const torus = new Mesh( new TorusKnotGeometry( .7, .1, 100, 16 ) );
scene.add( torus );
}
sceneDict[ name ] = scene;
}
return scene;
};
export class PreviewEditor extends BaseNode {
constructor() {
const width = 300;
const height = 300;
super( 'Preview', 0, null, height );
const material = new MeshBasicNodeMaterial();
material.colorNode = nullValue;
material.side = DoubleSide;
material.transparent = true;
const previewElement = new Element();
previewElement.dom.style[ 'padding-top' ] = 0;
previewElement.dom.style[ 'padding-bottom' ] = 0;
const sceneInput = new SelectInput( [
{ name: 'Box', value: 'box' },
{ name: 'Sphere', value: 'sphere' },
{ name: 'Plane', value: 'plane' },
{ name: 'Sprite', value: 'sprite' },
{ name: 'Torus', value: 'torus' }
], 'box' );
const inputElement = new LabelElement( 'Input' ).setInput( 4 ).onConnect( () => {
material.colorNode = inputElement.getLinkedObject() || nullValue;
material.dispose();
}, true );
const canvas = document.createElement( 'canvas' );
canvas.style.position = 'absolute';
previewElement.dom.append( canvas );
previewElement.setHeight( height );
const renderer = new WebGLRenderer( {
canvas,
alpha: true
} );
renderer.autoClear = false;
renderer.setSize( width, height, true );
renderer.setPixelRatio( window.devicePixelRatio );
const camera = new PerspectiveCamera( 45, width / height, 0.1, 100 );
camera.aspect = width / height;
camera.updateProjectionMatrix();
camera.position.set( - 2, 2, 2 );
camera.lookAt( 0, 0, 0 );
const controls = new OrbitControls( camera, previewElement.dom );
controls.enableKeys = false;
controls.update();
const viewHelper = new ViewHelper( camera, previewElement.dom );
this.sceneInput = sceneInput;
this.viewHelper = viewHelper;
this.material = material;
this.camera = camera;
this.renderer = renderer;
this.add( inputElement )
.add( new LabelElement( 'Object' ).add( sceneInput ) )
.add( previewElement );
}
setEditor( editor ) {
super.setEditor( editor );
this.updateAnimationRequest();
}
updateAnimationRequest() {
if ( this.editor !== null ) {
requestAnimationFrame( () => this.update() );
}
}
update() {
const { viewHelper, material, renderer, camera, sceneInput } = this;
this.updateAnimationRequest();
const sceneName = sceneInput.getValue();
const scene = getScene( sceneName );
const mesh = scene.children[ 0 ];
mesh.material = material;
if ( sceneName === 'sprite' ) {
mesh.lookAt( camera.position );
}
renderer.clear();
renderer.render( scene, camera );
viewHelper.render( renderer );
}
}
......@@ -164,15 +164,15 @@ class MathNode extends TempNode {
} else if ( method === MathNode.SATURATE ) {
return `clamp( ${ a.build( builder, inputType ) }, 0.0, 1.0 )`;
return builder.format( `clamp( ${ a.build( builder, inputType ) }, 0.0, 1.0 )`, type, output );
} else if ( method === MathNode.NEGATE ) {
return '( -' + a.build( builder, inputType ) + ' )';
return builder.format( '( -' + a.build( builder, inputType ) + ' )', type, output );
} else if ( method === MathNode.INVERT ) {
return '( 1.0 - ' + a.build( builder, inputType ) + ' )';
return builder.format( '( 1.0 - ' + a.build( builder, inputType ) + ' )', type, output );
} else {
......
......@@ -149,21 +149,21 @@ class OperatorNode extends TempNode {
} else if ( op === '>' && outputLength > 1 ) {
return `${ builder.getMethod( 'greaterThan' ) }( ${a}, ${b} )`;
return builder.format( `${ builder.getMethod( 'greaterThan' ) }( ${a}, ${b} )`, type, output );
} else if ( op === '<=' && outputLength > 1 ) {
return `${ builder.getMethod( 'lessThanEqual' ) }( ${a}, ${b} )`;
return builder.format( `${ builder.getMethod( 'lessThanEqual' ) }( ${a}, ${b} )`, type, output );
} else {
return `( ${a} ${this.op} ${b} )`;
return builder.format( `( ${a} ${this.op} ${b} )`, type, output );
}
} else if ( typeA !== 'void' ) {
return `${a} ${this.op} ${b}`;
return builder.format( `${a} ${this.op} ${b}`, type, output );
}
......
......@@ -42,7 +42,8 @@
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js"
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册