Skip to content

Commit

Permalink
Read pixels using webgl renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
gkjohnson committed May 5, 2024
1 parent cd443ee commit 356c3fd
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 24 deletions.
10 changes: 5 additions & 5 deletions example/gltfExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { GLFTMeshFeatures } from '../src/three/extensions/GLTFMeshFeatures.js';
import { GLTFMeshFeaturesExtension } from '../src/three/gltf/GLTFMeshFeaturesExtension.js';

let camera, controls, scene, renderer;
let dirLight;
Expand All @@ -29,7 +29,7 @@ function init() {
document.body.appendChild( renderer.domElement );

camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
camera.position.set( 400, 400, 400 );
camera.position.set( 4, 4, 4 );

// controls
controls = new OrbitControls( camera, renderer.domElement );
Expand All @@ -45,16 +45,16 @@ function init() {
scene.add( ambLight );

new GLTFLoader()
.register( parser => new GLFTMeshFeatures( parser ) )
.register( parser => new GLTFMeshFeaturesExtension( parser ) )
// .loadAsync( 'https://raw.githubusercontent.com/CesiumGS/3d-tiles-samples/main/glTF/EXT_mesh_features/FeatureIdAttribute/FeatureIdAttribute.gltf' )
.loadAsync( 'https://raw.githubusercontent.com/CesiumGS/3d-tiles-samples/main/glTF/EXT_mesh_features/FeatureIdTexture/FeatureIdTexture.gltf' )

.then( res => {

console.log( res );

// console.log( res );
// scene.add( res.scene );
scene.add( res.scene );
console.log( res.scene )

Check failure on line 57 in example/gltfExample.js

View workflow job for this annotation

GitHub Actions / build (16.x)

Missing semicolon

} );

Expand Down
96 changes: 77 additions & 19 deletions src/three/gltf/MeshFeatures.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
import { Vector2 } from 'three';
import { ShaderMaterial, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer } from 'three';

Check warning on line 1 in src/three/gltf/MeshFeatures.js

View workflow job for this annotation

GitHub Actions / build (16.x)

'Vector3' is defined but never used
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';

const _canvas = document.createElement( 'canvas', {
alpha: true,
colorSpace: 'srgb',
willReadFrequently: true,
} );
_canvas.height = 1;
_canvas.width = 1;
const _renderer = new WebGLRenderer();
const _quad = new FullScreenQuad( new ShaderMaterial( {
uniforms: {

const _ctx = _canvas.getContext( '2d' );
_ctx.imageSmoothingEnabled = false;
map: { value: null },
pixel: { value: new Vector2() }

},

vertexShader: /* glsl */`
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,

fragmentShader: /* glsl */`
uniform sampler2D map;
uniform ivec2 pixel;
void main() {
gl_FragColor = texelFetch( map, pixel, 0 );
}
`,

} ) );

const _uv = new Vector2();
const _vec2_0 = new Vector2();
const _vec2_1 = new Vector2();
const _vec2_2 = new Vector2();
const _currentScissor = new Vector4();
const _pixel = new Vector2();
const _dstPixel = new Vector2();
const _target = new WebGLRenderTarget();

function getTextureCoordAttribute( geometry, index ) {

Expand All @@ -30,6 +54,29 @@ function getTextureCoordAttribute( geometry, index ) {

}

function renderPixelToTarget( texture, pixel, dstPixel, target ) {

_quad.material.uniforms.map.value = texture;
_quad.material.uniforms.pixel.value.copy( pixel );

const currentTarget = _renderer.getRenderTarget();
const currentScissorTest = _renderer.getScissorTest();
_renderer.getScissor( _currentScissor );

_renderer.setScissorTest( true );
_renderer.setScissor( dstPixel.x, dstPixel.y, 1, 1 );

_renderer.setRenderTarget( target );
_quad.render( _renderer );

_renderer.setScissorTest( currentScissorTest );
_renderer.setScissor( _currentScissor );
_renderer.setRenderTarget( currentTarget );

texture.dispose();

}

export class MeshFeatures {

constructor( geometry, textures, data ) {
Expand All @@ -46,14 +93,21 @@ export class MeshFeatures {

}

getFeatures( triangle, barycoord ) {
// getFeaturesAsync( triangle, barycoord ) {

// TODO: handle async read back to avoid blocking
// TODO: requires async read back

// }

getFeatures( triangle, barycoord, ) {

const { geometry, textures, data } = this;
const { featureIds } = data;
const result = new Array( featureIds.length ).fill( null );

// prep the canvas width
_canvas.width = Math.max( _canvas.width, data.featureIds.length );
_target.setSize( Math.max( _target.width, data.featureIds.length ), 1 );

for ( let i = 0, l = featureIds.length; i < l; i ++ ) {

Expand Down Expand Up @@ -91,10 +145,13 @@ export class MeshFeatures {

const fx = _uv.x - Math.floor( _uv.x );
const fy = _uv.y - Math.floor( _uv.y );
const px = ( fx * width ) % width;
const py = ( fy * height ) % height;
const px = Math.floor( ( fx * width ) % width );
const py = Math.floor( ( fy * height ) % height );

_pixel.set( px, py );
_dstPixel.set( i, 0 );

_ctx.drawImage( image, px, py, 1, 1, i, 0, 1, 1 );
renderPixelToTarget( textures[ featureId.texture.index ], _pixel, _dstPixel, _target );

} else if ( 'attribute' in featureId ) {

Expand Down Expand Up @@ -128,10 +185,11 @@ export class MeshFeatures {

}

// TODO: make sure this works for alpha and color space does not
const imageData = _ctx.getImageData( 0, 0, featureIds.length, 1 );
// TODO: remove this allocation
const buffer = new Uint8Array( _target.width * 4 );
_renderer.readRenderTargetPixels( _target, 0, 0, _target.width, 1, buffer );

// get data based on the texture informatino
// get data based on the texture information
for ( let i = 0, l = featureIds.length; i < l; i ++ ) {

const featureId = featureIds[ i ];
Expand All @@ -143,7 +201,7 @@ export class MeshFeatures {

channels.forEach( ( c, index ) => {

const byte = imageData.data[ 4 * i + c ];
const byte = buffer[ 4 * i + c ];
const shift = index * 8;
value = value | ( byte << shift );

Expand Down

0 comments on commit 356c3fd

Please sign in to comment.