🤍 전 강의 25% 할인 중 🤍

2024년 상반기를 돌아보고 하반기에도 함께 성장해요!
인프런이 준비한 25% 할인 받으러 가기 >>

  • 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

강의 너무 잘듣고 있습니다. 질문 드립니다.

22.04.06 16:06 작성 조회수 176

0

- 질문에 대한 답변은 강의자가 하는 경우도 있고, 수강생 여러분들이 해주시는 경우도 있습니다. 같이 도와가며 공부해요! :)
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
- 먼저 유사한 질문이 있었는지 검색해보세요.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
 
안녕하세요.
 
CSS 그리드 수업부터 해서 강의 너무 잘듣고 있습니다.
 
현재 material 수업까지 들었는데
 
제가 필요한부분에 있어서 도움을 받을수 있을까 질문 드립니다.
 
제가 필요한 부분이 Bar로 구성되어있는 3D Graph 인데
 
BoxGeomatry로 구성되어 y값에 따라 높이에 따른 색상이 다른부분으로 표현하고 싶은데
 
제가 구글링 해보니깐
 
http://darrendev.blogspot.com/2016/03/gradients-in-threejs.html
 
vertexColors 를 이용하는것 같더라구요
 
그런데 이게 옛날자료라 geomatry의 face부분이라던지 이런 부분이 현재 버젼하고 많이 다른데
 
vertexColor를 컨트롤 할수 있는 방법을 알수 없을까요?
 
답변주시면 정말 감사합니다.

답변 1

답변을 작성해보세요.

0

말씀대로 three.js 특정 버전 이후부터 faces 속성 자체가 없어진 것으로 알고 있습니다. 퍼포먼스 이유였다고 본 것 같은데 정확히 모르겠네요^^; 결국 각 Vertex들을 컨트롤 해야하는데, 다루기가 복잡해서 차라리 CanvasTexture를 이용해서 하는 방법이 어떨까 싶습니다.
(참고로 VertexColors를 컨트롤 하는 부분은 Particle 섹션에 다루는 부분이 있습니다)
여러개의 Material을 적용하는 큐브를 만들고, 각 면에 CanvasTexture를 적용하는 거라고 생각하시면 될 것 같습니다. Material 섹션을 학습하셨다면 아마 두 개념 모두 알고 계실 것 같아요~

이런걸 말씀하신건지 모르겠지만, 질문하신 걸 보고 만들어두면 저도 쓸 일이 있을 것 같아서, 겸사겸사 한번 만들어 봤습니다. 여기에 조금 기능을 붙여서, 강의에 보너스 콘텐츠로 추가 해도 좋을 것 같다는 생각이 드네요^^
값이 클 수록 초록색이 밝게 보이도록 해보았는데요, 그라데이션으로 색상 처리하는 부분을 원하시는 형태로 수정해보시면 될 것 같습니다.
일단 소스코드 공유해 드릴게요-
ex01.js 이런 것 처럼 똑같이 추가해서 같은 방식으로 실행해보시면 됩니다.

아, 참고로 vertexColors를 활용한 큐브 예제는 찾아보니 이런게 있네요.
https://jsfiddle.net/vptec390/2/

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// ----- 주제: 여러 개의 CanvasTexture로 막대 그래프 만들어 보기

