THREE.js - 将渐变颜色应用于导入的 GLTF 模型
THREE.js - Apply Gradient Colors to Imported GLTF Model
我一直在尝试将渐变颜色应用于此官方 THREE.js 教程中使用的 Flower 模型:
https://threejs.org/examples/webgl_instancing_scatter.html
花型是这样的:
可以从这里下载:https://github.com/mrdoob/three.js/tree/master/examples/models/gltf/Flower)
到目前为止,我已经能够成功地将模型加载到我的项目中,而且我还能够将不同的颜色应用于它的“花朵”网格——但只能是纯色。
我想应用 渐变 颜色。
为了说明我的想法,我在 photoshop 中制作了一张非常简单的图像,它可能看起来像:
我尝试使用 vertexColors
技术来做到这一点 - 这是我知道的唯一技术(我对 THREE.js 还很陌生) - 到目前为止运气不好(下面的代码。)
在这一点上,我的一部分人想知道这是否可以用导入的 GLTF 模型来做 - 或者这是否是一个失败的原因。
会喜欢一些 input/help。
这是我的代码 - 分为两部分:第一部分用于纯色 - 有效,第二部分是我尝试应用渐变色 - 但无效:
// NOTE: I stored the already imported GLTF model in a new Mesh called “blossomMesh”
// 1. Create a new Group to which I’ll add the Stem and Blossom:
var newFlower = new THREE.Group();
// 2. CLONE the MESH of the imported 3D model:
let newBlossomMesh = blossomMesh.clone();
// 3. CLONE it's GEOMETRY:
var newBlossomGeometry = blossomMesh.geometry.clone();
// 4. CLONE it's MATERIAL:
var newBlossomMaterial = blossomMesh.material.clone();
// 5. MAKE a NEW COLOR:
let newBlossomColor = new THREE.Color(generateRandomColor());
newBlossomMaterial.color = newBlossomColor;
newBlossomMesh.material = newBlossomMaterial;
newFlower.add(newBlossomMesh);
newFlower.add(newStemMesh);
scene.add(newFlower);
所以以上适用于纯色。
这是我试图让渐变颜色继续下去的方法:
// THE BLOSSOM:
// 1. CLONE the MESH of the imported 3D model:
let newBlossomMesh = blossomMesh.clone();
// 2. This time use a BufferGeometry to CLONE the GEOMETRY:
var newBlossomGeometry = new THREE.BufferGeometry();
newBlossomGeometry = blossomMesh.geometry.clone();
var blossomVertexPositionsArray = newBlossomGeometry.attributes.position;
newBlossomGeometry = newBlossomGeometry.toNonIndexed();
blossomVertexPositionsArray = newBlossomGeometry.attributes.position;
// Make a Colors Array:
var blossomColorsArray = [];
const newBlossomColor = new THREE.Color();
for(var i = 0, l = blossomVertexPositionsArray.count; i < l; i ++) {
newBlossomColor.setHSL(Math.random() * 0.2 + 0.05, 0.95, 0.799);
blossomColorsArray.push(newBlossomColor.r, newBlossomColor.g, newBlossomColor.b);
}
// Now “splash” the "blossomColorsArray" all over the Blossom:
newBlossomGeometry.setAttribute("color", new THREE.Float32BufferAttribute(blossomColorsArray, 3));
newBlossomMesh.material = newBlossomMaterial;
newFlower.add(newBlossomMesh);
newFlower.add(newStemMesh);
scene.add(newFlower);
我得到的是黑色的花朵。它基本上看起来只是没有任何颜色,所以我看到的黑色更像是没有颜色,而不是实际颜色“黑色”。
============================================= ===
更新:
好的,所以它在工作 - 但只是“单独”,而且只是“本地”。
我的意思是:我想制作的不仅仅是一个花卉对象,而是 100 个。而且我不想在 GLTFLoader
的回调函数中这样做,因为我需要将各种其他逻辑应用于我的 100 个花对象(比如给它们 (x, y, z) 坐标,给它们userData
值,将它们添加到数组等。因此,出于这个原因,我创建了一个单独的函数来处理所有这些工作,我的策略是:
- 像我们一直做的那样使用
GLTFLoader
加载Flower.glb
模型,一旦加载成功......
- 调用我的另一个函数,循环创建这朵花的 500 个新实例,每个实例都有自己独特的花朵渐变颜色、x、y、z、坐标等。
你的代码工作得很好,但我试图让它在多个 Blossom 对象上工作,并在 GLTFLoader
函数的回调之外进行。正是后一部分让我抓狂。
这是我的代码:
(目前的结果是,我的 500 朵花中的每朵花都得到了完全相同的灰色——而且没有渐变;它们只是不起作用。)
var blossomMesh;
var stemMesh;
function load3DFlowerModel() {
loader.load("./Flower.glb", function(theFlower) {
flowerScene = theFlower.scene;
// Assign values to my global "blossomMesh" and "stemMesh" variables:
blossomMesh = flowerScene.children[0]; // Blossom
stemMesh = flowerScene.children[1]; // Stem
// Now call my external function:
makeFlowers();
});
}
function makeFlowers() {
for(var flowerCount = 0; flowerCount < TOTAL_FLOWERS; flowerCount ++) {
var newFlowerGroup = new THREE.Group();
// I. THE BLOSSOM:
// 1. First, make a new copy of the incoming global "blossomMesh" object:
var newBlossomMesh = blossomMesh.clone();
// 2. Next, make a new copy of the MATERIAL of the incoming global "blossomMesh" object:
var newBlossomMaterial = blossomMesh.material.clone();
// 3. Now make a new copy of the GEOMETRY of the incoming global "blossomMesh" object:
var newBlossomGeometry = blossomMesh.geometry.clone();
// 4. Get its vertices:
let blossomVertexPositionsArray = newBlossomGeometry.attributes.position;
// 5. Make Colors for it:
var blossomColorsArray = [];
var newBlossomColor = new THREE.Color();
for(var i = 0; i < blossomVertexPositionsArray.count; i ++) {
newBlossomColor.setHSL(Math.random() * 0.2 + 0.05, 0.95, 0.799);
blossomColorsArray.push(newBlossomColor.r, newBlossomColor.g, newBlossomColor.b);
}
// 6. Finally SPLASH the "blossomColorsArray" all over the Blossom's Geometry:
newBlossomGeometry.setAttribute("color", new THREE.Float32BufferAttribute(blossomColorsArray, 3));
// And set "vertexColors" to true:
newBlossomMaterial.vertexColors = true;
// II. THE STEM
let newStemMesh = stemMesh.clone();
newStemMesh.castShadow = true;
newTulipGroup.add(newStemMesh);
newTulipGroup.add(newBlossomMesh);
newTulipGroup.name = "Tulip#" + tulipCount;
// etc.
所以我得到了一大束花,但它们都有相同的灰色花朵。它总是灰色的...
按预期工作。为场景添加灯光,设置 vertexColors: true
为 material。
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import {GLTFLoader} from "https://threejs.org/examples/jsm/loaders/GLTFLoader.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 10);
camera.position.set(0, 5, 5);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
scene.add(new THREE.GridHelper());
let loader = new GLTFLoader();
loader.load("https://threejs.org/examples/models/gltf/Flower/Flower.glb", gltf => {
let model = gltf.scene;
model.scale.setScalar(10);
//console.log(model);
let g = model.children[0].geometry;
let m = model.children[0].material;
let p = g.attributes.position;
let c = new THREE.Color();
let colors = [];
for(let i = 0; i < p.count; i++){
c.set(Math.random() < 0.5 ? 0xff00ff : 0xffff00);
colors.push(c.r, c.g, c.b);
}
g.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
m.vertexColors = true;
scene.add(model);
});
renderer.setAnimationLoop( _ => {
renderer.render(scene, camera);
});
</script>
我一直在尝试将渐变颜色应用于此官方 THREE.js 教程中使用的 Flower 模型:
https://threejs.org/examples/webgl_instancing_scatter.html
花型是这样的:
可以从这里下载:https://github.com/mrdoob/three.js/tree/master/examples/models/gltf/Flower)
到目前为止,我已经能够成功地将模型加载到我的项目中,而且我还能够将不同的颜色应用于它的“花朵”网格——但只能是纯色。
我想应用 渐变 颜色。
为了说明我的想法,我在 photoshop 中制作了一张非常简单的图像,它可能看起来像:
我尝试使用 vertexColors
技术来做到这一点 - 这是我知道的唯一技术(我对 THREE.js 还很陌生) - 到目前为止运气不好(下面的代码。)
在这一点上,我的一部分人想知道这是否可以用导入的 GLTF 模型来做 - 或者这是否是一个失败的原因。
会喜欢一些 input/help。
这是我的代码 - 分为两部分:第一部分用于纯色 - 有效,第二部分是我尝试应用渐变色 - 但无效:
// NOTE: I stored the already imported GLTF model in a new Mesh called “blossomMesh”
// 1. Create a new Group to which I’ll add the Stem and Blossom:
var newFlower = new THREE.Group();
// 2. CLONE the MESH of the imported 3D model:
let newBlossomMesh = blossomMesh.clone();
// 3. CLONE it's GEOMETRY:
var newBlossomGeometry = blossomMesh.geometry.clone();
// 4. CLONE it's MATERIAL:
var newBlossomMaterial = blossomMesh.material.clone();
// 5. MAKE a NEW COLOR:
let newBlossomColor = new THREE.Color(generateRandomColor());
newBlossomMaterial.color = newBlossomColor;
newBlossomMesh.material = newBlossomMaterial;
newFlower.add(newBlossomMesh);
newFlower.add(newStemMesh);
scene.add(newFlower);
所以以上适用于纯色。
这是我试图让渐变颜色继续下去的方法:
// THE BLOSSOM:
// 1. CLONE the MESH of the imported 3D model:
let newBlossomMesh = blossomMesh.clone();
// 2. This time use a BufferGeometry to CLONE the GEOMETRY:
var newBlossomGeometry = new THREE.BufferGeometry();
newBlossomGeometry = blossomMesh.geometry.clone();
var blossomVertexPositionsArray = newBlossomGeometry.attributes.position;
newBlossomGeometry = newBlossomGeometry.toNonIndexed();
blossomVertexPositionsArray = newBlossomGeometry.attributes.position;
// Make a Colors Array:
var blossomColorsArray = [];
const newBlossomColor = new THREE.Color();
for(var i = 0, l = blossomVertexPositionsArray.count; i < l; i ++) {
newBlossomColor.setHSL(Math.random() * 0.2 + 0.05, 0.95, 0.799);
blossomColorsArray.push(newBlossomColor.r, newBlossomColor.g, newBlossomColor.b);
}
// Now “splash” the "blossomColorsArray" all over the Blossom:
newBlossomGeometry.setAttribute("color", new THREE.Float32BufferAttribute(blossomColorsArray, 3));
newBlossomMesh.material = newBlossomMaterial;
newFlower.add(newBlossomMesh);
newFlower.add(newStemMesh);
scene.add(newFlower);
我得到的是黑色的花朵。它基本上看起来只是没有任何颜色,所以我看到的黑色更像是没有颜色,而不是实际颜色“黑色”。
============================================= ===
更新:
好的,所以它在工作 - 但只是“单独”,而且只是“本地”。
我的意思是:我想制作的不仅仅是一个花卉对象,而是 100 个。而且我不想在 GLTFLoader
的回调函数中这样做,因为我需要将各种其他逻辑应用于我的 100 个花对象(比如给它们 (x, y, z) 坐标,给它们userData
值,将它们添加到数组等。因此,出于这个原因,我创建了一个单独的函数来处理所有这些工作,我的策略是:
- 像我们一直做的那样使用
GLTFLoader
加载Flower.glb
模型,一旦加载成功...... - 调用我的另一个函数,循环创建这朵花的 500 个新实例,每个实例都有自己独特的花朵渐变颜色、x、y、z、坐标等。
你的代码工作得很好,但我试图让它在多个 Blossom 对象上工作,并在 GLTFLoader
函数的回调之外进行。正是后一部分让我抓狂。
这是我的代码:
(目前的结果是,我的 500 朵花中的每朵花都得到了完全相同的灰色——而且没有渐变;它们只是不起作用。)
var blossomMesh;
var stemMesh;
function load3DFlowerModel() {
loader.load("./Flower.glb", function(theFlower) {
flowerScene = theFlower.scene;
// Assign values to my global "blossomMesh" and "stemMesh" variables:
blossomMesh = flowerScene.children[0]; // Blossom
stemMesh = flowerScene.children[1]; // Stem
// Now call my external function:
makeFlowers();
});
}
function makeFlowers() {
for(var flowerCount = 0; flowerCount < TOTAL_FLOWERS; flowerCount ++) {
var newFlowerGroup = new THREE.Group();
// I. THE BLOSSOM:
// 1. First, make a new copy of the incoming global "blossomMesh" object:
var newBlossomMesh = blossomMesh.clone();
// 2. Next, make a new copy of the MATERIAL of the incoming global "blossomMesh" object:
var newBlossomMaterial = blossomMesh.material.clone();
// 3. Now make a new copy of the GEOMETRY of the incoming global "blossomMesh" object:
var newBlossomGeometry = blossomMesh.geometry.clone();
// 4. Get its vertices:
let blossomVertexPositionsArray = newBlossomGeometry.attributes.position;
// 5. Make Colors for it:
var blossomColorsArray = [];
var newBlossomColor = new THREE.Color();
for(var i = 0; i < blossomVertexPositionsArray.count; i ++) {
newBlossomColor.setHSL(Math.random() * 0.2 + 0.05, 0.95, 0.799);
blossomColorsArray.push(newBlossomColor.r, newBlossomColor.g, newBlossomColor.b);
}
// 6. Finally SPLASH the "blossomColorsArray" all over the Blossom's Geometry:
newBlossomGeometry.setAttribute("color", new THREE.Float32BufferAttribute(blossomColorsArray, 3));
// And set "vertexColors" to true:
newBlossomMaterial.vertexColors = true;
// II. THE STEM
let newStemMesh = stemMesh.clone();
newStemMesh.castShadow = true;
newTulipGroup.add(newStemMesh);
newTulipGroup.add(newBlossomMesh);
newTulipGroup.name = "Tulip#" + tulipCount;
// etc.
所以我得到了一大束花,但它们都有相同的灰色花朵。它总是灰色的...
按预期工作。为场景添加灯光,设置 vertexColors: true
为 material。
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import {GLTFLoader} from "https://threejs.org/examples/jsm/loaders/GLTFLoader.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 10);
camera.position.set(0, 5, 5);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
scene.add(new THREE.GridHelper());
let loader = new GLTFLoader();
loader.load("https://threejs.org/examples/models/gltf/Flower/Flower.glb", gltf => {
let model = gltf.scene;
model.scale.setScalar(10);
//console.log(model);
let g = model.children[0].geometry;
let m = model.children[0].material;
let p = g.attributes.position;
let c = new THREE.Color();
let colors = [];
for(let i = 0; i < p.count; i++){
c.set(Math.random() < 0.5 ? 0xff00ff : 0xffff00);
colors.push(c.r, c.g, c.b);
}
g.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
m.vertexColors = true;
scene.add(model);
});
renderer.setAnimationLoop( _ => {
renderer.render(scene, camera);
});
</script>