Add WebXR rendering mode toggle with 4 modes
Implemented a single button in the toolbox that cycles through four rendering modes: 1. Lightmap + Lighting - diffuseColor + lightmapTexture with lighting enabled 2. Emissive Texture - emissiveColor + emissiveTexture with lighting disabled (default) 3. Flat Color - emissiveColor only with lighting disabled 4. Diffuse + Lights - diffuseColor with two dynamic scene lights enabled Features: - Single clickable button displays current mode and cycles to next on click - Automatically manages two scene lights (HemisphericLight + PointLight) for Diffuse + Lights mode - UI materials (buttons, handles, labels) are excluded from mode changes to remain readable - Button positioned below color grid with user-adjusted scaling - Added comprehensive naming conventions documentation - Updated inspector hotkey to Ctrl+Shift+I 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c7887d7d8f
commit
bda0735c7f
@ -108,3 +108,4 @@ Databases can be optionally encrypted. The `Encryption` class handles AES encryp
|
|||||||
- `VITE_SYNCDB_ENDPOINT`: Remote database sync endpoint
|
- `VITE_SYNCDB_ENDPOINT`: Remote database sync endpoint
|
||||||
|
|
||||||
Check `.env.local` for local configuration.
|
Check `.env.local` for local configuration.
|
||||||
|
- document the toolId and material naming conventions.
|
||||||
138
docs/NAMING_CONVENTIONS.md
Normal file
138
docs/NAMING_CONVENTIONS.md
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# Naming Conventions
|
||||||
|
|
||||||
|
## Tool and Material Naming
|
||||||
|
|
||||||
|
This document describes the naming conventions used for tools, materials, and related entities in the immersive WebXR application.
|
||||||
|
|
||||||
|
## Material Naming
|
||||||
|
|
||||||
|
Materials follow a consistent naming pattern based on their color:
|
||||||
|
|
||||||
|
**Format:** `material-{color}`
|
||||||
|
|
||||||
|
**Where:**
|
||||||
|
- `{color}` is the hex string representation of the material's color (e.g., `#ff0000` for red)
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
- `material-#ff0000` - Red material
|
||||||
|
- `material-#00ff00` - Green material
|
||||||
|
- `material-#222222` - Dark gray material
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
```typescript
|
||||||
|
const material = new StandardMaterial("material-" + color.toHexString(), scene);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Location:** Materials are created in:
|
||||||
|
- `src/toolbox/functions/buildColor.ts` - For toolbox color swatches
|
||||||
|
- `src/diagram/functions/buildMeshFromDiagramEntity.ts` - Fallback material creation via `buildMissingMaterial()`
|
||||||
|
|
||||||
|
## Tool Mesh Naming
|
||||||
|
|
||||||
|
Tool meshes use a compound naming pattern that includes both the tool type and color:
|
||||||
|
|
||||||
|
**Format:** `tool-{toolId}`
|
||||||
|
|
||||||
|
**Where:**
|
||||||
|
- `{toolId}` = `{toolType}-{color}`
|
||||||
|
- `{toolType}` is a value from the `ToolType` enum (e.g., `BOX`, `SPHERE`, `CYLINDER`, `CONE`, `PLANE`, `PERSON`)
|
||||||
|
- `{color}` is the hex string representation of the tool's color
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
- `tool-BOX-#ff0000` - Red box tool
|
||||||
|
- `tool-SPHERE-#00ff00` - Green sphere tool
|
||||||
|
- `tool-CYLINDER-#0000ff` - Blue cylinder tool
|
||||||
|
- `tool-PLANE-#ffff00` - Yellow plane tool
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
```typescript
|
||||||
|
function toolId(tool: ToolType, color: Color3) {
|
||||||
|
return tool + "-" + color.toHexString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const newItem = await buildMesh(tool, `tool-${id}`, colorParent.getScene());
|
||||||
|
// For example: `tool-BOX-#ff0000`
|
||||||
|
```
|
||||||
|
|
||||||
|
**Location:** Tool meshes are created in `src/toolbox/functions/buildTool.ts`
|
||||||
|
|
||||||
|
## Tool Colors
|
||||||
|
|
||||||
|
The application uses 16 predefined colors for the toolbox:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const colors: string[] = [
|
||||||
|
"#222222", "#8b4513", "#006400", "#778899", // Row 1: Dark gray, Brown, Dark green, Light slate gray
|
||||||
|
"#4b0082", "#ff0000", "#ffa500", "#ffff00", // Row 2: Indigo, Red, Orange, Yellow
|
||||||
|
"#00ff00", "#00ffff", "#0000ff", "#ff00ff", // Row 3: Green, Cyan, Blue, Magenta
|
||||||
|
"#1e90ff", "#98fb98", "#ffe4b5", "#ff69b4" // Row 4: Dodger blue, Pale green, Moccasin, Hot pink
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tool Types
|
||||||
|
|
||||||
|
Available tool types from the `ToolType` enum:
|
||||||
|
- `BOX` - Cube mesh
|
||||||
|
- `SPHERE` - Sphere mesh
|
||||||
|
- `CYLINDER` - Cylinder mesh
|
||||||
|
- `CONE` - Cone mesh
|
||||||
|
- `PLANE` - Flat plane mesh
|
||||||
|
- `PERSON` - Person/avatar mesh
|
||||||
|
|
||||||
|
## Material Color Access
|
||||||
|
|
||||||
|
When accessing material colors, use this priority order to handle both current and legacy materials:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// For StandardMaterial
|
||||||
|
const stdMat = material as StandardMaterial;
|
||||||
|
const materialColor = stdMat.emissiveColor || stdMat.diffuseColor;
|
||||||
|
|
||||||
|
// Current rendering uses emissiveColor
|
||||||
|
// Legacy materials may have diffuseColor instead
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rendering Modes
|
||||||
|
|
||||||
|
Materials can be rendered in three different modes, affecting how color properties are used:
|
||||||
|
|
||||||
|
### 1. Lightmap with Lighting
|
||||||
|
- Uses `diffuseColor` + `lightmapTexture`
|
||||||
|
- `disableLighting = false`
|
||||||
|
- Most expensive performance-wise
|
||||||
|
- Provides lighting illusion with actual lighting calculations
|
||||||
|
|
||||||
|
### 2. Unlit with Emissive Texture (Default)
|
||||||
|
- Uses `emissiveColor` + `emissiveTexture` (lightmap)
|
||||||
|
- `disableLighting = true`
|
||||||
|
- Best balance of visual quality and performance
|
||||||
|
- Provides lighting illusion without lighting calculations
|
||||||
|
|
||||||
|
### 3. Flat Emissive
|
||||||
|
- Uses only `emissiveColor`
|
||||||
|
- `disableLighting = true`
|
||||||
|
- Best performance
|
||||||
|
- No lighting illusion, flat shading
|
||||||
|
|
||||||
|
## Instance Naming
|
||||||
|
|
||||||
|
Instanced meshes (created from tool templates) follow this pattern:
|
||||||
|
|
||||||
|
**Format:** `tool-instance-{toolId}`
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```typescript
|
||||||
|
const instance = new InstancedMesh("tool-instance-" + id, newItem);
|
||||||
|
// For example: `tool-instance-BOX-#ff0000`
|
||||||
|
```
|
||||||
|
|
||||||
|
These instances share materials with their source mesh and are used for visual feedback before creating actual diagram entities.
|
||||||
|
|
||||||
|
## Related Files
|
||||||
|
|
||||||
|
- `src/toolbox/functions/buildTool.ts` - Tool mesh creation and naming
|
||||||
|
- `src/toolbox/functions/buildColor.ts` - Material creation and color management
|
||||||
|
- `src/diagram/functions/buildMeshFromDiagramEntity.ts` - Diagram entity instantiation
|
||||||
|
- `src/toolbox/types/toolType.ts` - ToolType enum definition
|
||||||
|
- `src/util/lightmapGenerator.ts` - Lightmap texture generation and caching
|
||||||
|
- `src/util/renderingMode.ts` - Rendering mode enum and labels
|
||||||
19
server/etc/cert.pem
Normal file
19
server/etc/cert.pem
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDHTCCAgWgAwIBAgIJF3WqWLMk6JOlMA0GCSqGSIb3DQEBCwUAMCwxKjAoBgNV
|
||||||
|
BAMTIWRldi1nMGx0MThuZGJjcDZlYXJyLnVzLmF1dGgwLmNvbTAeFw0yNDA4MTUx
|
||||||
|
NTE1NDdaFw0zODA0MjQxNTE1NDdaMCwxKjAoBgNVBAMTIWRldi1nMGx0MThuZGJj
|
||||||
|
cDZlYXJyLnVzLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAKfmuyqb2N8Tf5W9KTAy2D6FTkYICX+mcclyZS+0Mi7fLzSB7IeSuWXmuHoR
|
||||||
|
h5FHJ/Qp6eC1ahYs9WmAjFp81HPzZ/9hEbK3XrLMSta7zVldPTQjnt5sU/Zxr/M2
|
||||||
|
xMjHH2P3G231si+G20czvDWoItnyWs8rcE2wEcyiXM+/Ixgxoh8kfc9pqpNLXTvM
|
||||||
|
IvqAuxXbPeju3XccQ6B0lshN72EwV9yW73B0s7DuHsbBA0WHKYmcvdXgnQ1dU2/L
|
||||||
|
8BR5s/gJJE0MUh2qhsnKE3yUC/hTW7A0Qn0SMEZey04hvJWePnn59kv52DPVXZpZ
|
||||||
|
ql6ISehwn3hZdhHjpsoHbE48CN0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAd
|
||||||
|
BgNVHQ4EFgQUbjF1ri0QhHovlQ2D5gPtDucLGhowDgYDVR0PAQH/BAQDAgKEMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4IBAQAxIRNANDbVrkXF6x/KHYgj5prb+4yHtmYb7tiRi51z
|
||||||
|
MNHNLkltNou3dWsS4tU/YgzHTof3SJe2CIg9xAgk0XTHZjxRtbwIY6Zc9Sgf/KKL
|
||||||
|
OxFIiNcIQIGDoKHWmv2w4qSrYBkH9hva4kCysjgIFNc+0il7DQR2ifwLOxQGl/AE
|
||||||
|
hSfexgUKjfrno12gBlNCNcP+Xyn9/G++eg9vV+RuGLLIyLX0d0Vl7/C1pGoDrNpO
|
||||||
|
m/3oxR4IRnhEfGBD+LdWvmmIuxzXM1hSbLYJbMotHqKZSh0XlEM6Mi12gMZi7sEC
|
||||||
|
lhbXs+4ecvTBFfGCWFyUISFoSwRRnpQnEM5DsZT/t/Z8
|
||||||
|
-----END CERTIFICATE-----
|
||||||
126
server/etc/local.ini
Normal file
126
server/etc/local.ini
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
; CouchDB Configuration Settings
|
||||||
|
|
||||||
|
; Custom settings should be made in this file. They will override settings
|
||||||
|
; in default.ini, but unlike changes made to default.ini, this file won't be
|
||||||
|
; overwritten on server upgrade.
|
||||||
|
|
||||||
|
[couchdb]
|
||||||
|
database_dir = /var/snap/couchdb/common/data
|
||||||
|
view_index_dir = /var/snap/couchdb/common/data
|
||||||
|
;max_document_size = 4294967296 ; bytes
|
||||||
|
;os_process_timeout = 5000
|
||||||
|
uuid = dd27b78cfb458b894e0277173f176878
|
||||||
|
|
||||||
|
[couch_peruser]
|
||||||
|
; If enabled, couch_peruser ensures that a private per-user database
|
||||||
|
; exists for each document in _users. These databases are writable only
|
||||||
|
; by the corresponding user. Databases are in the following form:
|
||||||
|
; userdb-{hex encoded username}
|
||||||
|
enable = true
|
||||||
|
|
||||||
|
; If set to true and a user is deleted, the respective database gets
|
||||||
|
; deleted as well.
|
||||||
|
delete_dbs = true
|
||||||
|
|
||||||
|
; Set a default q value for peruser-created databases that is different from
|
||||||
|
; cluster / q
|
||||||
|
;q = 1
|
||||||
|
[log]
|
||||||
|
level = debug
|
||||||
|
|
||||||
|
[chttpd]
|
||||||
|
;port = 5984
|
||||||
|
bind_address = 127.0.0.1
|
||||||
|
authentication_handlers = {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
|
||||||
|
;authentication_handlers = {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
|
||||||
|
; Options for the MochiWeb HTTP server.
|
||||||
|
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
|
||||||
|
|
||||||
|
; For more socket options, consult Erlang's module 'inet' man page.
|
||||||
|
;socket_options = [{sndbuf, 262144}, {nodelay, true}]
|
||||||
|
enable_cors = true
|
||||||
|
|
||||||
|
[httpd]
|
||||||
|
; NOTE that this only configures the "backend" node-local port, not the
|
||||||
|
; "frontend" clustered port. You probably don't want to change anything in
|
||||||
|
; this section.
|
||||||
|
; Uncomment next line to trigger basic-auth popup on unauthorized requests.
|
||||||
|
;WWW-Authenticate = Basic realm="administrator"
|
||||||
|
|
||||||
|
; Uncomment next line to set the configuration modification whitelist. Only
|
||||||
|
; whitelisted values may be changed via the /_config URLs. To allow the admin
|
||||||
|
; to change this value over HTTP, remember to include {httpd,config_whitelist}
|
||||||
|
; itself. Excluding it from the list would require editing this file to update
|
||||||
|
; the whitelist.
|
||||||
|
;config_whitelist = [{httpd,config_whitelist}, {log,level}, {etc,etc}]
|
||||||
|
|
||||||
|
[ssl]
|
||||||
|
;enable = true
|
||||||
|
;cert_file = /full/path/to/server_cert.pem
|
||||||
|
;key_file = /full/path/to/server_key.pem
|
||||||
|
;password = somepassword
|
||||||
|
|
||||||
|
; set to true to validate peer certificates
|
||||||
|
;verify_ssl_certificates = false
|
||||||
|
|
||||||
|
; Set to true to fail if the client does not send a certificate. Only used if verify_ssl_certificates is true.
|
||||||
|
;fail_if_no_peer_cert = false
|
||||||
|
|
||||||
|
; Path to file containing PEM encoded CA certificates (trusted
|
||||||
|
; certificates used for verifying a peer certificate). May be omitted if
|
||||||
|
; you do not want to verify the peer.
|
||||||
|
;cacert_file = /full/path/to/cacertf
|
||||||
|
|
||||||
|
; The verification fun (optional) if not specified, the default
|
||||||
|
; verification fun will be used.
|
||||||
|
;verify_fun = {Module, VerifyFun}
|
||||||
|
|
||||||
|
; maximum peer certificate depth
|
||||||
|
;ssl_certificate_max_depth = 1
|
||||||
|
|
||||||
|
; Reject renegotiations that do not live up to RFC 5746.
|
||||||
|
;secure_renegotiate = true
|
||||||
|
|
||||||
|
; The cipher suites that should be supported.
|
||||||
|
; Can be specified in erlang format "{ecdhe_ecdsa,aes_128_cbc,sha256}"
|
||||||
|
; or in OpenSSL format "ECDHE-ECDSA-AES128-SHA256".
|
||||||
|
;ciphers = ["ECDHE-ECDSA-AES128-SHA256", "ECDHE-ECDSA-AES128-SHA"]
|
||||||
|
|
||||||
|
; The SSL/TLS versions to support
|
||||||
|
;tls_versions = [tlsv1, 'tlsv1.1', 'tlsv1.2']
|
||||||
|
|
||||||
|
; To enable Virtual Hosts in CouchDB, add a vhost = path directive. All requests to
|
||||||
|
; the Virtual Host will be redirected to the path. In the example below all requests
|
||||||
|
; to http://example.com/ are redirected to /database.
|
||||||
|
; If you run CouchDB on a specific port, include the port number in the vhost:
|
||||||
|
; example.com:5984 = /database
|
||||||
|
[vhosts]
|
||||||
|
;example.com = /database/
|
||||||
|
|
||||||
|
; To create an admin account uncomment the '[admins]' section below and add a
|
||||||
|
; line in the format 'username = password'. When you next start CouchDB, it
|
||||||
|
; will change the password to a hash (so that your passwords don't linger
|
||||||
|
; around in plain-text files). You can add more admin accounts with more
|
||||||
|
; 'username = password' lines. Don't forget to restart CouchDB after
|
||||||
|
; changing this.
|
||||||
|
[admins]
|
||||||
|
admin = -pbkdf2-eeee185ee6142700c0e5a9e31b1d6d85ba952a49,f073f989f3201b55d953825d56acad2a,10
|
||||||
|
|
||||||
|
[chttpd_auth]
|
||||||
|
secret = a6bc1f1fd52803b4feae8f30b3944300
|
||||||
|
;authentication_handlers = {chttpd_auth, jwt_authentication_handler}
|
||||||
|
[jwt_auth]
|
||||||
|
roles_claim_path = metadata.databases
|
||||||
|
required_claims = exp,iat
|
||||||
|
;validate_claim_iss = https://dev-g0lt18ndbcp6earr.us.auth0.com/
|
||||||
|
;validate_claim_aud = sxAJub9Uo2mOE7iYCTOuQGhppGLEPWzb
|
||||||
|
[jwt_keys]
|
||||||
|
rsa:_default = -----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+a7KpvY3xN/lb0pMDLY\nPoVORggJf6ZxyXJlL7QyLt8vNIHsh5K5Zea4ehGHkUcn9Cnp4LVqFiz1aYCMWnzU\nc/Nn/2ERsrdessxK1rvNWV09NCOe3mxT9nGv8zbEyMcfY/cbbfWyL4bbRzO8Nagi\n2fJazytwTbARzKJcz78jGDGiHyR9z2mqk0tdO8wi+oC7Fds96O7ddxxDoHSWyE3v\nYTBX3JbvcHSzsO4exsEDRYcpiZy91eCdDV1Tb8vwFHmz+AkkTQxSHaqGycoTfJQL\n+FNbsDRCfRIwRl7LTiG8lZ4+efn2S/nYM9VdmlmqXohJ6HCfeFl2EeOmygdsTjwI\n3QIDAQAB\n-----END PUBLIC KEY-----\n
|
||||||
|
|
||||||
|
rsa:1R0ZY6dzJ7ttWk60bT0_V = -----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+a7KpvY3xN/lb0pMDLY\nPoVORggJf6ZxyXJlL7QyLt8vNIHsh5K5Zea4ehGHkUcn9Cnp4LVqFiz1aYCMWnzU\nc/Nn/2ERsrdessxK1rvNWV09NCOe3mxT9nGv8zbEyMcfY/cbbfWyL4bbRzO8Nagi\n2fJazytwTbARzKJcz78jGDGiHyR9z2mqk0tdO8wi+oC7Fds96O7ddxxDoHSWyE3v\nYTBX3JbvcHSzsO4exsEDRYcpiZy91eCdDV1Tb8vwFHmz+AkkTQxSHaqGycoTfJQL\n+FNbsDRCfRIwRl7LTiG8lZ4+efn2S/nYM9VdmlmqXohJ6HCfeFl2EeOmygdsTjwI\n3QIDAQAB\n-----END PUBLIC KEY-----\n
|
||||||
|
|
||||||
|
[cors]
|
||||||
|
origins = https://www.cybersecshield.com,https://cybersecshield.com,http://localhost:5173
|
||||||
|
headers = accept, authorization, content-type, origin, referer
|
||||||
|
credentials = true
|
||||||
|
methods = GET, PUT, POST, HEAD, DELETE
|
||||||
9
server/etc/pubkey.pem
Normal file
9
server/etc/pubkey.pem
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+a7KpvY3xN/lb0pMDLY
|
||||||
|
PoVORggJf6ZxyXJlL7QyLt8vNIHsh5K5Zea4ehGHkUcn9Cnp4LVqFiz1aYCMWnzU
|
||||||
|
c/Nn/2ERsrdessxK1rvNWV09NCOe3mxT9nGv8zbEyMcfY/cbbfWyL4bbRzO8Nagi
|
||||||
|
2fJazytwTbARzKJcz78jGDGiHyR9z2mqk0tdO8wi+oC7Fds96O7ddxxDoHSWyE3v
|
||||||
|
YTBX3JbvcHSzsO4exsEDRYcpiZy91eCdDV1Tb8vwFHmz+AkkTQxSHaqGycoTfJQL
|
||||||
|
+FNbsDRCfRIwRl7LTiG8lZ4+efn2S/nYM9VdmlmqXohJ6HCfeFl2EeOmygdsTjwI
|
||||||
|
3QIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
101
server/etc/vm.args
Normal file
101
server/etc/vm.args
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
|
# Each node in the system must have a unique name. These are specified through
|
||||||
|
# the Erlang -name flag, which takes the form:
|
||||||
|
#
|
||||||
|
# -name nodename@<FQDN>
|
||||||
|
#
|
||||||
|
# or
|
||||||
|
#
|
||||||
|
# -name nodename@<IP-ADDRESS>
|
||||||
|
#
|
||||||
|
# CouchDB recommends the following values for this flag:
|
||||||
|
#
|
||||||
|
# 1. If this is a single node, not in a cluster, use:
|
||||||
|
# -name couchdb@127.0.0.1
|
||||||
|
#
|
||||||
|
# 2. If DNS is configured for this host, use the FQDN, such as:
|
||||||
|
# -name couchdb@my.host.domain.com
|
||||||
|
#
|
||||||
|
# 3. If DNS isn't configured for this host, use IP addresses only, such as:
|
||||||
|
# -name couchdb@192.168.0.1
|
||||||
|
#
|
||||||
|
# Do not rely on tricks with /etc/hosts or libresolv to handle anything
|
||||||
|
# other than the above 3 approaches correctly. They will not work reliably.
|
||||||
|
#
|
||||||
|
# Multiple CouchDBs running on the same machine can use couchdb1@, couchdb2@,
|
||||||
|
# etc.
|
||||||
|
-name couchdb@127.0.0.1
|
||||||
|
|
||||||
|
# All nodes must share the same magic cookie for distributed Erlang to work.
|
||||||
|
# Uncomment the following line and append a securely generated random value.
|
||||||
|
-setcookie eh.RauybPRHzP4-pXv
|
||||||
|
|
||||||
|
# Which interfaces should the node listen on?
|
||||||
|
-kernel inet_dist_use_interface {127,0,0,1}
|
||||||
|
|
||||||
|
# Tell kernel and SASL not to log anything
|
||||||
|
-kernel error_logger silent
|
||||||
|
-sasl sasl_error_logger false
|
||||||
|
|
||||||
|
# This will toggle to true in Erlang 25+. However since we don't use global
|
||||||
|
# any longer, and have our own auto-connection module, we can keep the
|
||||||
|
# existing global behavior to avoid surprises. See
|
||||||
|
# https://github.com/erlang/otp/issues/6470#issuecomment-1337421210 for more
|
||||||
|
# information about possible increased coordination and messages being sent on
|
||||||
|
# disconnections when this setting is enabled.
|
||||||
|
#
|
||||||
|
-kernel prevent_overlapping_partitions false
|
||||||
|
|
||||||
|
# Increase the pool of dirty IO schedulers from 10 to 16
|
||||||
|
# Dirty IO schedulers are used for file IO.
|
||||||
|
+SDio 16
|
||||||
|
|
||||||
|
# Comment this line out to enable the interactive Erlang shell on startup
|
||||||
|
+Bd -noinput
|
||||||
|
|
||||||
|
# Set maximum SSL session lifetime to reap terminated replication readers
|
||||||
|
-ssl session_lifetime 300
|
||||||
|
|
||||||
|
## TLS Distribution
|
||||||
|
## Use TLS for connections between Erlang cluster members.
|
||||||
|
## http://erlang.org/doc/apps/ssl/ssl_distribution.html
|
||||||
|
##
|
||||||
|
## Generate Cert(PEM) File
|
||||||
|
## This is just an example command to generate a certfile (PEM).
|
||||||
|
## This is not an endorsement of specific expiration limits, key sizes, or algorithms.
|
||||||
|
## $ openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
|
||||||
|
## $ cat key.pem cert.pem > dev/erlserver.pem && rm key.pem cert.pem
|
||||||
|
##
|
||||||
|
## Generate a Config File (couch_ssl_dist.conf)
|
||||||
|
## [{server,
|
||||||
|
## [{certfile, "</path/to/erlserver.pem>"},
|
||||||
|
## {secure_renegotiate, true}]},
|
||||||
|
## {client,
|
||||||
|
## [{secure_renegotiate, true}]}].
|
||||||
|
##
|
||||||
|
## CouchDB recommends the following values for no_tls flag:
|
||||||
|
## 1. Use TCP only, set to true, such as:
|
||||||
|
## -couch_dist no_tls true
|
||||||
|
## 2. Use TLS only, set to false, such as:
|
||||||
|
## -couch_dist no_tls false
|
||||||
|
## 3. Specify which node to use TCP, such as:
|
||||||
|
## -couch_dist no_tls \"*@127.0.0.1\"
|
||||||
|
##
|
||||||
|
## To ensure search works, make sure to set 'no_tls' option for the clouseau node.
|
||||||
|
## By default that would be "clouseau@127.0.0.1".
|
||||||
|
## Don't forget to override the paths to point to your certificate(s) and key(s)!
|
||||||
|
##
|
||||||
|
#-proto_dist couch
|
||||||
|
#-couch_dist no_tls '"clouseau@127.0.0.1"'
|
||||||
|
#-ssl_dist_optfile <path/to/couch_ssl_dist.conf>
|
||||||
@ -5,6 +5,7 @@ import {Handle} from "../objects/handle";
|
|||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
import {Button} from "../objects/Button";
|
import {Button} from "../objects/Button";
|
||||||
import {LightmapGenerator} from "../util/lightmapGenerator";
|
import {LightmapGenerator} from "../util/lightmapGenerator";
|
||||||
|
import {RenderingMode, RenderingModeLabels} from "../util/renderingMode";
|
||||||
|
|
||||||
const colors: string[] = [
|
const colors: string[] = [
|
||||||
"#222222", "#8b4513", "#006400", "#778899",
|
"#222222", "#8b4513", "#006400", "#778899",
|
||||||
@ -21,6 +22,7 @@ export class Toolbox {
|
|||||||
private readonly _handle: Handle;
|
private readonly _handle: Handle;
|
||||||
private readonly _scene: Scene;
|
private readonly _scene: Scene;
|
||||||
private _xr?: WebXRDefaultExperience;
|
private _xr?: WebXRDefaultExperience;
|
||||||
|
private _renderModeDisplay?: Button;
|
||||||
|
|
||||||
constructor(readyObservable: Observable<boolean>) {
|
constructor(readyObservable: Observable<boolean>) {
|
||||||
this._scene = DefaultScene.Scene;
|
this._scene = DefaultScene.Scene;
|
||||||
@ -149,24 +151,126 @@ export class Toolbox {
|
|||||||
|
|
||||||
this._xr.baseExperience.onStateChangedObservable.add((state) => {
|
this._xr.baseExperience.onStateChangedObservable.add((state) => {
|
||||||
if (state == 2) { // WebXRState.IN_XR
|
if (state == 2) { // WebXRState.IN_XR
|
||||||
const button = Button.CreateButton("exitXr", "exitXr", this._scene, {});
|
// Create exit XR button
|
||||||
|
const exitButton = Button.CreateButton("exitXr", "exitXr", this._scene, {});
|
||||||
|
|
||||||
// Position button at bottom-right of toolbox, matching handle size and orientation
|
// Position button at bottom-right of toolbox, matching handle size and orientation
|
||||||
button.transform.position.x = 0.5; // Right side
|
exitButton.transform.position.x = 0.5; // Right side
|
||||||
button.transform.position.y = -0.35; // Below color grid
|
exitButton.transform.position.y = -0.35; // Below color grid
|
||||||
button.transform.position.z = 0; // Coplanar with toolbox
|
exitButton.transform.position.z = 0; // Coplanar with toolbox
|
||||||
button.transform.rotation.y = Math.PI; // Flip 180° on local x-axis to face correctly
|
exitButton.transform.rotation.y = Math.PI; // Flip 180° on local x-axis to face correctly
|
||||||
button.transform.scaling = new Vector3(.2, .2, .2); // Match handle height
|
exitButton.transform.scaling = new Vector3(.2, .2, .2); // Match handle height
|
||||||
button.transform.parent = this._toolboxBaseNode;
|
exitButton.transform.parent = this._toolboxBaseNode;
|
||||||
|
|
||||||
button.onPointerObservable.add((evt) => {
|
exitButton.onPointerObservable.add((evt) => {
|
||||||
this._logger.debug(evt);
|
this._logger.debug(evt);
|
||||||
if (evt.sourceEvent.type == 'pointerdown') {
|
if (evt.sourceEvent.type == 'pointerdown') {
|
||||||
this._xr.baseExperience.exitXRAsync();
|
this._xr.baseExperience.exitXRAsync();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create rendering mode button that cycles through modes
|
||||||
|
this.createRenderModeButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createRenderModeButton() {
|
||||||
|
const modes = [
|
||||||
|
RenderingMode.LIGHTMAP_WITH_LIGHTING,
|
||||||
|
RenderingMode.UNLIT_WITH_EMISSIVE_TEXTURE,
|
||||||
|
RenderingMode.FLAT_EMISSIVE,
|
||||||
|
RenderingMode.DIFFUSE_WITH_LIGHTS
|
||||||
|
];
|
||||||
|
|
||||||
|
const currentMode = LightmapGenerator.getRenderingMode();
|
||||||
|
|
||||||
|
this._renderModeDisplay = Button.CreateButton(
|
||||||
|
`Mode: ${RenderingModeLabels[currentMode]}`,
|
||||||
|
`renderModeButton`,
|
||||||
|
this._scene,
|
||||||
|
{
|
||||||
|
width: 0.5,
|
||||||
|
height: 0.2,
|
||||||
|
background: Color3.FromHexString("#333333"),
|
||||||
|
color: Color3.White(),
|
||||||
|
fontSize: 240
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Position below the color grid
|
||||||
|
this._renderModeDisplay.transform.position.x = 0;
|
||||||
|
this._renderModeDisplay.transform.position.y = -.2;
|
||||||
|
this._renderModeDisplay.transform.position.z = 0;
|
||||||
|
this._renderModeDisplay.transform.rotation.y = Math.PI;
|
||||||
|
this._renderModeDisplay.transform.scaling = new Vector3(.4, .4, .4);
|
||||||
|
this._renderModeDisplay.transform.parent = this._toolboxBaseNode;
|
||||||
|
|
||||||
|
// Add click handler to cycle through modes
|
||||||
|
this._renderModeDisplay.onPointerObservable.add((evt) => {
|
||||||
|
if (evt.sourceEvent.type == 'pointerdown') {
|
||||||
|
const currentMode = LightmapGenerator.getRenderingMode();
|
||||||
|
const currentIndex = modes.indexOf(currentMode);
|
||||||
|
const nextIndex = (currentIndex + 1) % modes.length;
|
||||||
|
const nextMode = modes[nextIndex];
|
||||||
|
|
||||||
|
this._logger.info(`Cycling to rendering mode: ${nextMode}`);
|
||||||
|
LightmapGenerator.updateAllMaterials(this._scene, nextMode);
|
||||||
|
|
||||||
|
// Update button text
|
||||||
|
this.updateRenderModeButton(nextMode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateRenderModeButton(mode: RenderingMode) {
|
||||||
|
if (this._renderModeDisplay) {
|
||||||
|
// Dispose old button and create new one with updated text
|
||||||
|
this._renderModeDisplay.dispose();
|
||||||
|
|
||||||
|
this._renderModeDisplay = Button.CreateButton(
|
||||||
|
`Mode: ${RenderingModeLabels[mode]}`,
|
||||||
|
`renderModeButton`,
|
||||||
|
this._scene,
|
||||||
|
{
|
||||||
|
width: 0.5,
|
||||||
|
height: 0.2,
|
||||||
|
background: Color3.FromHexString("#333333"),
|
||||||
|
color: Color3.White(),
|
||||||
|
fontSize: 240
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this._renderModeDisplay.transform.position.x = 0;
|
||||||
|
this._renderModeDisplay.transform.position.y = -.2;
|
||||||
|
this._renderModeDisplay.transform.position.z = 0;
|
||||||
|
this._renderModeDisplay.transform.rotation.y = Math.PI;
|
||||||
|
this._renderModeDisplay.transform.scaling = new Vector3(.15, .15, .15);
|
||||||
|
this._renderModeDisplay.transform.parent = this._toolboxBaseNode;
|
||||||
|
|
||||||
|
// Re-attach the click handler
|
||||||
|
this._renderModeDisplay.onPointerObservable.add((evt) => {
|
||||||
|
if (evt.sourceEvent.type == 'pointerdown') {
|
||||||
|
const modes = [
|
||||||
|
RenderingMode.LIGHTMAP_WITH_LIGHTING,
|
||||||
|
RenderingMode.UNLIT_WITH_EMISSIVE_TEXTURE,
|
||||||
|
RenderingMode.FLAT_EMISSIVE,
|
||||||
|
RenderingMode.DIFFUSE_WITH_LIGHTS
|
||||||
|
];
|
||||||
|
|
||||||
|
const currentMode = LightmapGenerator.getRenderingMode();
|
||||||
|
const currentIndex = modes.indexOf(currentMode);
|
||||||
|
const nextIndex = (currentIndex + 1) % modes.length;
|
||||||
|
const nextMode = modes[nextIndex];
|
||||||
|
|
||||||
|
this._logger.info(`Cycling to rendering mode: ${nextMode}`);
|
||||||
|
LightmapGenerator.updateAllMaterials(this._scene, nextMode);
|
||||||
|
|
||||||
|
// Update button text
|
||||||
|
this.updateRenderModeButton(nextMode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,17 +2,13 @@ import {DefaultScene} from "../../defaultScene";
|
|||||||
|
|
||||||
export function addSceneInspector() {
|
export function addSceneInspector() {
|
||||||
window.addEventListener("keydown", (ev) => {
|
window.addEventListener("keydown", (ev) => {
|
||||||
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
// Ctrl+Shift+I to open inspector
|
||||||
const web = document.querySelector('#webApp');
|
if (ev.shiftKey && ev.ctrlKey && !ev.altKey && ev.keyCode === 73) {
|
||||||
(web as HTMLDivElement).style.display = 'none';
|
|
||||||
|
|
||||||
import ("@babylonjs/inspector").then((inspector) => {
|
import ("@babylonjs/inspector").then((inspector) => {
|
||||||
inspector.Inspector.Show(DefaultScene.Scene, {
|
inspector.Inspector.Show(DefaultScene.Scene, {
|
||||||
overlay: true,
|
overlay: true,
|
||||||
showExplorer: true
|
showExplorer: true
|
||||||
});
|
});
|
||||||
const web = document.querySelector('#webApp');
|
|
||||||
(web as HTMLDivElement).style.display = 'none';
|
|
||||||
});
|
});
|
||||||
/*import("@babylonjs/core/Debug").then(() => {
|
/*import("@babylonjs/core/Debug").then(() => {
|
||||||
import("@babylonjs/inspector").then(() => {
|
import("@babylonjs/inspector").then(() => {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import {Color3, DynamicTexture, Scene} from "@babylonjs/core";
|
import {Color3, DynamicTexture, HemisphericLight, PointLight, Scene, StandardMaterial, Vector3} from "@babylonjs/core";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
|
import {RenderingMode} from "./renderingMode";
|
||||||
|
|
||||||
export class LightmapGenerator {
|
export class LightmapGenerator {
|
||||||
private static lightmapCache: Map<string, DynamicTexture> = new Map();
|
private static lightmapCache: Map<string, DynamicTexture> = new Map();
|
||||||
@ -8,6 +9,13 @@ export class LightmapGenerator {
|
|||||||
// Toggle to enable/disable lightmap usage (for performance testing)
|
// Toggle to enable/disable lightmap usage (for performance testing)
|
||||||
public static ENABLED = true;
|
public static ENABLED = true;
|
||||||
|
|
||||||
|
// Current rendering mode
|
||||||
|
private static currentMode: RenderingMode = RenderingMode.UNLIT_WITH_EMISSIVE_TEXTURE;
|
||||||
|
|
||||||
|
// Scene lights for DIFFUSE_WITH_LIGHTS mode
|
||||||
|
private static hemisphericLight?: HemisphericLight;
|
||||||
|
private static pointLight?: PointLight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates or retrieves cached lightmap for a given color
|
* Generates or retrieves cached lightmap for a given color
|
||||||
* @param color The base color for the lightmap
|
* @param color The base color for the lightmap
|
||||||
@ -125,4 +133,145 @@ export class LightmapGenerator {
|
|||||||
public static getCacheSize(): number {
|
public static getCacheSize(): number {
|
||||||
return this.lightmapCache.size;
|
return this.lightmapCache.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rendering mode
|
||||||
|
* @param mode The rendering mode to use
|
||||||
|
*/
|
||||||
|
public static setRenderingMode(mode: RenderingMode): void {
|
||||||
|
this.currentMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current rendering mode
|
||||||
|
* @returns Current rendering mode
|
||||||
|
*/
|
||||||
|
public static getRenderingMode(): RenderingMode {
|
||||||
|
return this.currentMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the specified rendering mode to a material
|
||||||
|
* @param material The material to update
|
||||||
|
* @param color The base color
|
||||||
|
* @param mode The rendering mode to apply
|
||||||
|
* @param scene The BabylonJS scene
|
||||||
|
*/
|
||||||
|
public static applyRenderingModeToMaterial(
|
||||||
|
material: StandardMaterial,
|
||||||
|
color: Color3,
|
||||||
|
mode: RenderingMode,
|
||||||
|
scene: Scene
|
||||||
|
): void {
|
||||||
|
// Clear existing textures and properties
|
||||||
|
material.diffuseColor = new Color3(0, 0, 0);
|
||||||
|
material.emissiveColor = new Color3(0, 0, 0);
|
||||||
|
material.diffuseTexture = null;
|
||||||
|
material.emissiveTexture = null;
|
||||||
|
material.lightmapTexture = null;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case RenderingMode.LIGHTMAP_WITH_LIGHTING:
|
||||||
|
// Use diffuseColor + lightmapTexture with lighting enabled
|
||||||
|
material.diffuseColor = color;
|
||||||
|
material.lightmapTexture = this.generateLightmapForColor(color, scene);
|
||||||
|
material.useLightmapAsShadowmap = false;
|
||||||
|
material.disableLighting = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderingMode.UNLIT_WITH_EMISSIVE_TEXTURE:
|
||||||
|
// Use emissiveColor + emissiveTexture with lighting disabled
|
||||||
|
material.emissiveColor = color;
|
||||||
|
material.emissiveTexture = this.generateLightmapForColor(color, scene);
|
||||||
|
material.disableLighting = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderingMode.FLAT_EMISSIVE:
|
||||||
|
// Use only emissiveColor with lighting disabled
|
||||||
|
material.emissiveColor = color;
|
||||||
|
material.disableLighting = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderingMode.DIFFUSE_WITH_LIGHTS:
|
||||||
|
// Use diffuseColor with dynamic lighting enabled
|
||||||
|
material.diffuseColor = color;
|
||||||
|
material.disableLighting = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates or enables scene lights for DIFFUSE_WITH_LIGHTS mode
|
||||||
|
* @param scene The BabylonJS scene
|
||||||
|
*/
|
||||||
|
private static createSceneLights(scene: Scene): void {
|
||||||
|
if (!this.hemisphericLight) {
|
||||||
|
this.hemisphericLight = new HemisphericLight("renderModeHemiLight", new Vector3(0, 1, 0), scene);
|
||||||
|
this.hemisphericLight.intensity = 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.pointLight) {
|
||||||
|
this.pointLight = new PointLight("renderModePointLight", new Vector3(2, 3, 2), scene);
|
||||||
|
this.pointLight.intensity = 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hemisphericLight.setEnabled(true);
|
||||||
|
this.pointLight.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables scene lights used for DIFFUSE_WITH_LIGHTS mode
|
||||||
|
*/
|
||||||
|
private static disableSceneLights(): void {
|
||||||
|
if (this.hemisphericLight) {
|
||||||
|
this.hemisphericLight.setEnabled(false);
|
||||||
|
}
|
||||||
|
if (this.pointLight) {
|
||||||
|
this.pointLight.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all materials in the scene to use the specified rendering mode
|
||||||
|
* @param scene The BabylonJS scene
|
||||||
|
* @param mode The rendering mode to apply
|
||||||
|
*/
|
||||||
|
public static updateAllMaterials(scene: Scene, mode: RenderingMode): void {
|
||||||
|
this.currentMode = mode;
|
||||||
|
|
||||||
|
// Enable or disable scene lights based on mode
|
||||||
|
if (mode === RenderingMode.DIFFUSE_WITH_LIGHTS) {
|
||||||
|
this.createSceneLights(scene);
|
||||||
|
} else {
|
||||||
|
this.disableSceneLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.materials.forEach(material => {
|
||||||
|
if (material instanceof StandardMaterial) {
|
||||||
|
// Skip UI materials (buttons, handles, and labels use emissiveTexture with text rendering)
|
||||||
|
if (material.name === 'buttonMat' ||
|
||||||
|
material.name === 'handleMaterial' ||
|
||||||
|
material.name === 'text-mat' ||
|
||||||
|
material.id.includes('button') ||
|
||||||
|
material.id.includes('handle') ||
|
||||||
|
material.id.includes('text')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to determine the base color from existing material
|
||||||
|
let baseColor: Color3;
|
||||||
|
|
||||||
|
if (material.emissiveColor && material.emissiveColor.toLuminance() > 0) {
|
||||||
|
baseColor = material.emissiveColor.clone();
|
||||||
|
} else if (material.diffuseColor && material.diffuseColor.toLuminance() > 0) {
|
||||||
|
baseColor = material.diffuseColor.clone();
|
||||||
|
} else {
|
||||||
|
// Skip materials without a color set
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.applyRenderingModeToMaterial(material, baseColor, mode, scene);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/util/renderingMode.ts
Normal file
36
src/util/renderingMode.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Rendering modes for materials in the scene
|
||||||
|
*
|
||||||
|
* LIGHTMAP_WITH_LIGHTING: Uses diffuseColor + lightmapTexture with lighting enabled
|
||||||
|
* - Provides lighting illusion with actual lighting calculations
|
||||||
|
* - Most expensive performance-wise
|
||||||
|
* - disableLighting = false
|
||||||
|
*
|
||||||
|
* UNLIT_WITH_EMISSIVE_TEXTURE: Uses emissiveColor + emissiveTexture with lighting disabled
|
||||||
|
* - Provides lighting illusion without lighting calculations (current default)
|
||||||
|
* - Best balance of visual quality and performance
|
||||||
|
* - disableLighting = true
|
||||||
|
*
|
||||||
|
* FLAT_EMISSIVE: Uses only emissiveColor with lighting disabled
|
||||||
|
* - Flat shading, no lighting illusion
|
||||||
|
* - Best performance
|
||||||
|
* - disableLighting = true
|
||||||
|
*
|
||||||
|
* DIFFUSE_WITH_LIGHTS: Uses diffuseColor with two scene lights enabled
|
||||||
|
* - Real-time lighting calculations with dynamic lights
|
||||||
|
* - Provides realistic lighting and shadows
|
||||||
|
* - disableLighting = false
|
||||||
|
*/
|
||||||
|
export enum RenderingMode {
|
||||||
|
LIGHTMAP_WITH_LIGHTING = "lightmap_with_lighting",
|
||||||
|
UNLIT_WITH_EMISSIVE_TEXTURE = "unlit_with_emissive_texture",
|
||||||
|
FLAT_EMISSIVE = "flat_emissive",
|
||||||
|
DIFFUSE_WITH_LIGHTS = "diffuse_with_lights"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RenderingModeLabels = {
|
||||||
|
[RenderingMode.LIGHTMAP_WITH_LIGHTING]: "Lightmap + Lighting",
|
||||||
|
[RenderingMode.UNLIT_WITH_EMISSIVE_TEXTURE]: "Emissive Texture",
|
||||||
|
[RenderingMode.FLAT_EMISSIVE]: "Flat Color",
|
||||||
|
[RenderingMode.DIFFUSE_WITH_LIGHTS]: "Diffuse + Lights"
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user