# Vertex colors with lighting info

**URL:** <https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690>\
**Category:** Questions\
**Tags:** lighting, vertex-colors\
**Created:** [March 31, 2026, 9:01am UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690 "2026-03-31T09:01:06Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![yesbird](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/yesbird/32/46097_2.png) [@yesbird](https://discourse.threejs.org/u/yesbird)\
**Post date:** [March 31, 2026, 9:01am UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/1 "2026-03-31T09:01:06Z")

</div>

Greetings !

I am working on implementation of a custom external renderer and would like to update vertex colors according to present lighting (Gouraud method will be fine for the start) and save this information to file. Is it possible to fetch the color info from existing shader (material) and bake it to vertex colors somehow ?

---

<div class="post-metadata">

**Author:** ![Umbawa\_Sarosong](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/umbawa_sarosong/32/30107_2.png) [@Umbawa\_Sarosong](https://discourse.threejs.org/u/Umbawa_Sarosong)\
**Post date:** [March 31, 2026, 10:39am UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/2 "2026-03-31T10:39:59Z")

</div>

Short answer: not directly.

In three.js, lighting is computed in the shader on the GPU at render time. The material doesn’t store “final colors” per vertex anywhere you can just read back on the CPU, so you can’t simply fetch baked Gouraud colors from an existing material.

If you want vertex colors that include lighting, you have a couple of options:

1. Recompute on the CPU  
You can mimic the lighting calculations yourself in JavaScript. Loop through the geometry vertices, evaluate your lights (directional, point, etc.), normals, and material properties, then write the result into a color attribute. This is basically doing Gouraud shading manually on the CPU.

2. Custom shader + readback  
Modify or replace the material with a custom shader that outputs the lighting result per vertex (passed to fragment). Then render to a render target and read pixels back. The tricky part is mapping pixels back to vertices cleanly, so this is not as straightforward as it sounds.

3. GPU baking approach  
Render the mesh in a way where each vertex maps to a known pixel (for example using a special UV or ID encoding), output the computed lighting, and read that back. This is more advanced but closer to an actual “bake”.

If your goal is just Gouraud-style vertex colors, the CPU route is usually the simplest starting point. You already have access to geometry attributes and light data in three.js, so you can approximate what the built-in shaders are doing without fighting the GPU readback limitations.

---

<div class="post-metadata">

**Author:** ![yesbird](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/yesbird/32/46097_2.png) [@yesbird](https://discourse.threejs.org/u/yesbird)\
**Post date:** [March 31, 2026, 10:53am UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/3 "2026-03-31T10:53:31Z")

</div>

Thanks so much for your suggestions, I thought about all these approaches before writing the post, but they will take too much time and effort. Maybe I will choose a shader-based way if do not find a workaround.

---

<div class="post-metadata">

**Author:** ![donmccurdy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/donmccurdy/32/33209_2.png) [@donmccurdy](https://discourse.threejs.org/u/donmccurdy)\
**Post date:** [March 31, 2026, 12:36pm UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/4 "2026-03-31T12:36:23Z")

</div>

It’s no longer part of three.js, but you could start with MeshGouraudMaterial, which was removed here:

> <https://github.com/mrdoob/three.js/pull/32572>
>
> Related issue: #32569
> 
> \*\*Description\*\*
> 
> More code removal.

The Gouraud materials implements per-vertex Lambertian shading. You would still need to add a way to read back the per-vertex data, perhaps with Transform Feedback.

---

<div class="post-metadata">

**Author:** ![yesbird](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/yesbird/32/46097_2.png) [@yesbird](https://discourse.threejs.org/u/yesbird)\
**Post date:** [March 31, 2026, 1:34pm UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/5 "2026-03-31T13:34:47Z")

</div>

Many thanks !  
Transform feedback is very close to what I am looking for:

> <https://github.com/mrdoob/three.js/issues/14416>
>
> I'm working on implementing transform feedback support on top of the \[WebGLRende…rer to WebGL2 proposal\](https://github.com/mrdoob/three.js/pull/13717).
> 
> I would like to get some feedback from the community about the following two approaches:
> 
> 1) We'll have something like \`THREE.TransformFeedback\` and we will call it with a \`BufferGeometry\` and a \`Program\`:
> \`\`\`javascript
> var geometry = new THREE.BufferGeometry();
> var program = // A program with out varyings
> var tf = new THREE.TransformFeedback(geometry, program);
> 
> ...
> renderLoop() {
> tf.tick(); 
> scene.render();
> }
> 
> THREE.TransformFeedback.prototype.tick = function () {
> bindBuffersAndAttribs();
> gl.enable(gl.RASTERIZER\_DISCARD);
> bindTransformFeedback(this.transformFeedback);
> drawCall(currentGeometry, transformFeedbackProgram);
> gl.disable(gl.RASTERIZER\_DISCARD);
> unbindBuffersAndAttribs();
> }
> \`\`\`
> The constructor will create a copy of the buffergeometry that will then be used on \`tick\` to pingpong between these two geometries.
> As you can spot, we're calling \`RASTERIZER\_DISCARD\` as we don't want to draw anything, we just want to do the computation stored on the program and save the values back to a buffer that will be used later to paint the geometry.
> An example of this approach is the \[WebGL2Particles\](https://github.com/toji/webgl2-particles-2) demo by @toji 
> The key point here is that we're performing \[first the computation\](https://github.com/toji/webgl2-particles-2/blob/gh-pages/index.html#L621-L626) using a \[specific shader\](https://github.com/toji/webgl2-particles-2/blob/gh-pages/js/SimulationShader.js) and we use these computed attributes to \[render the geometry\](https://github.com/toji/webgl2-particles-2/blob/gh-pages/index.html#L641) using a https://github.com/toji/webgl2-particles-2/blob/gh-pages/index.html#L55-L74 unrelated to the transformfeedback. 
> 
> 2) The second approach will be to integrate it on the pipeline. So we could have a material definition like:
> \`\`\`javascript
> var materialWithTF = new THREE.ShaderMaterial( {
> uniforms: {...},
> vertexShader: document.getElementById( 'vs' ).textContent,
> fragmentShader: document.getElementById( 'fs' ).textContent
> transformFeedbackVaryings: \['outPosition', 'outVelocity'\]
> });
> \`\`\`
> Or we could use injection points for standard materials (Sorry I don't remember the current state on this @mrdoob @pailhead, but you get the point):
> \`\`\`javascript
> var materialWithTF = new THREE.StandardMaterial( {
> transformFeedbackVaryings: \['outPosition', 'outVelocity'\],
> preVertex: 'out vec3 outPosition; out vec3 outVelocity;',
> vertexMain: 'outPosition = position + velocity \* delta; outVelocity \*= acceleration;',
> });
> \`\`\`
> So the renderer and the related modules should take the transformFeedback attributes into account and generate the buffers, doing the pingpong (this could be defined on the material too), binding the tf and the attributes.
> With this second approach we don't separate the computation from the actual rendering as we just do it in one pass.
> An example of this implementation can be found here on the \[WebGL2Samples\](https://github.com/WebGLSamples/WebGL2Samples/blob/master/samples/transform\_feedback\_separated\_2.html#L270-L287) Where with just one \[drawcall you compute and render at the same time\](https://github.com/WebGLSamples/WebGL2Samples/blob/master/samples/transform\_feedback\_separated\_2.html#L270-L287) using just \[one program\](https://github.com/WebGLSamples/WebGL2Samples/blob/master/samples/transform\_feedback\_separated\_2.html#L21-L84)
> 
> 
> \---
> 
> \- I'm not sure if there's a huge overhead between option (1) or (2). Although until we won't have multiview support on three.js, (1) will do just one call to compute the new attributes while on (2) we will call twice one per each eye, as the usual drawcalls.
> \- I'd like to know if people would like to have the option (1) without rendering anything after, so just to do some gpgpu, or if it's a good idea to have both for two specific use cases.

Will try to follow this way …

---

<div class="post-metadata">

**Author:** ![donmccurdy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/donmccurdy/32/33209_2.png) [@donmccurdy](https://discourse.threejs.org/u/donmccurdy)\
**Post date:** [March 31, 2026, 4:28pm UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/6 "2026-03-31T16:28:15Z")

</div>

I don’t think it’s supported yet (or doesn’t have an example at least…) but another idea to keep an eye on would be:

> <https://github.com/gkjohnson/three-gpu-pathtracer/issues/5>
>
> \*\*UV Unwrapping\*\*
> 
> \- Update, test UV Unwrapper on sample model using xatlas. \[…UVUnwrapper\](https://github.com/gkjohnson/three-gpu-pathtracing/blob/main/src/utils/UVUnwrapper.js), from \[Mozilla Spoke code\](https://github.com/mozilla/Spoke/commit/9701d647020e09d584885bd457eb225e9995c12f)
> 
> \*\*Lightmap Generation\*\*
> 1. Optionally generate a UV map
> 2. Adjust the path tracing shader to project into UV space rather than world space.
> 3. Flood the texture gaps (use mip maps?)
> 4. Apply to model

---

<div class="post-metadata">

**Author:** ![yesbird](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/yesbird/32/46097_2.png) [@yesbird](https://discourse.threejs.org/u/yesbird)\
**Post date:** [March 31, 2026, 6:00pm UTC](https://discourse.threejs.org/t/vertex-colors-with-lighting-info/90690/7 "2026-03-31T18:00:09Z")

</div>

Thanks for this idea. I’ve seen it before, but did not consider it in the context of this task - I need to explore it in detail, probably this is a solution. I will get back to this question in a few days after completing the present, less challenged project ).
