# How to color specific part of Model

**URL:** <https://community.cesium.com/t/how-to-color-specific-part-of-model/14898>\
**Category:** CesiumJS\
**Created:** [August 18, 2021, 5:44pm UTC](https://community.cesium.com/t/how-to-color-specific-part-of-model/14898 "2021-08-18T17:44:38Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![tealminivan](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/tealminivan/32/5967_2.png) [@tealminivan](https://community.cesium.com/u/tealminivan)\
**Post date:** [August 18, 2021, 5:44pm UTC](https://community.cesium.com/t/how-to-color-specific-part-of-model/14898/1 "2021-08-18T17:44:38Z")

</div>

Hi all!  
I imported this ship model as a glTF Model and have implemented the model coloring feature from the sandcastle showcases. While the whole ship is able to change colors, I want to change the color of the gun of the ship specifically. I would also like to have the gun be a separate clickable entity. I’m not exactly sure how to achieve this with CesiumJS. Thanks in advance!

Here is the image of the gun of the ship:

 ![Screenshot 2021-08-18 134047](https://global.discourse-cdn.com/cesium/original/2X/e/e401961de438fe510c2f04b1d62f4bec57fc73e2.png)

Here is the sandcastle implementation that I’m working with: [link](https://sandcastle.cesium.com/#c=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)

---

<div class="post-metadata">

**Author:** ![sam.rothstein](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/sam.rothstein/32/6584_2.png) [@sam.rothstein](https://community.cesium.com/u/sam.rothstein)\
**Post date:** [August 19, 2021, 5:03pm UTC](https://community.cesium.com/t/how-to-color-specific-part-of-model/14898/2 "2021-08-19T17:03:24Z")

</div>

@tealminivan

Thank you for sharing such a cool sandcastle demo! Your use-case seems very interesting 😀

I am sharing your question with the rest of the development team at Cesium. I will get back to you with an answer to your questions shorty.

-Sam

---

<div class="post-metadata">

**Author:** ![sam.rothstein](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/sam.rothstein/32/6584_2.png) [@sam.rothstein](https://community.cesium.com/u/sam.rothstein)\
**Post date:** [August 19, 2021, 5:54pm UTC](https://community.cesium.com/t/how-to-color-specific-part-of-model/14898/3 "2021-08-19T17:54:12Z")

</div>

@tealminivan

Individual nodes in a `glTF` model **are** pickable. However, the `glTF` model must be created with the primitive API. This sandcastle demo showcases how this can be done.

> **[Cesium Sandcastle](https://sandcastle.cesium.com/#c=1VdZbxs3EP4rhB6CVSpTko+k9RFU9ZEUiGHBUv3Qqgjo3ZGWMJdckFzZbuD/3iG5lyTLqYsWRQXDWnKub4bfzFJLpsmSwz1ockIk3JNTMLzI6I3fi2ad2K9PlbSMS9CzTo98nUlCTKoKkYwkz5iFQ2J1ATP51D2ayZlcolMTgwT0GZxTvzwKokwlILzivJCx5UqSWAO6uXSCqNCiR1Lgi9S6b5ZwueiRnNs47RGthOgGBEEFQ5SQE5izQtgbJgqIKvsBHThMpHK0Vb0MU+v7eFu0Syy1rgO1RdWJWpou/TRfq/WnEHzsvF6jfvRs0r5gwYPSfMFlE/GUaYtPTO7RuVbZGSw0gImcOiE7w909Oni/v/9u+EMvbO3v08HBYO/94F25EarlnhuY/pQumdX8oYk01UyaudKZoeka6qm64A+QXGiWQRk64Kxi5LoK4L69e3TsiUFzzTNu+RIMZUlSmpcxPSt8Yh+FnUdfg5AQ5Mmh+9erNlqID9uLRoEjXYtsjDjFhP+BtB3ufl9Kn7ob6CiSMnkcY2BuIGhRm4KMatpGXq/ko/v0+2Qs2CNhMiFCqZwwZAbzTYL6hjBLUibmOyYHSFZwUxa7/Ee1rivECMlQ+0ZFpBXPBQd9iJQ66DUSF+twpWC1o88ootfn4/PRtDZ4qvJ0H3fYMR6aZk27hnVLCRP7VamMWBXgrhjjcHAU9TMknKfBhgY5yVkMp97Vaa1z1DZFiyaJXTogb5slHl5KM/YQikxvVSEd4SZ5ChqoRvYVplciR3oUxmLuEpju1iEaZLQ8e5fEGTeWydhNJ03eukquVwOk9clUBfU02qdl/R9/ehwrLm3UOhkP8TnOVbI1+CFES6s1D5p2jrqVQnelbBvDzNfKqmvcxgaNdvfqiVOZrM2zNYOd3RWDsqjIqrtRO82XUK9MMSYXsDnGsNh4xhs5PZU7VGF36XtstlaHgdZKtzrsnstE3VOGZ2pLYe0GH56q90+KLSjW32qThpbnS8zlU1CKAmljhpbGeSmNqQH7s8wLO/JgVvp+CRk6KIGFAsd3zTzDRa1EQSZjZbgzDWD5nKzOOHxn4Ns1iZxdl7x5s1VIJbLpZY0MTBqGWVU1bN6rwmIeZCGmF8S58BPKaRKkJZYJK49ELQzQYIKdY5QApMCiPv9Zx1ke4jf5jtRgqESy4MasQ73DttytvTy4CMnjET31tp3I9DEHenn1y+T8y+XVzXmYU/1/7lPRQ+VhIJ+Q3xymslAWHqzDP+I61mxu8bZTvsmkAQExChsOtEgZerK8jhwMBthMW/p1XfJyWw432nj1qvGNLm5dqpqWxXOiffybsCwXcMYs6/sJZfrBKeZePn3BR7oQt3UVmqvCykbo8mYntHuzdpg3et7Lw/+14p9pJeFvVX548H8uvM+7/fwf1P6jdq8pcgMpj8VfPoTX5huilEFWVyHnVyC+5OKOTHUR3/1baMOJuDg+zPr61Ygnd1zisCanKdN46fO/qV4P/Ftwmay6GB8Dxk1sv/vxOsF3QcyMxerjnXOqlLhl+hJkEZVT0hl2ep1jYx8FfKjg/MizXGnrruARIrGASBCf6d9iVcDS2Jgq4nG/bXqc8CXhyckzPy5JLJgxKJkXwl/RZ50Px33U3zAVylP/agkaL9xOLR1++Bw2KaXHfVw+b2lDgmue/wQ)**
>
> The Cesium Sandcastle provides an interactive environment for testing Cesium code.

Note that when you use your mouse to select the propeller, we see the following output in the console.

`node: Prop__2_. mesh: Prop`

While individual nodes in a `glTF` model are pickable, you **cannot** change the color of individual nodes in a `glTF` model. For more information on changing node colors, check out the following issue.

> <https://github.com/CesiumGS/cesium/issues/2387>
>
> Is there a way of changing the material linked to a primitive in a ModelMesh cre…ated from a glTF model?
> 
> The goal is to highlight the picked node by changing the material's parameters but \`ModelMaterial.selValue\` is applied over every primitive linked to that material. I think that the best solution is to temporary link the primitive to a special 'highlight' material but it does not have any effect over the rendered model. Maybe there is a better solution to solve the problem so I am open to suggestions!
> 
> Thanks!

Your desired functionality is possible with 3D Tiles. Unfortunately, our model tiler does not generate 3D Tilesets that have pickable features. Thus, I can’t really recommend using Cesium ion for this use case.

Sadly there is not a great workaround for you at the moment. I could not think of a quick and easy solution. You may be able to achieve your desired functionality using custom shaders.

> <https://github.com/CesiumGS/cesium/pull/9725>
>
> WIP experimental implementation of custom shaders for \`ModelExperimental\` Openin…g the PR early for feedback and so I can take notes on things that need to be changed.
> 
> Description last updated: 2021-08-16: 13:45 EDT
> 
> \## Overview
> 
> This is the core functionality of #9518, though there will be additional PRs in the future to add the metadata capabilities.
> 
> Custom shaders allows creating custom vertex and fragment shader code that can be applied anywhere a Model (for now, \`ModelExperimental\`) is used.
> 
> Note that this PR only implements the basic implementation. A future PR will add metadata to custom shaders, though this requires more architecture elsewhere in \`ModelExperimental\`-related classes.
> 
> There are two ways to try this feature right now:
> \* Load a tileset that uses .glb tiles via \`3DTILES\_content\_gltf\`. This requires \`Cesium.ExperimentalFeatures.enableModelExperimental \`. B3DM and other tile types are not supported yet, we've only wired up \`ModelExperimental\` to \`Gltf3DTileContent\` so far.
> \* Load a GLB or GLTF file via \`ModelExperimental.fromGltf()\`
> 
> \## Sandcastle Examples
> 
> EDIT 2021-08-25: Due to recent changes the following examples won't work without a small tweak to the vertex shader, the new signature should be:
> 
> \`\`\`glsl
> void vertexMain(VertexInput vsInput, inout vec3 position) {
> }
> \`\`\`
> 
> \* \[Simple example of tinting the baseColor texture\](http://cesium-dev.s3-website-us-east-1.amazonaws.com/cesium/model-experimental-custom-shaders/Apps/Sandcastle/index.html#c=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) (Updated 2021-08-16 13:40) -- this shows how the \`MODIFY\_MATERIAL\` mode can be used to update the textures 
> !\[image\](https://user-images.githubusercontent.com/8422414/129224784-69045bc2-7fea-40ea-9882-38381911bd2b.png)
> \* \[PBR Shading the Ocean\](http://cesium-dev.s3-website-us-east-1.amazonaws.com/cesium/model-experimental-custom-shaders/Apps/Sandcastle/index.html#c=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) (Updated 2021-08-16 13:40) -- this demonstrates how you can set the PBR properties properties like \`material.specular\` or \`material.roughness\`.
> !\[image\](https://user-images.githubusercontent.com/8422414/129224420-49286456-31ed-4c63-8738-0bd25e33a81c.png)
> \* \[Custom glTF attributes example\](http://cesium-dev.s3-website-us-east-1.amazonaws.com/cesium/model-experimental-custom-shaders/Apps/Sandcastle/index.html#c=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) (Updated 2021-08-16 13:40) -- in this case I made a model with a custom attribute \`\_BARYCENTRIC\_COORDS\`. This is accessible via \`fsInput.attributes.barycentric\_coords\`.
> !\[image\](https://user-images.githubusercontent.com/8422414/129225043-2f7abd61-f058-4d41-8f62-b49d24ee414a.png)
> \* \[Custom varyings\](http://cesium-dev.s3-website-us-east-1.amazonaws.com/cesium/model-experimental-custom-shaders/Apps/Sandcastle/index.html#c=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) (Updated 2021-08-16 13:45) -- this example shows how to define additional varyings, set them in the custom vertex shader and use them in the custom fragment shader.
> !\[image\](https://user-images.githubusercontent.com/8422414/129225966-08d57115-7154-4f83-b138-3aef707bf2f6.png)
> 
> \## \`CustomShader\` Documentation
> 
> \>Update 2021-08-23: The latest documentation for custom shaders is now in a \[README file\] on this branch. It is temporarily in \`Source/Scene/ModelExperimental/CustomShaderGuide/\` for now while this feature is experimental. 
> 
> CustomShader is a bit involved, so here's how it gets used. This may become the start of a user guide for custom shader, so I'll keep updating this as I update the PR.
> 
> Constructor:
> 
> \`\`\`js
> var customShader = new Cesium.CustomShader({
> // Any custom uniforms the user wants to add to the shader.
> // these can be changed at runtime via customShader.setUniform()
> uniforms: {
> u\_time: {
> value: 0, // initial value
> type: UniformType.FLOAT
> },
> }
> // custom varyings that will appear in the custom vertex and fragment shader text.
> // the user is responsible for setting these in the vertex shader and using them
> // in the fragment shader.
> varyings: {
> v\_customTexCoords: VaryingType.VEC2
> }, // optional
> // configure where in the fragment shader's materials/lighting pipeline the 
> // custom shader goes. More on this below. 
> mode: Cesium.CustomShaderMode.MODIFY\_MATERIAL,
> // either PBR (physically-based rendering) or UNLIT depending on the desired
> // results.
> lightingModel: Cesium.LightingModel.PBR,
> // Custom vertex shader. Right now this is a function from model space -\> model space.
> // VertexInput will be documented below
> // NOTE: which coordinate system is used here may change (e.g. could become model -\> view space
> vertexShaderText: \`
> vec3 vertexMain(VertexInput vsInput, vec3 position) {
> // code goes here. e.g. for a no-op:
> return position;
> }
> \`,
> // Custom fragment shader. 
> // FragmentInput will be documented below
> // Regardless of the mode, this always takes in a material and modifies it in place.
> fragmentShaderText: \`
> void fragmentMain(FragmentInput fsInput, inout czm\_modelMaterial material) {
> // code goes here. e.g. to set the diffuse color to solid red:
> material.diffuse = vec3(1.0, 0.0, 0.0);
> }
> \`,
> });
> \`\`\`
> 
> \### Custom Shader Modes
> 
> EDIT 2021-08-16: I removed \`BEFORE\_MATERIAL\` and \`AFTER\_LIGHTING\` to simplify the interface.
> 
> NOTE: the list of modes is subject to change. We might decide to make further simplifications.
> 
> The custom fragment shader is configurable so it can go before/after materials or lighting. here's a summary of what
> modes are available.
> 
> | Mode | Fragment shader pipeline | Description |
> |---------| -----------------------------------|----------------|
> | \`MODIFY\_MATERIAL\` (default) | material -\> custom shader -\> lighting | The custom shader modifies the results of the material stage |
> | \`REPLACE\_MATERIAL\` | custom shader -\> lighting | Don't run the material stage at all, but procedurally generate it in the custom shader |
> 
> In the above, "material" does preprocessing of glTF textures, resulting in a \`czm\_modelMaterial\`. This is mostly relevant for PBR, but even for UNLIT, the base color texture is handled.
> 
> \### \`VertexInput\` struct
> 
> An automatically-generated GLSL struct that contains glTF attributes. In the future we may add automatic fields. in a future PR, metadata will be added.
> 
> Right now an example struct looks like this:
> 
> \`\`\`glsl
> // this struct represents the raw attribute values.
> struct Attributes {
> // required semantics
> vec3 position; // model space position. always present as glTF POSITION is required
>     
> // optional semantics (added depending on what's in the glTF)
> vec3 normal; // glTF NORMAL
> vec3 tangent;
> vec3 texCoord\_0;
> // etc.
>     
> // custom attribues
> vec3 custom\_attribute; // corresponds to glTF attribute \_CUSTOM\_ATTRIBUTE
> };
> 
> struct VertexInput {
> // raw attribute values
> Attributes attributes;
> // in the future we may add another struct for derived attributes (e.g. positionEC)
> };
> \`\`\`
> 
> \### \`FragmentInput\` struct
> 
> This struct is similar to \`VertexInput\`, but there are a few more variables for positions in various coordinate spaces.
> 
> \`\`\`glsl
> // this struct represents the raw glTF attributes. The varyings required to make this work are handled
> // automatically. 
> struct Attributes {
> // required semantics
> vec3 position; // Raw model space position. always present as glTF POSITION is required
>     
> // optional semantics (added depending on what's in the glTF)
> vec3 normal; // glTF NORMAL
> vec3 tangent;
> vec3 texCoord\_0;
> // etc.
>     
> // custom attribues
> vec3 custom\_attribute; // corresponds to glTF attribute \_CUSTOM\_ATTRIBUTE
> };
> 
> struct FragmentInput {
> // raw glTF attribute values interpolated (but not normalized) from varyings.
> Attributes attributes;
> vec3 positionMC; // model space
> vec3 positionWC; // World coords (ECEF). Low precision.
> vec3 positionEC; // Eye coordinates
> };
> \`\`\`
> 
> \### \`czm\_modelMaterial\` struct
> 
> This one is a built-in, see the \[documentation comment\](https://github.com/CesiumGS/cesium/blob/model-experimental-custom-shaders/Source/Shaders/Builtin/Structs/modelMaterial.glsl). This is similar to \`czm\_material\` from the old Fabric system, but slightly different fields as this one supports PBR lighting.
> 
> This struct serves as the basic input/output of the fragment shader pipeline stages. For example:
> 
> \* the material stage produces a material
> \* the lighting stage takes in a material, computes lighting, and stores the result into \`material.diffuse\`
> \* Custom shaders (regardless of where in the pipeline it is) takes in a material (even if it's a material with default values) and modifies this.
> 
> \## To Do:
> 
> \- \[x\] Document usage more thoroughly in this PR description
> \- \[x\] Add development sandcastle
> \- \[x\] Where should documentation go?
> \- \[x\] Add unit tests - the basic regiment of tests are implemented, I'm trying to keep them updated in each commit.
> \- \[x\] uniform and varying types should be enums, not raw strings
> \- \[x\] \`uniform sampler2D\`s should be added. This requires some resource management, as the custom shader will need to fetch images and create \`Texture\` objects
> \- \[x\] Discussion: if we allow texture samplers should we also allow cubemap samplers? though this should go beyond the scope of this PR. (see https://github.com/CesiumGS/cesium/issues/9741)
> \- \[x\] Consider adding a built-in uniform for implicit tile coordinates (when \`3DTILES\_implicit\_tiling\` is used) EDIT: We're holding off on this, I opened #9736 to track this feature.
> \- \[x\] Discuss whether the custom vertex shader should be in model space, view space, or some other space. Right now it's a callback that goes from model -\> model space.
> \- \[x\] Implement various reference frames (model, cartesian, cartographic, and view space) EDIT: cartographic will have to wait. Opened https://github.com/CesiumGS/cesium/issues/9735 for this.
> \- \[x\] Discuss the shader modes more with @lilleyse and @sanjeetsuhag about the shader modes. We're considering changing the list of them. For example, instead of \`AFTER\_LIGHTING\`, we could just have an optional \`afterLighting\` GLSL callback. This way you could both modify the material \_and\_ post-process the lighting EDIT: We decided to skip this for now
> \- \[x\] handle heterogenous data: what if a tileset has multiple types of models, some with normals, some without? This should output a warning and a sensible default should be used.
> \- \[x\] Update unit tests. Recent changes added new classes and significantly changed the behavior of \`CustomShaderStage\`

However, we are still developing this technology and I am not 100% confident that it can be used for this purpose. @sean_lilley posted some thoughts and suggestions on the following issue.

> <https://github.com/CesiumGS/cesium/issues/9728#issuecomment-902111268>
>
> Custom Shaders (issue #9518 and initial implementation #9725) allows applying us…er-defined vertex and fragment shaders to glTF models as well as 3D Tiles. This is new behavior, as the old materials system was not compatible with 3D Tiles.
> 
> While the implementation is still a work in progress, we still want to gather ideas of what exciting things will be possible with this new feature.
> 
> Here are a few ideas we've seen already, though more are welcome!
> 
> \* glTF supports storing \[application-specific semantics\](https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes) (custom vertex attributes). For example, a mesh could have \`\_TEMPERATURE\`. Custom shaders provides a method to access these values and use them in the shader
> \* (requires glTF \`EXT\_feature\_metadata\`) Make a tileset that includes simple polygons with metadata labeling them as "grass" or "building" etc. Then use custom shaders to procedurally apply textures
> \* A user could apply a mask/tint to areas of imagery data in more nuanced ways than with styling. This will be even more useful once \`EXT\_feature\_metadata\` is available and the shader can use metadata to mask where the shading should be applied.
> \* If we include cartographic WGS84 coordinates (caveat: 32-bit precision limitations on the GPU) you could easily overlay a lat/lon grid over 3D tiles.
> \* @srothst1 had a couple interesting ideas for visualization:
> \* Weather visualizations on a tileset with terrain/imagery. For example, maybe visualize wildfires or other extreme weather events in the news. This would probably be a good use case for \`EXT\_feature\_metadata\` feature textures or feature ID textures.
> \* We talked about how you might represent \[The Valley Curtain\](https://christojeanneclaude.net/artworks/valley-curtain/) in CesiumJS. While certainly you could do something simple with a glTF and animations alone, with a custom vertex shader you could simulate the curtain flowing in the breeze (perhaps with procedural noise or something)
> 
> Thanks to @mramato and @srothst1 and others for some of the above ideas.
> 
> @mramato mentioned a couple more ideas in slack, could you expand on them in more detail here?

I recommend checking this out. Let me know if you have any other questions or comments!

-Sam
