Skip to content

Commit c9954a3

Browse files
committed
added monkey head + normal map node (still WIP ) + canvas resize issue (still weird) + combo box set items + mask some elements to stay within render box + metallic & roughness in standard material
1 parent 3adce48 commit c9954a3

File tree

15 files changed

+292
-25
lines changed

15 files changed

+292
-25
lines changed

public/monkey.glb

115 KB
Binary file not shown.

src/Editor.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ export class Editor {
106106
this.canvas.height = window.innerHeight * dpr;
107107

108108
// Set CSS size (for display)
109-
this.canvas.style.width = `${window.innerWidth}px`;
110-
this.canvas.style.height = `${window.innerHeight}px`;
109+
this.canvas.style.width = "100vw"; // `${window.innerWidth}px`;
110+
this.canvas.style.height = "100vh"// `${window.innerHeight}px`;
111111

112112
this.canvasAspect = this.canvas.height / this.canvas.width;
113113
this.reset();
@@ -496,6 +496,11 @@ export class Editor {
496496
}
497497

498498
protected onResize() {
499+
const dpr = window.devicePixelRatio || 1;
500+
501+
this.canvas.width = window.innerWidth * dpr;
502+
this.canvas.height = window.innerHeight * dpr;
503+
499504
const newAspectCorrection = ( this.canvas.offsetWidth/this.canvas.offsetHeight )*this.canvasAspect;
500505

501506
const xChange = this.aspectCorrection/newAspectCorrection;

src/EditorNodes.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { mathFunctions, mathOperations } from "./nodes/operators/list";
77
import { methodsDefinitions2NodeClassDefinitions } from "./nodes/operators/MethodCallNode";
88
import { MeshStandardNode } from "./nodes/shader/MeshStandardNode";
99
import { ImageTextureNode } from "./nodes/texture/ImageTextureNode";
10+
import { NormalMapNode } from "./nodes/vector/NormalMapNode";
1011

1112
// Define the type for class constructors that extend BaseType
1213
type Constructor<T extends Node> = new (...args: any[]) => T;
@@ -57,5 +58,12 @@ export const NodeTypes : NodeGroupType[] = [
5758
nodes:[
5859
{ TypeClass:ImageTextureNode, name:"Image Texture", id:"image-texture"}
5960
]
61+
},
62+
{
63+
group:"Vector",
64+
color:Theme.config.groupVector as string,
65+
nodes: [
66+
{ TypeClass:NormalMapNode, name: "Normal Map", id:"normal-map" }
67+
]
6068
}
6169
]

src/ThreeScene.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { clamp } from 'three/src/math/MathUtils.js';
22
import * as THREE from 'three/webgpu';
33
import { WebGPURenderer } from 'three/webgpu';
4+
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
45

5-
export class ThreeScene {
6+
type SceneEvents = {
7+
modelLoaded: {}
8+
}
9+
10+
export class ThreeScene extends THREE.EventDispatcher<SceneEvents>{
611
readonly scene:THREE.Scene;
712
readonly camera:THREE.PerspectiveCamera;
813
readonly renderer:WebGPURenderer;
@@ -19,6 +24,8 @@ export class ThreeScene {
1924
private materialNotSet = new THREE.MeshStandardMaterial({ color: 0xcccccc });
2025

2126
constructor() {
27+
super();
28+
2229
this.scene = new THREE.Scene();
2330
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
2431

@@ -69,6 +76,25 @@ export class ThreeScene {
6976
this.objs.push( sphere );
7077
this.objHolder.add( sphere );
7178

79+
const loader = new GLTFLoader();
80+
81+
loader.load( import.meta.env.BASE_URL+'monkey.glb', ( gltf ) => {
82+
83+
const monkey = gltf.scene.getObjectByName("monkey") as THREE.Mesh;
84+
monkey.name = "Monkey";
85+
monkey.visible = false;
86+
87+
this.objs.push( monkey)
88+
this.objHolder.add( monkey );
89+
90+
this.dispatchEvent({ type:"modelLoaded" })
91+
92+
}, undefined, function ( error ) {
93+
94+
console.error( error );
95+
96+
} );
97+
7298

7399
this.scene.add( this.objHolder )
74100

@@ -119,14 +145,15 @@ export class ThreeScene {
119145
set currentObjectIndex(index:number) {
120146
this._currentObjectIndex = clamp( index, 0, this.objs.length-1 );
121147
this.objs.forEach( (obj,i)=>obj.visible = i==index )
148+
console.log(index, this.objs )
122149
}
123150

124151
render() {
125152

126153
const delta = this.clock.getDelta()
127154
this.updateLightPosition();
128155
this.objHolder.rotateY(delta*this.rotationSpeed)
129-
this.objHolder.rotateX(-delta*this.rotationSpeed)
156+
//this.objHolder.rotateX(-delta*this.rotationSpeed)
130157
this.renderer.render( this.scene, this.camera );
131158
}
132159

src/components/ComboBox.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,30 @@ export class ComboBox extends InteractiveLayoutElement implements IOverlayRender
4747
this.index = 0;
4848
}
4949

50+
protected setListItems( items:string[] ) {
51+
const uiItems = items.map( (opt, i)=>new ListItem( opt, false, ()=>this.onOptionClicked(i), this.onScroll.bind(this) ));
52+
53+
if( this.listItems )
54+
{
55+
this.listItems.length = 0;
56+
this.listItems.push( ...uiItems );
57+
58+
uiItems.forEach( item=>item.parent=this.listLayout );
59+
}
60+
61+
return uiItems;
62+
}
63+
64+
updateOptions( newOptions:string[] )
65+
{
66+
this.setListItems( newOptions );
67+
}
68+
5069
get overlayBody(){ return this.comboList }
5170

5271
get index() { return this._index; }
5372
set index( i:number ) {
54-
const newIndex = clamp( i, 0, this.options.length-1 );
73+
const newIndex = clamp( i, 0, this.listItems.length-1 );
5574
const changed = newIndex!=this._index;
5675
this._index = newIndex;
5776

@@ -112,6 +131,7 @@ export class ComboBox extends InteractiveLayoutElement implements IOverlayRender
112131
}
113132

114133
protected onOptionClicked( i:number ) {
134+
console.log("CLICKED", i)
115135
this.index = i;
116136
(this.root as Node).editor.overlay = undefined;
117137
}

src/components/Header.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ export class HeaderElement extends LayoutElement {
1414
ctx.fillStyle = this.bgColor;
1515
ctx.fill()
1616

17-
17+
ctx.save();
18+
ctx.clip();
1819
this.writeText(ctx, this.title, this.fontSize, 10, maxHeight, this.fontColor );
20+
ctx.restore();
1921
}
2022
}

src/export/Script.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,25 @@ export class Script {
3535
* Defines a variable or function... if it is not already set. Else, it will not override.
3636
* @param varName
3737
* @param varValue a valid js sintax string or an object that will be stringified to a JSON
38+
* @param valueIsFunctionBody the contents of `varValue` will be put in the body of a self executing function.
3839
* @returns the name of the property passed.
3940
*/
40-
define( varName:string, varValue:string|Object ) {
41+
define( varName:string, varValue:string|Object, valueIsFunctionBody = false ) {
4142
if( typeof varValue == "object" )
4243
{
4344
varValue = JSON.stringify(varValue);
44-
}
45+
valueIsFunctionBody = false;
46+
}
47+
else
48+
{
49+
if( valueIsFunctionBody && !varValue.includes("return") )
50+
{
51+
throw new Error(`The value of script variable ${varName} MUST contain a return, since it is using valueIsFunctionBody=true`);
52+
}
53+
}
4554

4655
if( !this.definitions.find(def=>def[0]==varName ))
47-
this.definitions.push( [ varName, String( varValue ) ] );
56+
this.definitions.push( [ varName, String( valueIsFunctionBody? `(()=>{${varValue}})()` : varValue ) ] );
4857
return varName;
4958
}
5059

src/nodes/preview/ScenePreview.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class ScenePreviewNode extends WinNode {
2121

2222
const ambientLightSlider = new DraggableValue("Ambient light", true, 0, 3, 0.1, value =>this.onAmbientLightSlider(value) );
2323
const rotationSpeedSlider = new DraggableValue("Rotation speed", true, 0, 2, 0.1, value =>scene.rotationSpeed=value);
24-
const objType = new ComboBox("Wrapping mode", scene.meshes.map(m=>m.name), value=>scene.currentObjectIndex=value );
24+
const objType = new ComboBox("Object", scene.meshes.map(m=>m.name), value=>scene.currentObjectIndex=value );
2525

2626
const materialSlots = [
2727
new MaterialProperty(0),
@@ -50,6 +50,10 @@ export class ScenePreviewNode extends WinNode {
5050

5151
this.errorMaterial = new MeshBasicMaterial({ color:0xff0000 });
5252

53+
scene.addEventListener("modelLoaded", ()=> {
54+
objType.updateOptions( scene.meshes.map(m=>m.name) );
55+
});
56+
5357
}
5458

5559
protected onAmbientLightSlider( intensity:number ) {
@@ -87,6 +91,7 @@ export class ScenePreviewNode extends WinNode {
8791
}
8892
catch( error )
8993
{
94+
console.error( error )
9095
this.scene.setMaterial( materialIndex, this.errorMaterial );
9196
}
9297
}

src/nodes/shader/MeshStandardNode.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,78 @@ import { Script } from "../../export/Script";
44
import { BaseColorProperty } from "../../properties/BaseColorProperty";
55
import { MaterialOutput } from "../../properties/MaterialOutput";
66
import { WinNode } from "../WinNode";
7+
import { InputOrValue } from "../../properties/InputOrValue";
8+
import { MeshStandardNodeMaterial, NormalMapNode } from "three/webgpu";
9+
import { BasicInputProperty } from "../../properties/BasicInputProperty";
710

811
export class MeshStandardNode extends WinNode {
912

1013
protected colorProperty:BaseColorProperty;
14+
protected metallic:InputOrValue;
15+
protected roughness:InputOrValue;
16+
protected normal:BasicInputProperty;
1117

1218
constructor() {
1319

1420
const colorNodeInput = new BaseColorProperty();
21+
const metallic = new InputOrValue(1, { label:"Metallic", min:0, max:1, asBar:true });
22+
metallic.multiplyInputWithValue = true;
1523

16-
super( "MeshStandardMaterial", Theme.config.groupShader, [
24+
const roughness = new InputOrValue(1, { label:"Roughness", min:0, max:1, asBar:true });
25+
roughness.multiplyInputWithValue = true;
26+
27+
const normal = new BasicInputProperty(2, "Normal");
28+
29+
30+
super( "MeshStandardNodeMaterial", Theme.config.groupShader, [
1731
new MaterialOutput(),
18-
colorNodeInput
32+
colorNodeInput,
33+
metallic,
34+
roughness,
35+
normal
1936
] );
2037

2138
this.colorProperty = colorNodeInput;
39+
this.metallic = metallic;
40+
this.roughness = roughness;
41+
this.normal = normal;
2242
}
2343

2444
override writeScript( script: Script) {
2545

2646
const colorNode = this.colorProperty.writeScript( script );
27-
47+
const metallicNode = this.metallic.writeScript( script );
48+
const roughnessNode = this.roughness.writeScript( script );
49+
const normalNode = this.normal.writeScript( script );
50+
51+
//const material = new MeshStandardNodeMaterial();
52+
2853
return script.define( this.nodeName, `()=>{
2954
const material = new THREE.MeshStandardNodeMaterial();
3055
material.colorNode = ${colorNode};
56+
57+
material.metalnessNode = ${metallicNode};
58+
material.roughnessNode = ${roughnessNode};
59+
${ normalNode!=""? `material.normalNode = ${normalNode};`:"" }
60+
3161
return material;
3262
}` );
3363
}
3464

3565
override serialize(): Record<string, any> {
3666
return {
3767
...super.serialize(),
38-
baseColor: "#"+this.colorProperty.baseColor.getHexString()
68+
baseColor: "#"+this.colorProperty.baseColor.getHexString(),
69+
metallic: this.metallic.value,
70+
roughness: this.roughness.value
3971
}
4072
}
4173

4274
override unserialize(data: Record<string, any>): void {
4375
super.unserialize(data);
4476
if( data.baseColor ) this.colorProperty.baseColor = new Color( data.baseColor );
77+
78+
this.metallic.value = data.metallic;
79+
this.roughness.value = data.roughness;
4580
}
4681
}

src/nodes/texture/ImageTextureNode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export class ImageTextureNode extends TextureTypeNode {
4040
${texture}.wrapS = ${ this.extensionPolicy.extensionMode };
4141
${texture}.wrapT = ${ this.extensionPolicy.extensionMode };
4242
${texture}.mapping = ${ this.mappingPolicy.mappingType };
43+
${texture}.flipY = false;
44+
4345
` ) ;
4446

4547
const uv = this.uv.writeScript(script);

0 commit comments

Comments
 (0)