Browse Source

Merge pull request #116 from Tresjs/feature/100-vector-set-props

Enable vector set props
Alvaro Saburido 2 years ago
parent
commit
cee801961b

+ 22 - 0
docs/api/instances-arguments-and-props.md

@@ -89,6 +89,28 @@ All properties whose underlying object has a `.set()` method have a shortcut to
 <TresPerspectiveCamera :position="[1, 2, 3]" />
 ```
 
+To specify transformation properties such as position, rotation, and scale, a shorthand is available that allows you to directly indicate the axis you wish to set within the props. A similar shorthand is also available for color property.
+
+<!-- I changed color syntax from vue to html, because vue seems broken and does not color nested components -->
+```html
+<TresMesh :position-x="1" :scale-y="2" :rotation-x="Math.PI * 2">
+  <TresMeshBasicMaterial :color-r="0.7" :color-b="0.3" />
+</TresMesh>
+```
+
+::: warning
+When you set the rotation property in [three.js](https://threejs.org/docs/index.html#api/en/math/Euler), it will use the 'XYZ' order by default.
+It is important to note that when setting the rotation property with the shorthand, the order in which you set the angles matters. For more information on this topic, please refer to  [Euler angles](https://en.wikipedia.org/wiki/Euler_angles)
+:::
+
+```vue
+<TresMesh :rotation-x="1" :rotation-y="2" :rotation-z="Math.PI * 2" />
+
+<TresMesh :rotation-z="Math.PI * 2" :rotation-x="1" :rotation-y="2" />
+
+<!-- Note that the order of the rotation properties matters, and swapping the order can result in different outcomes. -->
+```
+
 ### Scalar
 
 Another shortcut you can use is pass a scalar value to a property that expects a `Vector3` object, using the same value for the rest of the Vector:

+ 5 - 2
packages/tres/src/App.vue

@@ -1,12 +1,15 @@
 <script setup lang="ts">
 import { useTweakPane } from '@tresjs/cientos'
-import TheEnvironment from '/@/components/TheEnvironment.vue'
+// import TheEnvironment from '/@/components/TheEnvironment.vue'
+// import TheEvents from '/@/components/TheEvents.vue'
+import VectorSetProps from '/@/components/VectorSetProps.vue'
 
 useTweakPane()
 </script>
 
 <template>
   <Suspense>
-    <TheEnvironment />
+    <!-- <TheEnvironment /> -->
+    <VectorSetProps />
   </Suspense>
 </template>

+ 70 - 0
packages/tres/src/components/VectorSetProps.vue

@@ -0,0 +1,70 @@
+<script setup lang="ts">
+import { sRGBEncoding, BasicShadowMap, NoToneMapping } from 'three'
+import { reactive } from 'vue'
+
+import { OrbitControls } from '@tresjs/cientos'
+// import { useRenderLoop } from '..'
+/* import { OrbitControls, GLTFModel } from '@tresjs/cientos' */
+
+const state = reactive({
+  clearColor: '#201919',
+  shadows: true,
+  alpha: false,
+  physicallyCorrectLights: true,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+})
+</script>
+<template>
+  <TresCanvas v-bind="state">
+    <TresPerspectiveCamera
+      :position-x="5"
+      :position-y="5"
+      :position-z="5"
+      :fov="45"
+      :near="0.1"
+      :far="1000"
+      :look-at="[-8, 3, -3]"
+    />
+    <OrbitControls make-default />
+    <TresScene>
+      <TresAmbientLight :intensity="0.5" />
+
+      <TresMesh
+        :scale-x="1.1"
+        :scale-y="2"
+        :scale-z="3"
+        :rotation-x="Math.PI * 1.5"
+        :rotation-y="Math.PI * 0.6"
+        :rotation-z="Math.PI * 0.2"
+        :position-y="1"
+        :position-z="-2"
+        cast-shadow
+      >
+        <TresBoxGeometry />
+        <TresMeshToonMaterial color="#FBB03B" />
+      </TresMesh>
+      <TresMesh
+        :scale-x="1.1"
+        :scale-y="2"
+        :scale-z="3"
+        :rotation-y="Math.PI * 0.6"
+        :rotation-x="Math.PI * 1.5"
+        :rotation-z="Math.PI * 0.2"
+        :position-y="1"
+        :position-z="2"
+        cast-shadow
+      >
+        <TresBoxGeometry />
+        <TresMeshToonMaterial :color-r="0xff / 255" :color-g="0x0 / 255" :color-b="0xff / 255" />
+      </TresMesh>
+      <TresDirectionalLight :position-y="8" :position-z="4" :intensity="0.7" cast-shadow />
+      <TresMesh :rotation="[-Math.PI / 2, 0, 0]" receive-shadow>
+        <TresPlaneGeometry :args="[10, 10, 10, 10]" />
+        <TresMeshToonMaterial />
+      </TresMesh>
+      <TresDirectionalLight :position-y="2" :position-z="4" :intensity="1" cast-shadow />
+    </TresScene>
+  </TresCanvas>
+</template>

+ 53 - 1
packages/tres/src/core/useInstanceCreator/index.ts

@@ -11,6 +11,9 @@ import { useLogger } from '/@/composables'
 import { TresAttributes, TresCatalogue, TresInstance, TresVNode, TresVNodeType, TresEvent } from '/@/types'
 
 const VECTOR3_PROPS = ['rotation', 'scale', 'position']
+const VECTOR3_AXIS = ['X', 'Y', 'Z']
+const COLOR_PROPS = ['color']
+const COLOR_KEYS = ['r', 'g', 'b']
 
 export function useInstanceCreator(prefix: string) {
   const { /* logMessage, */ logError } = useLogger()
@@ -31,14 +34,43 @@ export function useInstanceCreator(prefix: string) {
 
     Object.entries(props).forEach(([key, value]) => {
       const camelKey = key.replace(/(-\w)/g, m => m[1].toUpperCase())
-
+      let transformProps
+      let transformAxis
+      let colorProps
+      let colorKey
       // Ignore property args which is use for initial instance construction
       if (camelKey === 'args' || value === undefined) return
 
       // Normalize vector3 props
       if (VECTOR3_PROPS.includes(camelKey) && value) {
         value = normalizeVectorFlexibleParam(value)
+      } else {
+        VECTOR3_PROPS.forEach(vecProps => {
+          // Check if the props starts with one of the transform props
+          // and is followed only with one of the axis
+          if (camelKey.startsWith(vecProps) && camelKey.length === vecProps.length + 1) {
+            transformProps = vecProps
+            transformAxis = camelKey.substring(vecProps.length)
+            if (!VECTOR3_AXIS.includes(transformAxis)) {
+              logError(
+                `There was an error setting ${key} property`,
+                `${transformAxis} is not a valid axis for ${transformProps}`,
+              )
+            }
+          }
+        })
       }
+      COLOR_PROPS.forEach(props => {
+        // Check if the props starts with one of the color props
+        // and is followed only with one of the key
+        if (camelKey.startsWith(props) && camelKey.length === props.length + 1) {
+          colorProps = props
+          colorKey = camelKey.substring(props.length).toLowerCase()
+          if (!COLOR_KEYS.includes(colorKey)) {
+            logError(`There was an error setting ${key} property`, `${colorKey} is not a valid axis for ${colorProps}`)
+          }
+        }
+      })
 
       if (props.ref) {
         props.ref = instance
@@ -49,6 +81,26 @@ export function useInstanceCreator(prefix: string) {
         if (instance[camelKey] && isDefined(instance[camelKey].set)) {
           // Call the "set" method with the value, spread if it's an array
           instance[camelKey].set(...(isArray(value) ? value : [value]))
+        } else if (
+          // Check if the property has a "setAxis" method
+          transformProps &&
+          instance[transformProps]
+        ) {
+          // Check if setAxis function exist
+          // if it doesn't check if props is rotation
+          if (isDefined(instance[transformProps][`set${transformAxis}`])) {
+            instance[transformProps][`set${transformAxis}`](value)
+          } else if (isDefined(instance[`rotate${transformAxis}`])) {
+            instance[`rotate${transformAxis}`](value)
+          }
+        } else if (
+          // Check if the instance has a "color" property
+          colorProps &&
+          colorKey &&
+          instance[colorProps] &&
+          instance[colorProps][colorKey]
+        ) {
+          instance[colorProps][colorKey] = value
         } else {
           // Convert empty strings to `true`
           if (value === '') {

+ 4 - 4
pnpm-lock.yaml

@@ -8,8 +8,8 @@ importers:
       '@changesets/changelog-github': ^0.4.7
       '@changesets/cli': ^2.25.2
       '@stackblitz/sdk': ^1.8.1
-      '@tresjs/cientos': workspace:^1.6.0
-      '@tresjs/core': workspace:^1.6.3
+      '@tresjs/cientos': workspace:^1.7.0
+      '@tresjs/core': workspace:^1.7.0
       '@typescript-eslint/eslint-plugin': ^5.42.0
       '@typescript-eslint/parser': ^5.42.0
       conventional-changelog-cli: ^2.2.2
@@ -47,7 +47,7 @@ importers:
 
   packages/cientos:
     specifiers:
-      '@tresjs/core': workspace:^1.6.3
+      '@tresjs/core': workspace:^1.7.0
       '@tweakpane/plugin-essentials': ^0.1.8
       '@vitejs/plugin-vue': ^4.0.0
       kolorist: ^1.7.0
@@ -79,7 +79,7 @@ importers:
   packages/tres:
     specifiers:
       '@alvarosabu/utils': ^2.3.0
-      '@tresjs/cientos': workspace:^1.6.0
+      '@tresjs/cientos': workspace:^1.7.0
       '@types/three': latest
       '@vitejs/plugin-vue': ^4.0.0
       '@vitest/coverage-c8': ^0.28.4