export default function example() {
	// Renderer
	const canvas = document.querySelector('#three-canvas');
	const renderer = new THREE.WebGLRenderer({
		canvas,
		antialias: true
	});
	renderer.setSize(window.innerWidth, window.innerHeight);
	renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1);

	// Scene
	const scene = new THREE.Scene();
	scene.background = new THREE.Color('white');

	// Camera
	const camera = new THREE.PerspectiveCamera(
		75,
		window.innerWidth / window.innerHeight,
		0.1,
		1000
	);
	scene.add(camera);

	// Controls
	const controls = new OrbitControls(camera, renderer.domElement);

	const barGroup = new THREE.Group();
	scene.add(barGroup);

	// 샘플 값
	const values = [4, 2.5, 7, 1, 2, 4, 3, 5];
	const maxValue = Math.max(...values);

	const barWidthDepth = 0.5;
	const barDistance = 1;
	const barGeometry = new THREE.BoxGeometry(barWidthDepth, 1, barWidthDepth);
	const maxBarHeight = values.length; // 최대 막대 높이

	camera.position.z = values.length;

	barGroup.position.x = -(barDistance * (values.length - 1)) / 2;
	barGroup.position.y = -maxBarHeight / 2;

	class Bar {
		constructor(info = {}) {
			this.container = info.container;
			this.value = info.value || 0;
			
			const heightValue = this.value / maxValue * maxBarHeight;

			this.x = info.x || 0;
			this.y = heightValue / 2;
			this.z = info.z || 0;

			this.topCanvas = document.createElement('canvas');
			this.topCanvas.width = 500;
			this.topCanvas.height = 500;
			this.topContext = this.topCanvas.getContext('2d');

			this.bottomCanvas = document.createElement('canvas');
			this.bottomCanvas.width = 500;
			this.bottomCanvas.height = 500;
			this.bottomContext = this.bottomCanvas.getContext('2d');

			this.sideCanvas = document.createElement('canvas');
			this.sideCanvas.width = 500;
			this.sideCanvas.height = 500;
			this.sideContext = this.sideCanvas.getContext('2d');

			const textureTop = new THREE.CanvasTexture(this.topCanvas);
			const textureBottom = new THREE.CanvasTexture(this.bottomCanvas);
			const textureSide = new THREE.CanvasTexture(this.sideCanvas);

			this.materials = [
				new THREE.MeshBasicMaterial({ map: textureSide }),
				new THREE.MeshBasicMaterial({ map: textureSide }),
				new THREE.MeshBasicMaterial({ map: textureTop }),
				new THREE.MeshBasicMaterial({ map: textureBottom }),
				new THREE.MeshBasicMaterial({ map: textureSide }),
				new THREE.MeshBasicMaterial({ map: textureSide })
			];

			this.mesh = new THREE.Mesh(barGeometry, this.materials);
			this.mesh.position.set(this.x, this.y, this.z);
			this.mesh.scale.y = heightValue;

			this.container.add(this.mesh);

			this.draw();
		}

		draw() {
			const colorValue = `${this.value / maxValue * 255}`;

			// 위
			this.topContext.fillStyle = `rgb(0, ${colorValue}, 0)`;
			this.topContext.fillRect(0, 0, this.topCanvas.width, this.topCanvas.height);
			// 바닥
			this.bottomContext.fillStyle = 'black';
			this.bottomContext.fillRect(0, 0, this.bottomCanvas.width, this.bottomCanvas.height);

			// 옆 4면(그라데이션)
			const gradient = this.sideContext.createLinearGradient(0, 0, 0, this.sideCanvas.height);
			gradient.addColorStop(0, `rgb(0, ${colorValue}, 0`);
			gradient.addColorStop(1, 'black');
			this.sideContext.fillStyle = gradient;
			this.sideContext.fillRect(0, 0, this.sideCanvas.width, this.sideCanvas.height);
		}
	}

	// value가 클 수록 색상이 밝음
	values.forEach((value, i) => {
		new Bar({ value, container: barGroup, x: i * barDistance, y: 0, z: 0 });
	});

	// 그리기
	const clock = new THREE.Clock();

	function draw() {

		renderer.render(scene, camera);
		renderer.setAnimationLoop(draw);
	}

	function setSize() {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		renderer.setSize(window.innerWidth, window.innerHeight);
		renderer.render(scene, camera);
	}

	// 이벤트
	window.addEventListener('resize', setSize);

	draw();
}
이현선님의 프로필

이현선

질문자

2022.04.08

답변 정말 감사합니다.

 

정말 큰도움됐습니다.

 

감사합니다^^

채널톡 아이콘