增加 顶点捕捉材质

This commit is contained in:
hawk86104 2024-10-10 10:11:13 +08:00
parent 2dcc861ccb
commit fad03b0cef
6 changed files with 229 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@ -0,0 +1,75 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-10-10 08:29:17
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-10-10 09:49:12
-->
<template>
<primitive :object="srcMaterial" />
</template>
<script setup lang="ts">
import * as THREE from 'three'
import { toRef, watch } from 'vue'
const props = withDefaults(
defineProps<{
uSnappingResolution?: number
srcMaterial?: THREE.Material
}>(),
{
uSnappingResolution: 6,
srcMaterial: () => {
return new THREE.MeshStandardMaterial({
color: 0x00ff00,
roughness: 0.5,
metalness: 0.5,
})
},
},
)
const snappingResolutionRef = toRef(props.uSnappingResolution)
props.srcMaterial.onBeforeCompile = (material) => {
material.uniforms.uSnappingResolution = snappingResolutionRef
material.vertexShader = material.vertexShader.replace(
'#include <common>',
`
#include <common>
uniform float uSnappingResolution;
`,
)
material.vertexShader = material.vertexShader.replace(
'#include <project_vertex>',
`
vec4 mvPosition = vec4( transformed, 1.0 );
#ifdef USE_BATCHING
mvPosition = batchingMatrix * mvPosition;
#endif
#ifdef USE_INSTANCING
mvPosition = instanceMatrix * mvPosition;
#endif
mvPosition = modelMatrix * mvPosition;
mvPosition = vec4(
round(mvPosition.x * uSnappingResolution) / uSnappingResolution,
round(mvPosition.y * uSnappingResolution) / uSnappingResolution,
round(mvPosition.z * uSnappingResolution) / uSnappingResolution,
1.0);
mvPosition = viewMatrix * mvPosition;
gl_Position = projectionMatrix * mvPosition;
`,
)
}
watch(
() => props.uSnappingResolution,
(newValue) => {
snappingResolutionRef.value = newValue
},
)
</script>

View File

@ -0,0 +1,40 @@
import * as THREE from 'three'
export function transToVertexSnappingMaterial(curMaterial: THREE.Material, snappingResolution: number = 6) {
const uSnappingResolution = { value: snappingResolution }
curMaterial.onBeforeCompile = (material) => {
material.uniforms.uSnappingResolution = uSnappingResolution
material.vertexShader = material.vertexShader.replace(
'#include <common>',
`
#include <common>
uniform float uSnappingResolution;
`,
)
material.vertexShader = material.vertexShader.replace(
'#include <project_vertex>',
`
vec4 mvPosition = vec4( transformed, 1.0 );
#ifdef USE_BATCHING
mvPosition = batchingMatrix * mvPosition;
#endif
#ifdef USE_INSTANCING
mvPosition = instanceMatrix * mvPosition;
#endif
mvPosition = modelMatrix * mvPosition;
mvPosition = vec4(
round(mvPosition.x * uSnappingResolution) / uSnappingResolution,
round(mvPosition.y * uSnappingResolution) / uSnappingResolution,
round(mvPosition.z * uSnappingResolution) / uSnappingResolution,
1.0);
mvPosition = viewMatrix * mvPosition;
gl_Position = projectionMatrix * mvPosition;
`,
)
}
return uSnappingResolution
}

View File

@ -0,0 +1,45 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-10-10 09:25:11
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-10-10 09:54:40
-->
<template>
<primitive :object="scene" :scale="5" :position="[0, -2, 0]" />
</template>
<script setup lang="ts">
import { useGLTF } from '@tresjs/cientos'
import { transToVertexSnappingMaterial } from './index'
import { watch } from 'vue'
const props = withDefaults(
defineProps<{
uSnappingResolution?: number
}>(),
{
uSnappingResolution: 6,
},
)
const { scene, materials } = await useGLTF('https://opensource-1314935952.cos.ap-nanjing.myqcloud.com/model/industry4/MRBike.glb', {
draco: true,
decoderPath: './draco/',
})
const resolutionList = [] as any
Object.values(materials).forEach((material: any) => {
resolutionList.push(transToVertexSnappingMaterial(material, props.uSnappingResolution))
})
watch(
() => props.uSnappingResolution,
(newValue) => {
resolutionList.forEach((item: any) => {
item.value = newValue
})
},
)
</script>

