• 23-10-2024, 19:12:22
    #1
    Kişisel Rütbe

    HTML Hali
    <!DOCTYPE html>
    <html lang="tr">
      <head>
        <meta charset="UTF-8" />
        <title>3D Soul Planet</title>
        <style>
          body {
            margin: 0;
            background-color: black;
            touch-action: none;
          }
          canvas {
            display: block;
          }
        </style>
      </head>
      <body>
        <script type="module">
          import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js'
    
          
          const scene = new THREE.Scene()
    
          
          const camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
          )
          camera.position.set(0, 0, 14)
          camera.lookAt(0, 0, 0)
    
          
          const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
          renderer.setSize(window.innerWidth, window.innerHeight)
          renderer.setPixelRatio(window.devicePixelRatio)
          renderer.setClearColor(0x000000, 0)
          document.body.appendChild(renderer.domElement)
    
          
          const sphereGeometry = new THREE.SphereGeometry(4.85, 16, 16)
          const sphereMaterial = new THREE.ShaderMaterial({
            uniforms: {
              color: { value: new THREE.Color(0x000000) },
              opacity: { value: 0.8 },
            },
            vertexShader: `
              varying vec3 vNormal;
              void main() {
                  vNormal = normalize(normalMatrix * normal);
                  gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
              }
            `,
            fragmentShader: `
              uniform vec3 color;
              uniform float opacity;
              varying vec3 vNormal;
              void main() {
                  float alpha = opacity * smoothstep(0.5, 1.0, vNormal.z);
                  gl_FragColor = vec4(color, alpha);
              }
            `,
            transparent: true,
            side: THREE.FrontSide,
            depthWrite: false,
          })
    
          const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
          scene.add(sphere)
    
          
          const smallBallGeometry = new THREE.SphereGeometry(0.15, 16, 16)
          const smallBalls = []
          const labelSprites = []
    
          const radius = 5
          const numPoints = 88
          const goldenRatio = (1 + Math.sqrt(5)) / 2
          const maxWidth = 160
          const textSpeed = 0.002
    
          
          const raycaster = new THREE.Raycaster()
          const mouse = new THREE.Vector2()
    
          function createTextTexture(text, parameters = {}) {
            const {
              fontSize = 24,
              fontFace = 'PingFang SC, Microsoft YaHei, Noto Sans, Arial, sans-serif',
              textColor = 'white',
              backgroundColor = 'rgba(0,0,0,0)',
              maxWidth = 160,
            } = parameters
    
            const canvas = document.createElement('canvas')
            const context = canvas.getContext('2d')
            context.font = `${fontSize}px ${fontFace}`
    
            const textMetrics = context.measureText(text)
            const textWidth = Math.ceil(textMetrics.width)
            const textHeight = fontSize * 1.2
    
            const needMarquee = textWidth > maxWidth
    
            let canvasWidth = maxWidth
            if (needMarquee) {
              canvasWidth = textWidth + 60
            }
    
            canvas.width = canvasWidth
            canvas.height = textHeight
            context.font = `${fontSize}px ${fontFace}`
            context.clearRect(0, 0, canvas.width, canvas.height)
    
            context.fillStyle = backgroundColor
            context.fillRect(0, 0, canvas.width, canvas.height)
    
            context.fillStyle = textColor
            context.textAlign = needMarquee ? 'left' : 'center'
            context.textBaseline = 'middle'
    
            if (needMarquee) {
              context.fillText(text, 0, canvas.height / 2)
            } else {
              context.fillText(text, maxWidth / 2, canvas.height / 2)
            }
    
            const texture = new THREE.CanvasTexture(canvas)
            texture.needsUpdate = true
    
            if (needMarquee) {
              texture.wrapS = THREE.RepeatWrapping
              texture.wrapT = THREE.ClampToEdgeWrapping
              texture.repeat.x = maxWidth / canvas.width
            } else {
              texture.wrapS = THREE.ClampToEdgeWrapping
              texture.wrapT = THREE.ClampToEdgeWrapping
            }
    
            texture.minFilter = THREE.LinearFilter
            texture.magFilter = THREE.LinearFilter
            texture.generateMipmaps = false
            return { texture, needMarquee, HWRate: textHeight / maxWidth }
          }
    
          for (let i = 0; i < numPoints; i++) {
            const y = 1 - (i / (numPoints - 1)) * 2
            const radiusAtY = Math.sqrt(1 - y * y)
    
            const theta = (2 * Math.PI * i) / goldenRatio
    
            const x = Math.cos(theta) * radiusAtY
            const z = Math.sin(theta) * radiusAtY
            const smallBallMaterial = new THREE.MeshBasicMaterial({
              color: getRandomBrightColor(),
              depthWrite: true,
              depthTest: true,
              side: THREE.FrontSide,
            })
            const smallBall = new THREE.Mesh(smallBallGeometry, smallBallMaterial)
            smallBall.position.set(x * radius, y * radius, z * radius)
            sphere.add(smallBall)
            smallBalls.push(smallBall)
    
            const labelText = getRandomNickname()
            const { texture, needMarquee, HWRate } = createTextTexture(labelText, {
              fontSize: 28,
              fontFace: 'PingFang SC, Microsoft YaHei, Noto Sans, Arial, sans-serif',
              textColor: '#bbbbbb',
              maxWidth: maxWidth,
            })
    
            const spriteMaterial = new THREE.SpriteMaterial({
              map: texture,
              transparent: true,
              depthWrite: true,
              depthTest: true,
              blending: THREE.NormalBlending,
            })
    
            const sprite = new THREE.Sprite(spriteMaterial)
            sprite.scale.set(1, HWRate, 1)
            labelSprites.push({ sprite, smallBall, texture, needMarquee, labelText })
            scene.add(sprite)
          }
    
          
          const light = new THREE.AmbientLight(0xffffff, 0.5)
          scene.add(light)
          const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
          directionalLight.position.set(5, 5, 5)
          scene.add(directionalLight)
    
          
          const autoRotationSpeed = 0.0005
          let autoRotationAxis = new THREE.Vector3(0, 1, 0).normalize()
          let currentAngularVelocity = autoRotationAxis.clone().multiplyScalar(autoRotationSpeed)
    
          let isDragging = false
          let previousMousePosition = { x: 0, y: 0 }
          let lastDragDelta = { x: 0, y: 0 }
    
          const decayRate = 0.92
          const increaseRate = 1.02
    
          
          const onMouseDown = (event) => {
            isDragging = true
            previousMousePosition = {
              x: event.clientX,
              y: event.clientY,
            }
          }
    
          const onMouseMove = (event) => {
            if (isDragging) {
              const deltaX = event.clientX - previousMousePosition.x
              const deltaY = event.clientY - previousMousePosition.y
    
              lastDragDelta = { x: deltaX, y: deltaY }
    
              const rotationFactor = 0.005
    
              const angleY = deltaX * rotationFactor
              const angleX = deltaY * rotationFactor
    
              const quaternionY = new THREE.Quaternion().setFromAxisAngle(
                new THREE.Vector3(0, 1, 0),
                angleY
              )
              const quaternionX = new THREE.Quaternion().setFromAxisAngle(
                new THREE.Vector3(1, 0, 0),
                angleX
              )
    
              const deltaQuat = new THREE.Quaternion().multiplyQuaternions(quaternionY, quaternionX)
    
              sphere.quaternion.multiplyQuaternions(deltaQuat, sphere.quaternion)
    
              const dragRotationAxis = new THREE.Vector3(deltaY, deltaX, 0).normalize()
              const dragRotationSpeed = Math.sqrt(deltaX * deltaX + deltaY * deltaY) * rotationFactor
    
              if (dragRotationAxis.length() > 0) {
                currentAngularVelocity.copy(dragRotationAxis).multiplyScalar(dragRotationSpeed)
              }
    
              previousMousePosition = {
                x: event.clientX,
                y: event.clientY,
              }
            }
          }
    
          const onMouseUp = () => {
            if (isDragging) {
              isDragging = false
    
              const deltaX = lastDragDelta.x
              const deltaY = lastDragDelta.y
    
              if (deltaX !== 0 || deltaY !== 0) {
                const newAxis = new THREE.Vector3(deltaY, deltaX, 0).normalize()
                if (newAxis.length() > 0) {
                  autoRotationAxis.copy(newAxis)
                }
    
                const dragSpeed = currentAngularVelocity.length()
                if (dragSpeed > autoRotationSpeed) {
                  
                } else {
                  currentAngularVelocity.copy(autoRotationAxis).multiplyScalar(autoRotationSpeed)
                }
              }
            }
          }
    
          
          const onTouchStart = (event) => {
            isDragging = true
            const touch = event.touches[0]
            previousMousePosition = {
              x: touch.clientX,
              y: touch.clientY,
            }
          }
    
          const onTouchMove = (event) => {
            event.preventDefault()
            if (isDragging) {
              const touch = event.touches[0]
              const deltaX = touch.clientX - previousMousePosition.x
              const deltaY = touch.clientY - previousMousePosition.y
    
              lastDragDelta = { x: deltaX, y: deltaY }
    
              const rotationFactor = 0.002
    
              const angleY = deltaX * rotationFactor
              const angleX = deltaY * rotationFactor
    
              const quaternionY = new THREE.Quaternion().setFromAxisAngle(
                new THREE.Vector3(0, 1, 0),
                angleY
              )
              const quaternionX = new THREE.Quaternion().setFromAxisAngle(
                new THREE.Vector3(1, 0, 0),
                angleX
              )
    
              const deltaQuat = new THREE.Quaternion().multiplyQuaternions(quaternionY, quaternionX)
    
              sphere.quaternion.multiplyQuaternions(deltaQuat, sphere.quaternion)
    
              const dragRotationAxis = new THREE.Vector3(deltaY, deltaX, 0).normalize()
              const dragRotationSpeed = Math.sqrt(deltaX * deltaX + deltaY * deltaY) * rotationFactor
    
              if (dragRotationAxis.length() > 0) {
                currentAngularVelocity.copy(dragRotationAxis).multiplyScalar(dragRotationSpeed)
              }
    
              previousMousePosition = {
                x: touch.clientX,
                y: touch.clientY,
              }
            }
          }
    
          const onTouchEnd = (event) => {
            if (isDragging) {
              isDragging = false
    
              const deltaX = lastDragDelta.x
              const deltaY = lastDragDelta.y
    
              if (deltaX !== 0 || deltaY !== 0) {
                const newAxis = new THREE.Vector3(deltaY, deltaX, 0).normalize()
                if (newAxis.length() > 0) {
                  autoRotationAxis.copy(newAxis)
                }
    
                const dragSpeed = currentAngularVelocity.length()
                if (dragSpeed > autoRotationSpeed) {
                  
                } else {
                  currentAngularVelocity.copy(autoRotationAxis).multiplyScalar(autoRotationSpeed)
                }
              }
            }
    
            
            if (event.changedTouches.length > 0) {
              const touch = event.changedTouches[0]
              mouse.x = (touch.clientX / window.innerWidth) * 2 - 1
              mouse.y = -(touch.clientY / window.innerHeight) * 2 + 1
              checkIntersection()
            }
          }
    
          
          window.addEventListener('mousedown', onMouseDown)
          window.addEventListener('mousemove', onMouseMove)
          window.addEventListener('mouseup', onMouseUp)
          window.addEventListener('touchstart', onTouchStart)
          window.addEventListener('touchmove', onTouchMove)
          window.addEventListener('touchend', onTouchEnd)
          document.addEventListener('gesturestart', function (e) {
            e.preventDefault()
          })
    
         
          window.addEventListener('click', onMouseClick)
    
          
          window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
          })
    
          function onMouseClick(event) {
            event.preventDefault()
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
            console.log(event.clientX, mouse.x, mouse.y)
    
            checkIntersection()
          }
    
          function checkIntersection() {
            raycaster.setFromCamera(mouse, camera)
            const intersects = raycaster.intersectObjects(smallBalls)
    
            if (intersects.length > 0) {
              const intersectedBall = intersects[0].object
              const index = smallBalls.indexOf(intersectedBall)
              if (index !== -1) {
                const labelInfo = labelSprites[index]
                showLabelInfo(labelInfo)
              }
            }
          }
    
          function showLabelInfo(labelInfo) {
            alert(`Tıklanmış top etiketleri:${labelInfo.labelText}`)
          }
    
          
          function animate() {
            requestAnimationFrame(animate)
    
            if (!isDragging) {
              const deltaQuat = new THREE.Quaternion().setFromEuler(
                new THREE.Euler(
                  currentAngularVelocity.x,
                  currentAngularVelocity.y,
                  currentAngularVelocity.z,
                  'XYZ'
                )
              )
              sphere.quaternion.multiplyQuaternions(deltaQuat, sphere.quaternion)
    
              const currentSpeed = currentAngularVelocity.length()
    
              if (currentSpeed > autoRotationSpeed) {
                currentAngularVelocity.multiplyScalar(decayRate)
    
                if (currentAngularVelocity.length() < autoRotationSpeed) {
                  currentAngularVelocity.copy(autoRotationAxis).multiplyScalar(autoRotationSpeed)
                }
              } else if (currentSpeed < autoRotationSpeed) {
                currentAngularVelocity.multiplyScalar(increaseRate)
    
                if (currentAngularVelocity.length() > autoRotationSpeed) {
                  currentAngularVelocity.copy(autoRotationAxis).multiplyScalar(autoRotationSpeed)
                }
              } else {
                currentAngularVelocity.copy(autoRotationAxis).multiplyScalar(autoRotationSpeed)
              }
            }
    
            
            labelSprites.forEach(({ sprite, smallBall, texture, needMarquee }) => {
              smallBall.updateMatrixWorld()
              const smallBallWorldPos = new THREE.Vector3()
              smallBall.getWorldPosition(smallBallWorldPos)
    
              const upOffset = new THREE.Vector3(0, 0.3, 0)
    
              sprite.position.copy(smallBallWorldPos).add(upOffset)
    
              if (needMarquee) {
                texture.offset.x += textSpeed
    
                if (texture.offset.x > 1) {
                  texture.offset.x = 0
                }
              }
            })
    
            renderer.render(scene, camera)
          }
    
          animate()
    
          function getRandomBrightColor() {
            const hue = Math.floor(Math.random() * 360)
            const saturation = Math.floor(Math.random() * 40 + 10)
            const lightness = Math.floor(Math.random() * 40 + 40)
    
            const rgb = hslToRgb(hue, saturation, lightness)
    
            return (rgb.r << 16) | (rgb.g << 8) | rgb.b
          }
    
          function hslToRgb(h, s, l) {
            s /= 100
            l /= 100
    
            const c = (1 - Math.abs(2 * l - 1)) * s
            const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
            const m = l - c / 2
    
            let r, g, b
            if (h >= 0 && h < 60) {
              r = c
              g = x
              b = 0
            } else if (h >= 60 && h < 120) {
              r = x
              g = c
              b = 0
            } else if (h >= 120 && h < 180) {
              r = 0
              g = c
              b = x
            } else if (h >= 180 && h < 240) {
              r = 0
              g = x
              b = c
            } else if (h >= 240 && h < 300) {
              r = x
              g = 0
              b = c
            } else {
              r = c
              g = 0
              b = x
            }
    
            return {
              r: Math.round((r + m) * 255),
              g: Math.round((g + m) * 255),
              b: Math.round((b + m) * 255),
            }
          }
    
          function getRandomNickname() {
            const adjectives = [
              'Cool',
              'Crazy',
              'Mysterious',
              'Happy',
              'Silly',
              'Brave',
              'Smart',
              'Swift',
              'Fierce',
              'Gentle',
            ]
            const nouns = [
              'Tiger',
              'Lion',
              'Dragon',
              'Wizard',
              'Ninja',
              'Pirate',
              'Hero',
              'Ghost',
              'Phantom',
              'Knight',
            ]
    
            const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)]
            const randomNoun = nouns[Math.floor(Math.random() * nouns.length)]
    
            const nickname = `${randomAdjective} ${randomNoun}`
    
            if (nickname.length < 2) {
              return getRandomNickname()
            } else if (nickname.length > 22) {
              return nickname.slice(0, 22)
            }
    
            return nickname
          }
        </script>
      </body>
    </html>
  • 23-10-2024, 19:18:31
    #2
    @Saitama Emeğinize sağlık hocam.
  • 23-10-2024, 19:19:41
    #3
    Kişisel Rütbe
    _Forbidden_ adlı üyeden alıntı: mesajı görüntüle
    @Saitama Emeğinize sağlık hocam.
    Date uygulamarı için ideal şey adam kendi tıklayıp bulması ruh eşi sistemi için mantıklı bence