Я новичок в обращении с трехмерными объектами, а точнее с тремя JS. Я создал холст с 3 сценами, используя this , поэтому в основном мой проект состоит из 3 сцен, которые принимают полную ширину и высоту окна просмотра. Я хотел получить этот эффект прокрутки , но когда я добавляю элементы сцены в этот демонстрационный файл с прокруткой, возникают его ошибки бросания, поэтому я застрял в этом. Как еще можно это сделать? Будем очень признательны за любые указатели
function main() {
var textureLoader,
cloudMesh,
starGeo,
stars,
light,
camera,
cloudParticles = [];
var canvas = $("#c")[0];
var renderer = new THREE.WebGLRenderer({
canvas,
alpha: true,
antialias: true
});
const sceneElements = [];
// add scene
function addScene(elem, fn) {
sceneElements.push({ elem, fn });
}
// make scene
function makeScene() {
var scene = new THREE.Scene();
const fov = 55;
const aspect = 2;
const near = 0.1;
const far = 5;
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
1,
1000
);
camera.position.z = 1;
camera.rotation.x = 1.16;
camera.rotation.y = -0.12;
camera.rotation.z = 0.27;
// create directional light
const color = "white";
const intensity = 1;
light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
return { scene, camera };
}
{
const elem = $("#ocean_box")[0];
const { scene, camera } = makeScene();
var waterGeometry = new THREE.PlaneBufferGeometry(10000, 10000);
water = new THREE.Water(waterGeometry, {
textureWidth: 512,
textureHeight: 512,
waterNormals: new THREE.TextureLoader().load(
"images/waternormals.jpg",
function (texture) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
}
),
alpha: 1.0,
sunDirection: light.position.clone().normalize(),
sunColor: 0xffffff,
waterColor: 0x001e0f,
distortionScale: 3.7,
fog: scene.fog !== undefined
});
water.rotation.x = -Math.PI / 2;
scene.add(water);
// clouds
const objLoader = new THREE.OBJLoader();
objLoader.setPath("/blender_files/");
const mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath("/blender_files/");
new Promise(resolve => {
mtlLoader.load("Cloud.mtl", material => {
resolve(material);
});
}).then(material => {
material.preload();
objLoader.setMaterials(material);
objLoader.load("Cloud.obj", cubeObj => {
cube = cubeObj;
cube.scale.set(5, 5, 5);
cube.position.set(-1.5, 100, 100);
// cube.addColor("white");
// scene.add(cube);
});
});
textureLoader = new THREE.TextureLoader();
textureLoader.load("images/smoke.png", function (texture) {
cloudGeo = new THREE.PlaneGeometry(150, 150);
cloudMaterial = new THREE.MeshLambertMaterial({
map: texture,
transparent: true,
emissive: "white"
});
// create lots of clouds
for (let i = 0; i < 100; i++) {
cloudMesh = new THREE.Mesh(cloudGeo, cloudMaterial);
cloudMesh.position.set(
Math.random() * 800 - 500,
200,
Math.random() * 800 - 500
);
// cloudMesh.rotation.x = 1.16;
// cloudMesh.rotation.y = -0.2;
// cloudMesh.rotation.z = Math.random() * 2 * Math.PI;
cloudMesh.material.opacity = 0.5;
cloudParticles.push(cloudMesh);
scene.add(cloudMesh);
}
scene.add(cloudMesh);
});
var sky = new THREE.Sky();
var uniforms = sky.material.uniforms;
uniforms["turbidity"].value = 10;
uniforms["rayleigh"].value = 2;
uniforms["luminance"].value = 1;
uniforms["mieCoefficient"].value = 0.005;
uniforms["mieDirectionalG"].value = 0.8;
var parameters = {
distance: 400,
inclination: 0.4158,
azimuth: 0.215
};
var cubeCamera = new THREE.CubeCamera(0.1, 1, 512);
cubeCamera.renderTarget.texture.generateMipmaps = true;
cubeCamera.renderTarget.texture.minFilter = THREE.LinearMipmapLinearFilter;
scene.background = cubeCamera.renderTarget;
function updateSun() {
var theta = Math.PI * (parameters.inclination - 0.5);
var phi = 2 * Math.PI * (parameters.azimuth - 0.5);
light.position.x = parameters.distance * Math.cos(phi);
light.position.y = parameters.distance * Math.sin(phi) * Math.sin(theta);
light.position.z = parameters.distance * Math.sin(phi) * Math.cos(theta);
sky.material.uniforms["sunPosition"].value = light.position.copy(
light.position
);
water.material.uniforms["sunDirection"].value
.copy(light.position)
.normalize();
cubeCamera.update(renderer, sky);
}
updateSun();
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI * 0.495;
controls.target.set(0, 10, 0);
controls.minDistance = 10.0;
controls.maxDistance = 200.0;
controls.update();
addScene(elem, (time, rect) => {
camera.aspect = rect.width / rect.height;
camera.updateProjectionMatrix();
// cloudMesh.rotation.y = time * 0.1;
cloudParticles.forEach(p => {
// p.rotation.z -= 0.001;
});
renderer.render(scene, camera);
});
}
{
// const elem = $("#nebula_box")[0];
// const { scene, camera } = makeScene();
// scene.background = new THREE.Color("#b6e1fc");
// console.log("scene", scene);
// scene.fog = new THREE.FogExp2("#87cefa", 0.001);
// renderer.setClearColor(scene.fog.color);
// // create a loader for loading smoke effect
// textureLoader = new THREE.TextureLoader();
// textureLoader.load("images/smoke.png", function (texture) {
// console.log(texture);
// cloudGeo = new THREE.PlaneGeometry(500, 500);
// cloudMaterial = new THREE.MeshLambertMaterial({
// map: texture,
// emissive: "white",
// transparent: true
// });
// // create lots of clouds
// for (let i = 0; i < 30; i++) {
// cloudMesh = new THREE.Mesh(cloudGeo, cloudMaterial);
// cloudMesh.position.set(
// Math.random() * 800 - 500,
// 200,
// Math.random() * 800 - 500
// );
// cloudMesh.rotation.x = 1.16;
// cloudMesh.rotation.y = -0.12;
// cloudMesh.rotation.z = Math.random() * 2 * Math.PI;
// cloudMesh.material.opacity = 0.55;
// cloudParticles.push(cloudMesh);
// scene.add(cloudMesh);
// }
// scene.add(cloudMesh);
// // add lighting
// let directionalLight = new THREE.DirectionalLight(0xff8c19);
// directionalLight.position.set(0, 0, 1);
// scene.add(directionalLight);
// // now add differet point lights
// // blue light
// let blueLight = new THREE.PointLight(0x3677ac, 50, 450, 1.7);
// blueLight.position.set(300, 300, 200);
// scene.add(blueLight);
// // red light
// let greyLight = new THREE.PointLight("#808080", 50, 450, 1.7);
// greyLight.position.set(100, 300, 100);
// scene.add(greyLight);
// // orange light
// let orangeLight = new THREE.PointLight("#808080", 50, 450, 1.7);
// orangeLight.position.set(200, 300, 100);
// scene.add(orangeLight);
// addScene(elem, (time, rect) => {
// camera.aspect = rect.width / rect.height;
// camera.updateProjectionMatrix();
// // cloudMesh.rotation.y = time * 0.1;
// cloudParticles.forEach(p => {
// p.rotation.z -= 0.01;
// });
// renderer.render(scene, camera);
// });
// });
}
// cloud
{
const elem = $("#cloud_box")[0];
const { scene, camera } = makeScene();
scene.background = new THREE.Color("#b6e1fc");
// scene.fog = new THREE.FogExp2("#87cefa", 0.001);
// renderer.setClearColor(scene.fog.color);
// create a loader for loading smoke effect
textureLoader = new THREE.TextureLoader();
textureLoader.load("images/smoke.png", function (texture) {
cloudGeo = new THREE.PlaneGeometry(100, 100);
cloudMaterial = new THREE.MeshLambertMaterial({
map: texture,
emissive: "white",
transparent: true
});
// create lots of clouds
for (let i = 0; i < 800; i++) {
cloudMesh = new THREE.Mesh(cloudGeo, cloudMaterial);
cloudMesh.position.set(
Math.random() * 900 - 400,
300,
Math.random() * 900 - 500
);
cloudMesh.rotation.x = 1.16;
cloudMesh.rotation.y = -0.12;
cloudMesh.rotation.z = Math.random() * 9 * Math.PI;
cloudMesh.material.opacity = 0.9;
cloudParticles.push(cloudMesh);
scene.add(cloudMesh);
}
scene.add(cloudMesh);
// add lighting
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0, 0, 1);
scene.add(directionalLight);
// now add differet point lights
// blue light
let blueLight = new THREE.PointLight(0x3677ac, 50, 450, 1.7);
blueLight.position.set(300, 300, 200);
// scene.add(blueLight);
addScene(elem, (time, rect) => {
camera.aspect = rect.width / rect.height;
camera.updateProjectionMatrix();
// cloudMesh.rotation.y = time * 0.1;
cloudParticles.forEach(p => {
p.rotation.z -= 0.02;
});
renderer.render(scene, camera);
});
});
}
{
const elem = $("#star_space_box")[0];
const { scene, camera } = makeScene();
scene.background = new THREE.Color("black");
// create Geometery
starGeo = new THREE.Geometry();
for (i = 0; i < 6000; i++) {
star = new THREE.Vector3(
Math.random() * 800 - 500,
Math.random() * 800 - 500,
Math.random() * 800 - 500
);
// add animation
star.velocity = 0;
star.acceleration = 0.002;
starGeo.vertices.push(star);
}
var sprite = new THREE.TextureLoader().load("images/star.jpg");
var starMaterial = new THREE.PointsMaterial({
color: "yellow",
size: 0.9,
map: sprite
});
stars = new THREE.Points(starGeo, starMaterial);
scene.add(stars);
addScene(elem, (time, rect) => {
camera.aspect = rect.width / rect.height;
camera.updateProjectionMatrix();
// cloudMesh.rotation.y = time * 0.1;
starGeo.vertices.forEach(p => {
p.velocity += p.acceleration;
p.y -= p.velocity;
if (p.y < -200) {
p.y = 200;
p.velocity = 0;
}
});
starGeo.verticesNeedUpdate = true;
renderer.render(scene, camera);
});
}
console.log(sceneElements);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
// now render
function render(time) {
time *= 0.001;
// this is to allow object to transform along with the scrolling
const transform = "translateY(" + window.scrollY + "px)";
renderer.domElement.style.transform = transform;
resizeRendererToDisplaySize(renderer);
renderer.setScissorTest(false);
renderer.setClearColor("black", 0);
renderer.clear(true, true);
renderer.setScissorTest(true);
// animate water
water.material.uniforms["time"].value += 1.0 / 60.0;
// loop the sceneElements
sceneElements.forEach((sceneObj, index) => {
console.log("index", index);
const { elem, fn } = sceneObj;
// this fetch top, right, width, height etc of that elem
const cube = elem.getBoundingClientRect();
const { left, right, top, bottom, width, height } = cube;
// check if the cube is offscreen
const isOffScreen =
bottom < 0 ||
top > renderer.domElement.clientHeight ||
right < 0 ||
left > renderer.domElement.clientWidth;
// if it is not offscreen
if (!isOffScreen) {
const positiveYUpBottom = renderer.domElement.clientHeight - bottom;
renderer.setScissor(left, positiveYUpBottom, width, height);
renderer.setViewport(left, positiveYUpBottom, width, height);
fn(time, cube);
}
});
// request animation
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
#c {
position: absolute;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
display: block;
z-index: -1;
}
.diagram {
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<title>183degrees</title>
<!-- The default layout, resets and and text styling -->
<link href="stylesheets/main.css" rel="stylesheet" />
<!-- Custom styling -->
<link href="stylesheets/scroll.css" rel="stylesheet" />
<link href="stylesheets/custom.css" rel="stylesheet" />
</head>
<body>
<canvas id="c"></canvas>
<div id="ocean_box" class="diagram"></div>
<div id="cloud_box" class="diagram"></div>
<div id="star_space_box" class="diagram"></div>
<script src="./javascripts/jquery-3.5.0.min.js"></script>
<!-- <script src="./javascripts/rellax.min.js"></script> -->
<script src="javascripts/three.min.js"></script>
<script src="javascripts/postprocessing.min.js"></script>
<script src="javascripts/Water.js"></script>
<script src="javascripts/OrbitControls.js"></script>
<script src="javascripts/Sky.js"></script>
<script src="javascripts/OBJLoader.js"></script>
<script src="javascripts/MTLLoader.js"></script>
<script src="./javascripts/animation.js"></script>
</body>
</html>
Я использовал приведенный выше код, я просто хочу добавить в него эффект прокрутки.