View File

@ -4,7 +4,7 @@
* @Autor: 地虎降天龙
* @Date: 2023-11-03 15:07:09
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-06-05 16:36:20
* @LastEditTime: 2024-10-10 08:28:26
*/
export default {
name: 'basic',
@ -50,6 +50,7 @@ export default {
name: 'instancedMeshCustomShaderMaterial',
title: 'instanced和继承材质',
},
{ src: 'plugins/basic/materials/preview/vertexSnapping.png', type: 'img', name: 'vertexSnapping', title: '顶点捕捉材质' },
],
},
{

View File

@ -0,0 +1,67 @@
<template>
<TresCanvas v-bind="state" window-size>
<TresPerspectiveCamera :position="[8, 6, 8]" :fov="45" :near="1" :far="1000" />
<OrbitControls />
<TresAmbientLight :intensity="0.5" />
<TresDirectionalLight :position="[7, 10, -5.5]" :intensity="5" />
<TresMesh :position="[-5, 0.5, 5]" receive-shadow cast-shadow name="cube">
<TresCylinderGeometry :args="[1.5, 1.5, 2]" />
<TresMeshStandardMaterial :color="0xff6622" :roughness="0" :metalness="0" />
</TresMesh>
<TresMesh :position="[5, 0.9, -5]" name="torus">
<TresTorusKnotGeometry :args="[1, 0.35, 100, 32]" />
<vertexSnappingMaterial :uSnappingResolution="vertexSnappingState.uSnappingResolution" />
</TresMesh>
<Suspense>
<model :uSnappingResolution="vertexSnappingState.modelSnappingResolution" />
</Suspense>
<Suspense>
<Environment :resolution="256" :blur="1" background>
<Lightformer :intensity="2" form="circle" :rotation-x="Math.PI / 2" :position="[2 * 4 - (3 * 4) / 2, 4, 0]" :scale="[1, 5, 0]" />
<Lightformer :intensity="2" form="circle" :rotation-x="Math.PI / 2" :position="[-(3 * 4) / 2, 4, 0]" :scale="[1, 5, 0]" />
<Lightformer :intensity="1" :rotation-y="-Math.PI / 2" :position="[-1, 0, 0]" :scale="[10, 0.2, 1]" />
<Lightformer :intensity="1" :rotation-y="-Math.PI / 2" :position="[1, 0, 0]" :scale="[10, 0.2, 1]" />
</Environment>
</Suspense>
</TresCanvas>
</template>
<script setup lang="ts">
import { ACESFilmicToneMapping } from 'three'
import { reactive } from 'vue'
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { Environment, Lightformer } from 'PLS/basic'
import { Pane } from 'tweakpane'
import vertexSnappingMaterial from '../../components/vertexSnappingMaterial/com.vue'
import model from '../../components/vertexSnappingMaterial/model.vue'
const state = reactive({
alpha: true,
toneMapping: ACESFilmicToneMapping,
windowSize: true,
clearColor: 0x000000,
})
const vertexSnappingState = reactive({
uSnappingResolution: 3,
modelSnappingResolution: 6,
})
const paneControl = new Pane()
paneControl.addBinding(vertexSnappingState, 'uSnappingResolution', {
label: '圆环扭结-分辨率',
min: 0,
max: 20,
step: 0.01,
})
paneControl.addBinding(vertexSnappingState, 'modelSnappingResolution', {
label: '自行车模型-分辨率',
min: 0,
max: 20,
step: 0.01,
})
</script>