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
|
||||
|
||||
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 {Button} from "../objects/Button";
|
||||
import {LightmapGenerator} from "../util/lightmapGenerator";
|
||||
import {RenderingMode, RenderingModeLabels} from "../util/renderingMode";
|
||||
|
||||
const colors: string[] = [
|
||||
"#222222", "#8b4513", "#006400", "#778899",
|
||||
@ -21,6 +22,7 @@ export class Toolbox {
|
||||
private readonly _handle: Handle;
|
||||
private readonly _scene: Scene;
|
||||
private _xr?: WebXRDefaultExperience;
|
||||
private _renderModeDisplay?: Button;
|
||||
|
||||
constructor(readyObservable: Observable<boolean>) {
|
||||
this._scene = DefaultScene.Scene;
|
||||
@ -149,24 +151,126 @@ export class Toolbox {
|
||||
|
||||
this._xr.baseExperience.onStateChangedObservable.add((state) => {
|
||||
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
|
||||
button.transform.position.x = 0.5; // Right side
|
||||
button.transform.position.y = -0.35; // Below color grid
|
||||
button.transform.position.z = 0; // Coplanar with toolbox
|
||||
button.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
|
||||
button.transform.parent = this._toolboxBaseNode;
|
||||
exitButton.transform.position.x = 0.5; // Right side
|
||||
exitButton.transform.position.y = -0.35; // Below color grid
|
||||
exitButton.transform.position.z = 0; // Coplanar with toolbox
|
||||
exitButton.transform.rotation.y = Math.PI; // Flip 180° on local x-axis to face correctly
|
||||
exitButton.transform.scaling = new Vector3(.2, .2, .2); // Match handle height
|
||||
exitButton.transform.parent = this._toolboxBaseNode;
|
||||
|
||||
button.onPointerObservable.add((evt) => {
|
||||
exitButton.onPointerObservable.add((evt) => {
|
||||
this._logger.debug(evt);
|
||||
if (evt.sourceEvent.type == 'pointerdown') {
|
||||
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() {
|
||||
window.addEventListener("keydown", (ev) => {
|
||||
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
||||
const web = document.querySelector('#webApp');
|
||||
(web as HTMLDivElement).style.display = 'none';
|
||||
|
||||
// Ctrl+Shift+I to open inspector
|
||||
if (ev.shiftKey && ev.ctrlKey && !ev.altKey && ev.keyCode === 73) {
|
||||
import ("@babylonjs/inspector").then((inspector) => {
|
||||
inspector.Inspector.Show(DefaultScene.Scene, {
|
||||
overlay: true,
|
||||
showExplorer: true
|
||||
});
|
||||
const web = document.querySelector('#webApp');
|
||||
(web as HTMLDivElement).style.display = 'none';
|
||||
});
|
||||
/*import("@babylonjs/core/Debug").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 {RenderingMode} from "./renderingMode";
|
||||
|
||||
export class LightmapGenerator {
|
||||
private static lightmapCache: Map<string, DynamicTexture> = new Map();
|
||||
@ -8,6 +9,13 @@ export class LightmapGenerator {
|
||||
// Toggle to enable/disable lightmap usage (for performance testing)
|
||||
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
|
||||
* @param color The base color for the lightmap
|
||||
@ -125,4 +133,145 @@ export class LightmapGenerator {
|
||||
public static getCacheSize(): number {
|
||||
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