Threejs随机生成建筑

news/2024/11/8 16:45:19 标签: 3d, 前端

生成建筑,重点在于,什么?

答案当然是数量,生成的建筑过多,那么一定会卡顿模糊,所以。生成建筑的难点而是在于对性能的优化。优化的解决方案就是:BufferGeometryUtils

BufferGeometryUtils的用法就点击上面的连接,去看就好了,这里就直接展示案例:

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js';

export default (domId) => {
    /* ------------------------------初始化三件套--------------------------------- */
    const dom = document.getElementById(domId);
    const { innerHeight, innerWidth } = window

    const scene = new THREE.Scene();

    const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 2000);
    camera.position.set(100, 100, 100);
    camera.lookAt(scene.position);

    const renderer = new THREE.WebGLRenderer({
        antialias: true,// 抗锯齿
        alpha: false,// 透明度
        powerPreference: 'high-performance',// 性能
        logarithmicDepthBuffer: true,// 深度缓冲
    })
    // renderer.setClearColor(0x000000, 0);// 设置背景色
    // renderer.clear();// 清除渲染器
    renderer.shadowMap.enabled = true;// 开启阴影
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;// 阴影类型
    renderer.outputEncoding = THREE.sRGBEncoding;// 输出编码
    renderer.toneMapping = THREE.ACESFilmicToneMapping;// 色调映射
    renderer.toneMappingExposure = 1;// 色调映射曝光
    renderer.physicallyCorrectLights = true;// 物理正确灯光
    renderer.setPixelRatio(devicePixelRatio);// 设置像素比
    renderer.setSize(innerWidth, innerHeight);// 设置渲染器大小
    dom.appendChild(renderer.domElement);

    // 重置大小
    window.addEventListener('resize', () => {
        const { innerHeight, innerWidth } = window
        camera.aspect = innerWidth / innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(innerWidth, innerHeight);
    })

    /* ------------------------------初始化工具--------------------------------- */
    const controls = new OrbitControls(camera, renderer.domElement) // 相机轨道控制器
    controls.enableDamping = true // 是否开启阻尼
    controls.dampingFactor = 0.05// 阻尼系数
    controls.panSpeed = -1// 平移速度

    const axesHelper = new THREE.AxesHelper(10);
    scene.add(axesHelper);

    /* ------------------------------正题--------------------------------- */

    // 设置黄光 (点光源)
    const yellowLight = new THREE.AmbientLight(0xffffff, 0.6);
    scene.add(yellowLight);

    // 设置蓝光 (点光源)
    const blueLight = new THREE.DirectionalLight(0x0000ff, 3);
    blueLight.position.set(50, 50, 50);
    scene.add(blueLight);
    blueLight.castShadow = true; // 开启阴影
    // 设置相机上、下、左、右、近和远裁剪面
    blueLight.shadow.camera.top = 100;
    blueLight.shadow.camera.bottom = -100;
    blueLight.shadow.camera.left = -100;
    blueLight.shadow.camera.right = 100;
    blueLight.shadow.camera.near = 1;
    blueLight.shadow.camera.far = 200;
    blueLight.shadow.mapSize.set(1024, 1024);// 阴影贴图大小

    // 创建一个平面
    const planeGeometry = new THREE.PlaneGeometry(100, 100);
    // 创建一个物理材质
    const planeMaterial = new THREE.MeshStandardMaterial({
        color: new THREE.Color('gray'),
        side: THREE.FrontSide,
        transparent: true
    });
    const plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.rotateX(-Math.PI / 2);
    plane.receiveShadow = true; // 开启阴影
    scene.add(plane);

    const geometries = [];// 存放建筑
    // 随机生成建筑
    const randomBuilding = () => {
        const helper = new THREE.Object3D();
        for (let i = 0; i < 100; i++) {
            const h = Math.round(Math.random() * 15) + 5;// 高度
            const x = Math.round(Math.random() * 50);// x坐标
            const y = Math.round(Math.random() * 50);// y坐标
            helper.position.set((x % 2 ? -1 : 1) * x, h * 0.5, (y % 2 ? -1 : 1) * y);// 设置位置
            const geometry = new THREE.BoxGeometry(5, h, 5);
            helper.updateWorldMatrix(true, false);// 更新世界矩阵
            geometry.applyMatrix4(helper.matrixWorld);// 应用世界矩阵
            geometries.push(geometry);
        }
        // 合并几何体(几何体数组,是否在合并的几何体中保留原始几何体的分组信息)
        const geometry = BufferGeometryUtils.mergeGeometries(geometries, false);
        const img = new URL('../assets/images/house.jpg', import.meta.url).href;
        const texture = new THREE.TextureLoader().load(img);
        // 纹理将以镜像重复的方式填充到物体的表面,即纹理会以镜像的形式重复,直到覆盖整个物体。
        texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping;
        const material = new THREE.MeshStandardMaterial({
            map: texture
        })
        const mesh = new THREE.Mesh(geometry, material);
        mesh.castShadow = true;// 开启阴影投射
        mesh.receiveShadow = true;// 开启阴影接收
        scene.add(mesh);

        const shaderList = []
        material.onBeforeCompile = (shader, renderer) => {
            console.log(shader.vertexShader)
            shaderList.push(shader)
            shader.uniforms.uSize = { value: 50 };
            shader.vertexShader = shader.vertexShader.replace(
                'void main() {',
                `uniform float uSize;
                varying vec2 vUv;
                void main() {`
            );
            shader.vertexShader = shader.vertexShader.replace(
                '#include <fog_vertex>',
                `#include <fog_vertex>
                vUv=position.xz/uSize;`
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                'void main() {',
                `varying vec2 vUv;
                uniform float uTime;
                void main() {`
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                '#include <dithering_fragment>',
                `#include <dithering_fragment>
                gl_FragColor.rgb=gl_FragColor.rgb+mix(vec3(0,0.5,0.5),vec3(1,1,0),vUv.y);`
            );
        }
        planeMaterial.onBeforeCompile = (shader, renderer) => {
            shaderList.push(shader)
            shader.uniforms.uSize = { value: 50 };
            shader.vertexShader = shader.vertexShader.replace(
                'void main() {',
                `uniform float uSize;
                varying vec2 vUv;
                void main() {`
            );
            shader.vertexShader = shader.vertexShader.replace(
                '#include <fog_vertex>',
                `#include <fog_vertex>
                vUv=position.xz/uSize;`
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                'void main() {',
                `varying vec2 vUv;
                uniform float uTime;
                void main() {`
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                '#include <dithering_fragment>',
                `#include <dithering_fragment>
                gl_FragColor.rgb=gl_FragColor.rgb+mix(vec3(0,0.5,0.5),vec3(1,1,0),vUv.y);`
            );
        }
    }
    randomBuilding()

    /* ------------------------------动画函数--------------------------------- */
    const animation = () => {
        controls.update();// 如果不调用,就会很卡
        renderer.render(scene, camera);
        requestAnimationFrame(animation);
    }
    animation();
}

 


