bx-1140-postprocessing #12
|
@ -168,6 +168,30 @@
|
|||
"detail": "django.db",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "migrations",
|
||||
"importPath": "django.db",
|
||||
"description": "django.db",
|
||||
"isExtraImport": true,
|
||||
"detail": "django.db",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "models",
|
||||
"importPath": "django.db",
|
||||
"description": "django.db",
|
||||
"isExtraImport": true,
|
||||
"detail": "django.db",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "migrations",
|
||||
"importPath": "django.db",
|
||||
"description": "django.db",
|
||||
"isExtraImport": true,
|
||||
"detail": "django.db",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "models",
|
||||
"importPath": "django.db",
|
||||
|
@ -594,6 +618,23 @@
|
|||
"detail": "object.models",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "colorfield.fields",
|
||||
"kind": 6,
|
||||
"isExtraImport": true,
|
||||
"importPath": "colorfield.fields",
|
||||
"description": "colorfield.fields",
|
||||
"detail": "colorfield.fields",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "ColorField",
|
||||
"importPath": "colorfield.fields",
|
||||
"description": "colorfield.fields",
|
||||
"isExtraImport": true,
|
||||
"detail": "colorfield.fields",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Image",
|
||||
"importPath": "PIL",
|
||||
|
@ -1177,12 +1218,30 @@
|
|||
"detail": "back.object.migrations.0008_rename_can_disabled_element3d_can_not_disable",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Migration",
|
||||
"kind": 6,
|
||||
"importPath": "back.object.migrations.0009_environment_remove_scene3d_hdr_gainmap_and_more",
|
||||
"description": "back.object.migrations.0009_environment_remove_scene3d_hdr_gainmap_and_more",
|
||||
"peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('object', '0008_rename_can_disabled_element3d_can_not_disable'),\n ]\n operations = [\n migrations.CreateModel(\n name='Environment',\n fields=[\n ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n ('env_displacementmap', models.FileField(blank=True, null=True, upload_to=object.models.group_based_upload_to)),",
|
||||
"detail": "back.object.migrations.0009_environment_remove_scene3d_hdr_gainmap_and_more",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Migration",
|
||||
"kind": 6,
|
||||
"importPath": "back.object.migrations.0010_environment_clear_color",
|
||||
"description": "back.object.migrations.0010_environment_clear_color",
|
||||
"peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('object', '0009_environment_remove_scene3d_hdr_gainmap_and_more'),\n ]\n operations = [\n migrations.AddField(\n model_name='environment',\n name='clear_color',\n field=colorfield.fields.ColorField(blank=True, default=None, image_field=None, max_length=25, null=True, samples=None),\n ),",
|
||||
"detail": "back.object.migrations.0010_environment_clear_color",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Scene3DAdmin",
|
||||
"kind": 6,
|
||||
"importPath": "back.object.admin",
|
||||
"description": "back.object.admin",
|
||||
"peekOfCode": "class Scene3DAdmin(admin.ModelAdmin):\n filter_horizontal = ('elements',)\nadmin.site.register(Scene3D, Scene3DAdmin)\nadmin.site.register(Element3D)\nadmin.site.register(ClickableArea)",
|
||||
"peekOfCode": "class Scene3DAdmin(admin.ModelAdmin):\n filter_horizontal = (\"elements\",)\nadmin.site.register(Environment)\nadmin.site.register(Scene3D, Scene3DAdmin)\nadmin.site.register(Element3D)\nadmin.site.register(ClickableArea)",
|
||||
"detail": "back.object.admin",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -1195,6 +1254,15 @@
|
|||
"detail": "back.object.apps",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Environment",
|
||||
"kind": 6,
|
||||
"importPath": "back.object.models",
|
||||
"description": "back.object.models",
|
||||
"peekOfCode": "class Environment(models.Model):\n env_displacementmap = models.FileField(\n upload_to=group_based_upload_to, blank=True, null=True\n )\n env_normalmap = models.FileField(\n upload_to=group_based_upload_to, blank=True, null=True\n )\n clear_color = ColorField(blank=True, null=True)\n hdr_gainmap = models.FileField(\n upload_to=group_based_upload_to, blank=True, null=True",
|
||||
"detail": "back.object.models",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Element3D",
|
||||
"kind": 6,
|
||||
|
@ -1209,7 +1277,7 @@
|
|||
"kind": 6,
|
||||
"importPath": "back.object.models",
|
||||
"description": "back.object.models",
|
||||
"peekOfCode": "class Scene3D(models.Model):\n filter_horizontal = (\"elements\",)\n name = models.CharField(\n max_length=120,\n )\n elements = models.ManyToManyField(Element3D)\n min_distance = models.IntegerField(\n validators=[MinValueValidator(1), MaxValueValidator(600)], blank=True, null=True\n )\n max_distance = models.IntegerField(",
|
||||
"peekOfCode": "class Scene3D(models.Model):\n name = models.CharField(max_length=120)\n elements = models.ManyToManyField(Element3D)\n env = models.ForeignKey(Environment, models.RESTRICT, blank=True, null=True)\n min_distance = models.IntegerField(\n default=10,\n validators=[MinValueValidator(1), MaxValueValidator(600)],\n )\n max_distance = models.IntegerField(\n default=20,",
|
||||
"detail": "back.object.models",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -1227,7 +1295,7 @@
|
|||
"kind": 2,
|
||||
"importPath": "back.object.models",
|
||||
"description": "back.object.models",
|
||||
"peekOfCode": "def group_based_upload_to(instance, filename):\n logger.info(instance)\n return \"files/image/{}/{}/{}\".format(\n type(instance).__name__.lower(), instance.id, filename\n )\nclass Element3D(models.Model):\n parent = models.ForeignKey(\"self\", on_delete=models.PROTECT, blank=True, null=True)\n model_file = models.FileField(upload_to=group_based_upload_to)\n name = models.CharField(max_length=255)\n description = models.TextField(blank=True, null=True)",
|
||||
"peekOfCode": "def group_based_upload_to(instance, filename):\n logger.info(instance)\n return \"files/image/{}/{}/{}\".format(\n type(instance).__name__.lower(), instance.id, filename\n )\nclass Environment(models.Model):\n env_displacementmap = models.FileField(\n upload_to=group_based_upload_to, blank=True, null=True\n )\n env_normalmap = models.FileField(",
|
||||
"detail": "back.object.models",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -1245,16 +1313,25 @@
|
|||
"kind": 5,
|
||||
"importPath": "back.object.models",
|
||||
"description": "back.object.models",
|
||||
"peekOfCode": "logger = logging.getLogger(\"root\")\ndef group_based_upload_to(instance, filename):\n logger.info(instance)\n return \"files/image/{}/{}/{}\".format(\n type(instance).__name__.lower(), instance.id, filename\n )\nclass Element3D(models.Model):\n parent = models.ForeignKey(\"self\", on_delete=models.PROTECT, blank=True, null=True)\n model_file = models.FileField(upload_to=group_based_upload_to)\n name = models.CharField(max_length=255)",
|
||||
"peekOfCode": "logger = logging.getLogger(\"root\")\ndef group_based_upload_to(instance, filename):\n logger.info(instance)\n return \"files/image/{}/{}/{}\".format(\n type(instance).__name__.lower(), instance.id, filename\n )\nclass Environment(models.Model):\n env_displacementmap = models.FileField(\n upload_to=group_based_upload_to, blank=True, null=True\n )",
|
||||
"detail": "back.object.models",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "EnvironmentSerializer",
|
||||
"kind": 6,
|
||||
"importPath": "back.object.serializers",
|
||||
"description": "back.object.serializers",
|
||||
"peekOfCode": "class EnvironmentSerializer(serializers.ModelSerializer):\n hdr_gainmap = serializers.FileField(use_url=False)\n hdr_json = serializers.FileField(use_url=False)\n hdr_webp = serializers.FileField(use_url=False)\n env_displacementmap = serializers.FileField(use_url=False)\n env_normalmap = serializers.FileField(use_url=False)\n class Meta:\n model = Environment\n fields = \"__all__\"\nclass Element3DSerializer(serializers.ModelSerializer):",
|
||||
"detail": "back.object.serializers",
|
||||
"documentation": {}
|
||||
},
|
||||
{
|
||||
"label": "Element3DSerializer",
|
||||
"kind": 6,
|
||||
"importPath": "back.object.serializers",
|
||||
"description": "back.object.serializers",
|
||||
"peekOfCode": "class Element3DSerializer(serializers.ModelSerializer):\n model_file = serializers.ImageField(use_url=False)\n class Meta:\n model = Element3D\n fields = \"__all__\"\nclass Scene3DSerializer(serializers.ModelSerializer):\n elements = Element3DSerializer(many=True)\n hdr_gainmap = serializers.FileField(use_url=False)\n hdr_json = serializers.FileField(use_url=False)\n hdr_webp = serializers.FileField(use_url=False)",
|
||||
"peekOfCode": "class Element3DSerializer(serializers.ModelSerializer):\n model_file = serializers.ImageField(use_url=False)\n class Meta:\n model = Element3D\n fields = \"__all__\"\nclass Scene3DSerializer(serializers.ModelSerializer):\n elements = Element3DSerializer(many=True)\n env = EnvironmentSerializer()\n class Meta:\n model = Scene3D",
|
||||
"detail": "back.object.serializers",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -1263,7 +1340,7 @@
|
|||
"kind": 6,
|
||||
"importPath": "back.object.serializers",
|
||||
"description": "back.object.serializers",
|
||||
"peekOfCode": "class Scene3DSerializer(serializers.ModelSerializer):\n elements = Element3DSerializer(many=True)\n hdr_gainmap = serializers.FileField(use_url=False)\n hdr_json = serializers.FileField(use_url=False)\n hdr_webp = serializers.FileField(use_url=False)\n class Meta:\n model = Scene3D\n fields = \"__all__\"\n depth = 2\nclass ClickableAreaSerializer(serializers.ModelSerializer):",
|
||||
"peekOfCode": "class Scene3DSerializer(serializers.ModelSerializer):\n elements = Element3DSerializer(many=True)\n env = EnvironmentSerializer()\n class Meta:\n model = Scene3D\n fields = \"__all__\"\n depth = 2\nclass ClickableAreaSerializer(serializers.ModelSerializer):\n image = serializers.ImageField(use_url=False)\n class Meta:",
|
||||
"detail": "back.object.serializers",
|
||||
"documentation": {}
|
||||
},
|
||||
|
|
|
@ -83,6 +83,7 @@ INSTALLED_APPS = [
|
|||
"rest_framework",
|
||||
"crispy_forms",
|
||||
"crispy_bootstrap4",
|
||||
"colorfield",
|
||||
"api",
|
||||
"frontImages",
|
||||
"object",
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
from django.contrib import admin
|
||||
from .models import ClickableArea, Element3D, Scene3D
|
||||
from .models import ClickableArea, Element3D, Environment, Scene3D
|
||||
|
||||
|
||||
class Scene3DAdmin(admin.ModelAdmin):
|
||||
filter_horizontal = ('elements',)
|
||||
filter_horizontal = ("elements",)
|
||||
|
||||
|
||||
admin.site.register(Environment)
|
||||
admin.site.register(Scene3D, Scene3DAdmin)
|
||||
admin.site.register(Element3D)
|
||||
admin.site.register(ClickableArea)
|
||||
admin.site.register(ClickableArea)
|
||||
|
|
|
@ -2,6 +2,7 @@ from PIL import Image
|
|||
from django.db import models
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.core.exceptions import ValidationError
|
||||
from colorfield.fields import ColorField
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("root")
|
||||
|
@ -14,6 +15,21 @@ def group_based_upload_to(instance, filename):
|
|||
)
|
||||
|
||||
|
||||
class Environment(models.Model):
|
||||
env_displacementmap = models.FileField(
|
||||
upload_to=group_based_upload_to, blank=True, null=True
|
||||
)
|
||||
env_normalmap = models.FileField(
|
||||
upload_to=group_based_upload_to, blank=True, null=True
|
||||
)
|
||||
clear_color = ColorField(blank=True, null=True)
|
||||
hdr_gainmap = models.FileField(
|
||||
upload_to=group_based_upload_to, blank=True, null=True
|
||||
)
|
||||
hdr_json = models.FileField(upload_to=group_based_upload_to, blank=True, null=True)
|
||||
hdr_webp = models.FileField(upload_to=group_based_upload_to, blank=True, null=True)
|
||||
|
||||
|
||||
class Element3D(models.Model):
|
||||
parent = models.ForeignKey("self", on_delete=models.PROTECT, blank=True, null=True)
|
||||
model_file = models.FileField(upload_to=group_based_upload_to)
|
||||
|
@ -27,27 +43,19 @@ class Element3D(models.Model):
|
|||
|
||||
|
||||
class Scene3D(models.Model):
|
||||
filter_horizontal = ("elements",)
|
||||
name = models.CharField(
|
||||
max_length=120,
|
||||
)
|
||||
name = models.CharField(max_length=120)
|
||||
elements = models.ManyToManyField(Element3D)
|
||||
env = models.ForeignKey(Environment, models.RESTRICT, blank=True, null=True)
|
||||
|
||||
min_distance = models.IntegerField(
|
||||
validators=[MinValueValidator(1), MaxValueValidator(600)], blank=True, null=True
|
||||
default=10,
|
||||
validators=[MinValueValidator(1), MaxValueValidator(600)],
|
||||
)
|
||||
max_distance = models.IntegerField(
|
||||
default=20,
|
||||
validators=[MinValueValidator(2), MaxValueValidator(1000)],
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
|
||||
hdr_gainmap = models.FileField(
|
||||
upload_to=group_based_upload_to, blank=True, null=True
|
||||
)
|
||||
hdr_json = models.FileField(upload_to=group_based_upload_to, blank=True, null=True)
|
||||
hdr_webp = models.FileField(upload_to=group_based_upload_to, blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
from rest_framework import serializers
|
||||
from .models import Scene3D, Element3D, ClickableArea
|
||||
from .models import Scene3D, Element3D, ClickableArea, Environment
|
||||
|
||||
|
||||
class EnvironmentSerializer(serializers.ModelSerializer):
|
||||
hdr_gainmap = serializers.FileField(use_url=False)
|
||||
hdr_json = serializers.FileField(use_url=False)
|
||||
hdr_webp = serializers.FileField(use_url=False)
|
||||
env_displacementmap = serializers.FileField(use_url=False)
|
||||
env_normalmap = serializers.FileField(use_url=False)
|
||||
|
||||
class Meta:
|
||||
model = Environment
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class Element3DSerializer(serializers.ModelSerializer):
|
||||
|
@ -12,9 +24,7 @@ class Element3DSerializer(serializers.ModelSerializer):
|
|||
|
||||
class Scene3DSerializer(serializers.ModelSerializer):
|
||||
elements = Element3DSerializer(many=True)
|
||||
hdr_gainmap = serializers.FileField(use_url=False)
|
||||
hdr_json = serializers.FileField(use_url=False)
|
||||
hdr_webp = serializers.FileField(use_url=False)
|
||||
env = EnvironmentSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Scene3D
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
asgiref==3.8.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0"
|
||||
crispy-bootstrap4==2024.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
django-colorfield==0.11.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
django-cors-headers==4.3.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
django-crispy-forms==2.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
django-extensions==3.2.3 ; python_version >= "3.10" and python_version < "4.0"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
|
@ -1,35 +1,53 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, watch } from 'vue';
|
||||
|
||||
import { EquirectangularReflectionMapping, ReinhardToneMapping } from 'three';
|
||||
import { ACESFilmicToneMapping, Color, Fog, PMREMGenerator, SRGBColorSpace } from 'three';
|
||||
import { GainMapLoader } from '@monogrid/gainmap-js'
|
||||
import { useTresContext } from '@tresjs/core';
|
||||
|
||||
import hdr_gainmap from '../../assets/promo/hdr/hdr-gainmap.webp'
|
||||
import hdr_json from '../../assets/promo/hdr/hdr.json?url'
|
||||
import hdr_webp from '../../assets/promo/hdr/hdr.webp'
|
||||
import { IMAGE_URL, PROMOBG } from '../../constants';
|
||||
|
||||
const props = defineProps(['hdr_webp', 'hdr_gainmap', 'hdr_json'])
|
||||
|
||||
const props = defineProps(['hdr_webp', 'hdr_gainmap', 'hdr_json', 'env_displacementmap', 'env_normalmap', 'clear_color', 'focus'])
|
||||
const { renderer, scene } = useTresContext()
|
||||
|
||||
const k = { start: 0.5, end: 3.5 }
|
||||
|
||||
renderer.value.outputColorSpace = SRGBColorSpace;
|
||||
renderer.value.toneMapping = ACESFilmicToneMapping;
|
||||
renderer.value.toneMappingExposure = 1.25;
|
||||
renderer.value.setPixelRatio(1.5)
|
||||
|
||||
const loadEnv = async () => {
|
||||
// console.log('update env')
|
||||
const loader = new GainMapLoader(renderer.value)
|
||||
const result = await loader.loadAsync([
|
||||
props.hdr_webp || hdr_webp,
|
||||
props.hdr_gainmap || hdr_gainmap,
|
||||
props.hdr_json || hdr_json,
|
||||
props.hdr_webp ? `${IMAGE_URL}/${props.hdr_webp}` : hdr_webp,
|
||||
props.hdr_gainmap ? `${IMAGE_URL}/${props.hdr_gainmap}` : hdr_gainmap,
|
||||
props.hdr_json ? `${IMAGE_URL}/${props.hdr_json}` : hdr_json,
|
||||
])
|
||||
const pmremGenerator = new PMREMGenerator(renderer.value);
|
||||
pmremGenerator.compileEquirectangularShader();
|
||||
|
||||
const exrCubeRenderTarget = pmremGenerator.fromEquirectangular(result.renderTarget.texture);
|
||||
const newEnvMap = exrCubeRenderTarget ? exrCubeRenderTarget.texture : null;
|
||||
|
||||
scene.value.environment = newEnvMap
|
||||
scene.value.environmentIntensity = 1
|
||||
|
||||
scene.value.environment = result.renderTarget.texture
|
||||
// scene.value.background = result.renderTarget.texture
|
||||
// scene.value.background.mapping = EquirectangularReflectionMapping
|
||||
// scene.value.backgroundBlurriness = 0.15
|
||||
result.renderTarget.texture.dispose();
|
||||
|
||||
const c = new Color()
|
||||
c.set(props.clear_color || PROMOBG)
|
||||
renderer.value.setClearColor(c)
|
||||
scene.value.fog = new Fog(c, props.focus * k.start, props.focus * k.end)
|
||||
}
|
||||
renderer.value.toneMapping = ReinhardToneMapping
|
||||
|
||||
onMounted(async () => {
|
||||
loadEnv()
|
||||
// loadEnv()
|
||||
})
|
||||
watch(() => props.hdr_webp, loadEnv)
|
||||
watch(() => props, loadEnv, { deep: true })
|
||||
</script>
|
||||
<template></template>
|
|
@ -1,21 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import {
|
||||
Box3, Color, DoubleSide, Group, Mesh, MeshBasicMaterial,
|
||||
Box3, CircleGeometry, Color, DoubleSide, Group, Mesh, MeshBasicMaterial,
|
||||
MeshStandardMaterial,
|
||||
MeshStandardMaterialParameters,
|
||||
PlaneGeometry, SpriteMaterial, TextureLoader, Vector2, Vector3,
|
||||
} from 'three';
|
||||
|
||||
import { useTresContext, useSeek, useRenderLoop } from '@tresjs/core';
|
||||
import { useTresContext, useSeek, useRenderLoop, useTexture, useLoop } from '@tresjs/core';
|
||||
import { useGLTF } from '@tresjs/cientos'
|
||||
|
||||
import Env from './env.vue'
|
||||
import PostProcess from './post_pocessing.vue'
|
||||
|
||||
import { IMAGE_URL, SERVER_URL, } from '../../constants'
|
||||
import { IMAGE_URL, PROMOBG, SERVER_URL, } from '../../constants'
|
||||
import { usePromoSidebar } from '../../stores/promo_sidebar';
|
||||
import { usePromoScene } from '../../stores/promo_scene';
|
||||
|
||||
const props = defineProps(['source', 'loaded', 'loaded_pan', 'clearColor'])
|
||||
const props = defineProps(['source', 'loaded', 'loaded_pan'])
|
||||
|
||||
const models = ref<model3DType[]>([])
|
||||
const clickable = ref<clickableAreaType[]>([])
|
||||
|
@ -23,26 +24,46 @@ const clickable_items = ref<any[]>([])
|
|||
const clickable_refs = ref<any[]>([])
|
||||
const sidebar = usePromoSidebar();
|
||||
const sidebar_scene = usePromoScene()
|
||||
const { controls, camera, scene, raycaster } = useTresContext()
|
||||
const { controls, camera, scene, raycaster, renderer } = useTresContext()
|
||||
const { pause, resume } = useLoop()
|
||||
const { seekByName, seekAllByName } = useSeek()
|
||||
const envVars = reactive({}) as { hdr_gainmap?: string, hdr_json?: string, hdr_webp?: string }
|
||||
const tiltShift = reactive({}) as { focus: number, aperture: number, maxblur: number }
|
||||
const envVars = reactive({}) as {
|
||||
focus: number,
|
||||
hdr_gainmap?: string,
|
||||
hdr_json?: string,
|
||||
hdr_webp?: string,
|
||||
clear_color?: string,
|
||||
env_displacementmap?: string,
|
||||
env_normalmap?: string
|
||||
}
|
||||
|
||||
const groundTexture = await useTexture({
|
||||
displacementMap: '/ground_displacement.jpg',
|
||||
})
|
||||
|
||||
const timer = ref(10)
|
||||
let int
|
||||
|
||||
// renderer.value.capabilities.maxTextures = 4
|
||||
// renderer.value.capabilities.maxTextureSize = 512
|
||||
// renderer.value.capabilities.precision = 'lowp'
|
||||
renderer.value.capabilities.maxTextureSize = 512
|
||||
renderer.value.capabilities.precision = 'lowp'
|
||||
|
||||
const loadModels = async () => {
|
||||
const res = await fetch(`${SERVER_URL}/api/obj/scene/${props.source}`)
|
||||
const raw_data = await res.json() as scene3D
|
||||
|
||||
envVars.hdr_gainmap = raw_data.hdr_gainmap ? `${IMAGE_URL}/${raw_data.hdr_gainmap}` : undefined
|
||||
envVars.hdr_json = raw_data.hdr_json ? `${IMAGE_URL}/${raw_data.hdr_json}` : undefined
|
||||
envVars.hdr_webp = raw_data.hdr_webp ? `${IMAGE_URL}/${raw_data.hdr_webp}` : undefined
|
||||
envVars.focus = raw_data.min_distance * 1
|
||||
if (raw_data.env) {
|
||||
Object.assign(envVars, raw_data.env)
|
||||
} else {
|
||||
delete envVars.env_displacementmap
|
||||
delete envVars.env_normalmap
|
||||
delete envVars.hdr_gainmap
|
||||
delete envVars.hdr_json
|
||||
delete envVars.hdr_webp
|
||||
envVars.clear_color = PROMOBG
|
||||
}
|
||||
|
||||
tiltShift.focus = raw_data.max_distance * 0.33
|
||||
tiltShift.aperture = 10
|
||||
tiltShift.maxblur = 1
|
||||
|
||||
const data = raw_data.elements
|
||||
if (!controls.value) return;
|
||||
|
@ -66,12 +87,54 @@ const loadModels = async () => {
|
|||
item.modelFile = loaded_scene
|
||||
item.name = element.name
|
||||
|
||||
if (!element.is_enabled) {
|
||||
item.modelFile.visible = false
|
||||
}
|
||||
|
||||
models.value.push(item)
|
||||
|
||||
const res = await fetch(`${SERVER_URL}/api/obj/clickable/?source=${element.id}`)
|
||||
const clickable_areas = await res.json()
|
||||
clickable.value.push(...clickable_areas)
|
||||
}
|
||||
|
||||
let c = new Color()
|
||||
if (envVars.clear_color) {
|
||||
c.set(envVars.clear_color)
|
||||
} else {
|
||||
renderer.value.getClearColor(c)
|
||||
}
|
||||
const tex = {} as any
|
||||
if (envVars.env_displacementmap) { tex.displacementMap = `${IMAGE_URL}/${envVars.env_displacementmap}` }
|
||||
if (envVars.env_normalmap) { tex.normalMap = `${IMAGE_URL}/${envVars.env_normalmap}` }
|
||||
let addTexture: any
|
||||
if (Object.keys(tex).length > 0) {
|
||||
addTexture = await useTexture(tex)
|
||||
}
|
||||
|
||||
const mesh = {
|
||||
color: c.offsetHSL(0, 0.5, -0.33),
|
||||
displacementScale: envVars.focus * 0.33,
|
||||
roughness: 100,
|
||||
side: DoubleSide
|
||||
} as MeshStandardMaterialParameters
|
||||
if (envVars.env_displacementmap) {
|
||||
mesh.displacementMap = addTexture.displacementMap
|
||||
} else {
|
||||
mesh.displacementMap = groundTexture.displacementMap
|
||||
}
|
||||
if (envVars.env_normalmap) {
|
||||
mesh.normalMap = addTexture.normalMap
|
||||
}
|
||||
const ground = new Mesh(
|
||||
new PlaneGeometry(envVars.focus * 7, envVars.focus * 7, 1024, 1024),
|
||||
new MeshStandardMaterial(mesh)
|
||||
)
|
||||
ground.position.y = -0.33 * envVars.focus
|
||||
ground.rotateX(-Math.PI / 2)
|
||||
ground.name = "ground"
|
||||
models.value.push({ name: 'ground', modelFile: ground })
|
||||
|
||||
sidebar_scene.setData(sidebar_items)
|
||||
|
||||
for (let index = 0; index < clickable.value.length; index++) {
|
||||
|
@ -116,21 +179,44 @@ const loadModels = async () => {
|
|||
box.getSize(box_size)
|
||||
props.loaded_pan(
|
||||
new Vector3(box_size.x * 0.5, box_size.y * 0.5, box_size.z * 0.5),
|
||||
new Vector3(box_size.x * -0.5, box_size.y * -0.5, box_size.z * -0.5),
|
||||
new Vector3(box_size.x * -0.5, box_size.y * -0.25, box_size.z * -0.5),
|
||||
)
|
||||
}
|
||||
|
||||
controls.value.enabled = true;
|
||||
props.loaded(false)
|
||||
|
||||
clearInterval(int)
|
||||
timer.value = 10
|
||||
int = setInterval(() => {
|
||||
if (timer.value > 0) {
|
||||
timer.value -= 1
|
||||
} else if (timer.value == 0 && !controls.value.autoRotate) {
|
||||
pause()
|
||||
camera.value?.position.set(
|
||||
controls.value.minDistance * 0.5,
|
||||
controls.value.minDistance * 0.5,
|
||||
controls.value.minDistance
|
||||
);
|
||||
(controls.value as any).autoRotate = true;
|
||||
(controls.value as any).autoRotateSpeed = 1;
|
||||
resume()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const { onLoop } = useRenderLoop()
|
||||
onLoop(() => {
|
||||
const { onAfterRender } = useLoop()
|
||||
onAfterRender(() => {
|
||||
clickable_refs.value.map(el => {
|
||||
if (el.value[0] && typeof el.value[0].lookAt == 'function') {
|
||||
el.value[0].lookAt(camera.value?.position)
|
||||
el.value[0].lookAt(camera.value?.position);
|
||||
}
|
||||
})
|
||||
if (controls.value) {
|
||||
if (timer.value == 0) {
|
||||
(controls.value as any).update();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const openSidebar = (id: number) => {
|
||||
|
@ -160,12 +246,24 @@ watch(() => props.source, () => {
|
|||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', clickEvent)
|
||||
document.addEventListener('click', stopTimer)
|
||||
document.addEventListener('touchstart', stopTimer)
|
||||
if (sidebar.is_open) {
|
||||
sidebar.close()
|
||||
}
|
||||
})
|
||||
onUnmounted(() => { document.removeEventListener('click', clickEvent) })
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', clickEvent)
|
||||
document.removeEventListener('click', stopTimer)
|
||||
document.removeEventListener('touchstart', stopTimer)
|
||||
})
|
||||
const pointer = reactive({ x: 0, y: 0 })
|
||||
const stopTimer = () => {
|
||||
timer.value = 10;
|
||||
if (controls.value.autoRotate) {
|
||||
controls.value.autoRotate = false;
|
||||
}
|
||||
}
|
||||
const clickEvent = (event: MouseEvent) => {
|
||||
const x = (event.clientX / window.innerWidth) * 2 - 1
|
||||
const y = - (event.clientY / window.innerHeight) * 2 + 1
|
||||
|
@ -196,7 +294,6 @@ watch(() => sidebar_scene.list, () => {
|
|||
<template>
|
||||
<TresGroup name="loaded">
|
||||
<Env v-bind="envVars" />
|
||||
<PostProcess :tiltShift="tiltShift" :clearColor="props.clearColor" />
|
||||
<template v-for="item in models">
|
||||
<TresGroup :name="item.name">
|
||||
<TresObject3D v-bind="item.modelFile.clone()" />
|
||||
|
|
|
@ -5,12 +5,13 @@ import { RouterLink, useRoute } from 'vue-router';
|
|||
|
||||
import { Vector3 } from 'three';
|
||||
import { TresCanvas } from '@tresjs/core';
|
||||
import { OrbitControls } from '@tresjs/cientos'
|
||||
import { OrbitControls, Stats } from '@tresjs/cientos'
|
||||
import '@tresjs/leches/styles'
|
||||
|
||||
import LoadModels from './load_models.vue'
|
||||
import Sidebar from './sidebar.vue'
|
||||
import { usePromoSidebar } from '../../stores/promo_sidebar';
|
||||
import { PROMOBG } from '../../constants';
|
||||
|
||||
const minPan = ref(new Vector3(-2, -2, -2))
|
||||
const maxPan = ref(new Vector3(2, 2, 2))
|
||||
|
@ -35,7 +36,7 @@ const cameraPosition = ref([1, 1, 1]) as unknown as Ref<Vector3>
|
|||
const controlsState = reactive({
|
||||
enableDamping: false,
|
||||
maxPolarAngle: (Math.PI / 2) - 0.07,
|
||||
minAzimuthAngle: (Math.PI / 2) - 0.07,
|
||||
minAzimuthAngle: (Math.PI / 2) - 0.20,
|
||||
})
|
||||
const models_loading = ref(true)
|
||||
const set_model_load_status = (status: boolean) => {
|
||||
|
@ -54,22 +55,18 @@ watch(() => route.params.target, () => {
|
|||
}
|
||||
}, { deep: true })
|
||||
|
||||
const clearColor = 'steelBlue'
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div :class="[{ 'loading': models_loading }, 'canvas-wrapper']">
|
||||
<TresCanvas window-size :alpha="false" power-preference="high-performance" :clear-color="clearColor">
|
||||
<TresCanvas window-size :alpha="false" power-preference="high-performance" :clear-color="PROMOBG"
|
||||
:shadows="false">
|
||||
<Stats />
|
||||
<TresPerspectiveCamera :position="cameraPosition" ref="camera" />
|
||||
<OrbitControls v-bind="controlsState" @change="onChange" make-default />
|
||||
<Suspense>
|
||||
<LoadModels :source="source" :loaded="set_model_load_status" :loaded_pan="loadedPan" :clear-color="clearColor" />
|
||||
<LoadModels :source="source" :loaded="set_model_load_status" :loaded_pan="loadedPan" />
|
||||
</Suspense>
|
||||
<TresMesh :position-y="-1" :rotate-x="-Math.PI / 2" receive-shadow>
|
||||
<TresPlaneGeometry :args="[2000, 2000]" />
|
||||
<!-- <TresShadowMaterial :opacity="0.2" /> -->
|
||||
<TresMeshStandardMaterial :color="clearColor" />
|
||||
</TresMesh>
|
||||
</TresCanvas>
|
||||
<div class="homelink">
|
||||
<a href="#" @click.prevent="sidebar.open" v-if="!sidebar.is_open">
|
||||
|
|
|
@ -8,53 +8,39 @@ import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
|
|||
|
||||
import { useTresContext, useLoop } from '@tresjs/core';
|
||||
import { watch } from 'vue';
|
||||
import { Fog, FogExp2 } from 'three';
|
||||
import { Color, Fog } from 'three';
|
||||
|
||||
const { renderer, camera, scene } = useTresContext()
|
||||
|
||||
const composer = new EffectComposer(renderer.value);
|
||||
|
||||
const props = defineProps(['tiltShift', 'clearColor'])
|
||||
const k = { start: 0.25, end: 3 }
|
||||
const props = defineProps(['tiltShift'])
|
||||
const k = { start: 0.5, end: 2.5 }
|
||||
|
||||
if (camera.value) {
|
||||
const renderPass = new RenderPass(scene.value, camera.value);
|
||||
const makePostProcess = () => {
|
||||
if (camera.value) {
|
||||
const renderPass = new RenderPass(scene.value, camera.value);
|
||||
|
||||
const bokehPass = new BokehPass(scene.value, camera.value, {
|
||||
focus: props.tiltShift.focus,
|
||||
aperture: (props.tiltShift.aperture) * 0.00001,
|
||||
maxblur: (props.tiltShift.maxblur) * 0.01
|
||||
});
|
||||
const bokehPass = new BokehPass(scene.value, camera.value, {
|
||||
focus: props.tiltShift.focus,
|
||||
aperture: (props.tiltShift.aperture) * 0.00001,
|
||||
maxblur: (props.tiltShift.maxblur) * 0.01
|
||||
});
|
||||
const outputPass = new OutputPass();
|
||||
// composer.addPass(renderPass);
|
||||
// composer.addPass(bokehPass);
|
||||
// composer.addPass(outputPass);
|
||||
|
||||
const outputPass = new OutputPass();
|
||||
composer.addPass(renderPass);
|
||||
composer.addPass(bokehPass);
|
||||
composer.addPass(outputPass);
|
||||
|
||||
// scene.value.fog = new FogExp2(0xff0000, 0.005)
|
||||
scene.value.fog = new Fog(props.clearColor, props.tiltShift.focus * k.start, props.tiltShift.focus * k.end)
|
||||
const c = new Color()
|
||||
renderer.value.getClearColor(c)
|
||||
scene.value.fog = new Fog(c, props.tiltShift.focus * k.start, props.tiltShift.focus * k.end)
|
||||
}
|
||||
}
|
||||
makePostProcess()
|
||||
const { onAfterRender } = useLoop()
|
||||
onAfterRender(() => {
|
||||
composer.render()
|
||||
// composer.render()
|
||||
})
|
||||
watch(props.tiltShift, () => {
|
||||
if (camera.value) {
|
||||
const args = {
|
||||
focus: props.tiltShift.focus,
|
||||
aperture: props.tiltShift.aperture * 0.00001,
|
||||
maxblur: props.tiltShift.maxblur * 0.01
|
||||
}
|
||||
const bokehPass = new BokehPass(scene.value, camera.value, args);
|
||||
composer.passes = []
|
||||
const renderPass = new RenderPass(scene.value, camera.value);
|
||||
const outputPass = new OutputPass();
|
||||
composer.addPass(renderPass);
|
||||
composer.addPass(bokehPass);
|
||||
composer.addPass(outputPass);
|
||||
|
||||
scene.value.fog = new Fog(props.clearColor, props.tiltShift.focus * k.start, props.tiltShift.focus * k.end)
|
||||
}
|
||||
}, { deep: true })
|
||||
watch(props.tiltShift, makePostProcess, { deep: true })
|
||||
</script>
|
||||
<template></template>
|
|
@ -1,2 +1,4 @@
|
|||
export const SERVER_URL = import.meta.env.VITE_SERVER_URL ?? window.location.origin
|
||||
export const IMAGE_URL = import.meta.env.VITE_IMAGE_URL ?? window.location.origin
|
||||
export const IMAGE_URL = import.meta.env.VITE_IMAGE_URL ?? window.location.origin
|
||||
|
||||
export const PROMOBG='#ccc'
|
|
@ -14,10 +14,15 @@ interface scene3D {
|
|||
name: string
|
||||
min_distance: number
|
||||
max_distance: number
|
||||
hdr_gainmap?: string
|
||||
hdr_json?: string
|
||||
hdr_webp?: string
|
||||
elements: element3DType[]
|
||||
env: {
|
||||
hdr_gainmap?: string
|
||||
hdr_json?: string
|
||||
hdr_webp?: string
|
||||
env_displacementmap?: string
|
||||
env_normalmap?: string
|
||||
clear_color?: string
|
||||
}
|
||||
}
|
||||
interface element3DType {
|
||||
id: number
|
||||
|
|
|
@ -63,6 +63,20 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""}
|
|||
argon2 = ["argon2-cffi (>=19.1.0)"]
|
||||
bcrypt = ["bcrypt"]
|
||||
|
||||
[[package]]
|
||||
name = "django-colorfield"
|
||||
version = "0.11.0"
|
||||
description = "color field for django models with a nice color-picker in the admin."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "django-colorfield-0.11.0.tar.gz", hash = "sha256:05c38c8eb2a94938b810a19b2011846391a4ce71d1c92e88a35974fbcc8fc62e"},
|
||||
{file = "django_colorfield-0.11.0-py3-none-any.whl", hash = "sha256:460f40e6123b6ae0fb51a4eb86fc258fcdc0ea28f75102b685e8209b1eae9ec3"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
Pillow = ">=9.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "django-cors-headers"
|
||||
version = "4.3.1"
|
||||
|
@ -449,4 +463,4 @@ files = [
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "be85620e01baf8ceb925bd6fe9283c50da4fc1a97d9f572b92266adb0f44c124"
|
||||
content-hash = "6b760d833dfd807526e05ba86e0e6cddb82ee47ec315f4a51d469aecfd1534e4"
|
||||
|
|
|
@ -21,6 +21,7 @@ django-filter = "^24.2"
|
|||
django-crispy-forms = "^2.2"
|
||||
crispy-bootstrap4 = "^2024.1"
|
||||
django-extensions = "^3.2.3"
|
||||
django-colorfield = "^0.11.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
|
Loading…
Reference in New Issue