http://www.niftyadmin.cn/n/5744167.html

相关文章

ubuntu22.04 docker-compose安装postgresql数据库

在 Ubuntu 22.04 上使用 Docker Compose 来安装和运行 PostgreSQL 数据库的过程如下&#xff1a; 1. 创建 Docker Compose 文件 在项目文件夹中创建一个 docker-compose.yml 文件&#xff0c;以配置 PostgreSQL 数据库的服务。 mkdir postgres_docker cd postgres_docker to…

基于MATLAB的实现垃圾分类Matlab源码

⼀、垃圾分类 如何通过垃圾分类管理&#xff0c;最⼤限度地实现垃圾资源利⽤&#xff0c;减少垃圾处置量&#xff0c;改善⽣存环境质量&#xff0c;是当前世界各国共同关注的迫切问题之⼀。根据国家制定的统⼀标准&#xff0c;现在⽣活垃圾被⼴泛分为四类&#xff0c;分别是可…

.Net IOC理解及代码实现

IOC理解 IoC(Inversion of Control)&#xff1a;即控制反转&#xff0c;这是一种设计思想&#xff0c;指将对象的控制权交给IOC容器&#xff0c;由容器来实现对象的创建、管理&#xff0c;程序员只需要从容器获取想要的对象就可以了。DI(Dependency Injection)&#xff0c;即依…

【学习笔记】SAP ABAP——OPEN SQL(一)【INTO语句】

【INTO语句】 结构体插入(插入一条语句时) SELECT...INTO [CORRESPONDING FIELDS OF] <wa> FROM <db> WHERE <condition>.内表插入(插入多条语句时) SELECT...INTO|APPENDING [CORRESPONDING FIELDS OF] TABLE <itab>FROM <db> WHERE <con…

计算机网络——HTTP篇

基础篇 IOS七层网络模型 TCP/IP四层模型&#xff1f; 应⽤层&#xff1a;位于传输层之上&#xff0c;主要提供两个终端设备上的应⽤程序之间的通信&#xff0c;它定义了信息交换的格式&#xff0c;消息会交给下⼀层传输层来传输。 传输层的主要任务就是负责向两台设备进程之间…

OpenSSL 生成根证书、中间证书和网站证书

OpenSSL 生成根证书、中间证书和网站证书 一、生成根证书&#xff08;ChinaRootCA&#xff09;二、生成中间 CA&#xff08;GuangDongCA&#xff09;三、生成网站证书&#xff08;gdzwfw&#xff09; 一、生成根证书&#xff08;ChinaRootCA&#xff09; 创建私钥&#xff1a; …

43.第二阶段x86游戏实战2-提取游戏里面的lua

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

【开源免费】基于SpringBoot+Vue.JS医院管理系统(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 062 &#xff0c;文末自助获取源码 \color{red}{T062&#xff0c;文末自助获取源码} T062&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…