Closed mkraessig closed 8 years ago
Until I implement a nice function to get it, for now,
In your component that will contain React3
, you can add a ref
like so:
<React3 ref="react3" ...other properties here ...>
This way, for example within componentDidMount
:
console.log(react3.refs.canvas.userData.markup.childrenMarkup[0].threeObject._renderer);
should print the renderer.
I am thinking of adding a prop e.g. onRendererCreated
or something to React3
.
Totally suffices for now! Thank you so much, @toxicFork!
This may be another issue, but I still can't seem to get the Stereo Effect to work. Have you ever tried that or do you know on the spot whether something like that's even possible with react-three-renderer?
Hmm... http://threejs.org/examples/js/effects/StereoEffect.js doesn't look very complicated, I can add support for stereoCamera, or you can try to duplicate it by combining it with https://github.com/mrdoob/three.js/blob/master/src/cameras/StereoCamera.js
I will add support for StereoCamera
anyway, as well as onRendererCreated
:)
Perfect, thanks! Yup, should be pretty straightforward - I kinda missed StereoCamera there ;) Thanks a bunch!
In v0.1.0 now :) Please reopen if there are any issues!
Please bare with as I am brand new ThreeJS. We've got react-three-renderer working GREAT!
We're now just trying to dive into post processing and running into a few issues. First, when looking into the post processing examples on Threejs.org, all the examples directly edit the global Three object when they want to implement a module. Additionally, those examples have a ton of tiny libs/objects/modules that do not seem to be part of any npm package.
We are trying to use three-effectcomposer with react-three-renderer and we're not getting any errors, just a warning, and there is no noticiable change to the render.
here is our code:
import './scss/ParticleScene.scss';
import React from 'react';
import React3 from 'react-three-renderer';
import THREE from 'three';
import ReactDOM from 'react-dom';
import TweenLite from 'gsap';
import BinaryLoader from '../../utils/BinaryLoader.js';
import Particle from '../Particle/Particle.jsx';
import ParticleField from '../ParticleField/ParticleField.jsx';
import textureImage from './textures/UV_Grid_Sm.jpg';
import cellModel from './objects/stemcell2/stemCell_lp.json';
import cellTexture from './objects/stemcell2/stemCell_lp-TM_AO_u0_v0.jpg';
import cellNormalMap from './objects/stemcell2/stemCell_lp-NM_u0_v0.jpg';
import cellDisplacmentMap from './objects/stemcell2/stemCell_lp-DM1024_8bit_u0_v0.jpg';
import cellAOMap from './objects/stemcell2/stemCell_lp-AO_u0_v0.jpg';
const EffectComposer = require('three-effectcomposer')(THREE);
THREE.DotScreenShader = {
uniforms: {
"tDiffuse": { type: "t", value: null },
"tSize": { type: "v2", value: new THREE.Vector2( 256, 256 ) },
"center": { type: "v2", value: new THREE.Vector2( 0.5, 0.5 ) },
"angle": { type: "f", value: 1.57 },
"scale": { type: "f", value: 1.0 }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform vec2 center;",
"uniform float angle;",
"uniform float scale;",
"uniform vec2 tSize;",
"uniform sampler2D tDiffuse;",
"varying vec2 vUv;",
"float pattern() {",
"float s = sin( angle ), c = cos( angle );",
"vec2 tex = vUv * tSize - center;",
"vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;",
"return ( sin( point.x ) * sin( point.y ) ) * 4.0;",
"}",
"void main() {",
"vec4 color = texture2D( tDiffuse, vUv );",
"float average = ( color.r + color.g + color.b ) / 3.0;",
"gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );",
"}"
].join("\n")
};
THREE.RGBShiftShader = {
uniforms: {
"tDiffuse": { type: "t", value: null },
"amount": { type: "f", value: 0.005 },
"angle": { type: "f", value: 0.0 }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform sampler2D tDiffuse;",
"uniform float amount;",
"uniform float angle;",
"varying vec2 vUv;",
"void main() {",
"vec2 offset = amount * vec2( cos(angle), sin(angle));",
"vec4 cr = texture2D(tDiffuse, vUv + offset);",
"vec4 cga = texture2D(tDiffuse, vUv);",
"vec4 cb = texture2D(tDiffuse, vUv - offset);",
"gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);",
"}"
].join("\n")
};
export default class ParticleScene extends React.Component {
constructor(props, context) {
super(props, context);
// SCENE POSITION
this.scenePosition = new THREE.Vector3(0, 0, 0);
// construct the position vector here, because if we use 'new' within render,
// React will think that things have changed when they have not.
this.cameraPosition = new THREE.Vector3(0, 0, 5);
this.cameraRotation = new THREE.Euler(0, 0, 90 * Math.PI / 180);
// LIGHT POSITION
this.directionalLightPosition = new THREE.Vector3(0, 1, 0);
//PARTICLE POSITION
this.particlePosition = new THREE.Vector3(0, 0, 4);
// FOG SETUP
this.fog = new THREE.Fog(0x4994c8, 0, 10);
//Mesh Geometry
this.cellGeometry = this.parseMeshFromJSON(cellModel);
this.state = {
viewerWidth : window.innerWidth,
viewerHeight : window.innerHeight
};
this._onAnimate = this._onAnimate.bind(this);
this._handleWindowResize = this._handleWindowResize.bind(this);
this._handleRenderUpdated = this._handleRenderUpdated.bind(this);
}
// Native Functions
// -----------------
componentDidMount() {
window.addEventListener('resize', this._handleWindowResize, false);
this.refs.meshPhongMaterial.normalMap = this.loadTexture(cellNormalMap);
this.refs.meshPhongMaterial.displacementMap = this.loadTexture(cellDisplacmentMap);
this.refs.meshPhongMaterial.displacementBias = 2;
// this.refs.meshPhongMaterial.wireframe = true;
this.refs.meshPhongMaterial.displacementScale = 0.4;
this.refs.meshPhongMaterial.aoMap = this.loadTexture(cellAOMap);
// Post-Processing
this.composer = new EffectComposer(this.renderer);
this.composer.addPass(new EffectComposer.RenderPass(this.refs.mainScene, this.refs.mainCamera));
// Redraw with a shader
const effect = new EffectComposer.ShaderPass(THREE.DotScreenShader);
this.composer.addPass(effect);
// And another shader, drawing to the screen at this point
const effect2 = new EffectComposer.ShaderPass(THREE.RGBShiftShader);
effect2.renderToScreen = true;
this.composer.addPass(effect2);
}
componentWillUnmount() {
window.removeEventListener('resize', this._handleWindowResize, false);
}
// Custom Functions
// -----------------
_onAnimate() {
// we will get this callback every frame
this.refs.CellParticlesClose.update();
this.refs.CellParticlesSuperClose.update();
this.refs.CellParticlesMed.update();
this.refs.CellParticlesFar.update();
this.composer.render();
};
// <--- Removed code for brevity
_handleRenderUpdated(renderer) {
if(renderer !== null) {
console.log(renderer instanceof THREE.WebGLRenderer); // true
this.renderer = renderer;
} else {
// renderer is just destroyed or will be recreated soon
}
}
// <--- Removed code for brevity
render() {
const {
viewerWidth,
viewerHeight
} = this.state;
return (<div className="ParticleScene"><React3
mainCamera="mainCamera" // this points to the perspectiveCamera which has the name set to "camera" below
width={viewerWidth}
height={viewerHeight}
antialias = {true}
onAnimate={this._onAnimate}
clearColor={this.fog.color}
ref="react3"
onRendererUpdated={this._handleRenderUpdated}
>
<resources>
<geometry
resourceId="cellGeometry"
{...this.cellGeometry}
/>
<texture
resourceId="cellTexture"
url={cellTexture}
/>
<meshPhongMaterial
resourceId="cellMaterial"
ref="meshPhongMaterial"
>
<textureResource
resourceId="cellTexture"
/>
</meshPhongMaterial>
<sphereGeometry
resourceId="particleGeometry"
radius={0.1}
widthSegments={20}
heightSegments={20}
/>
<sphereGeometry
resourceId="particleGeometrySmall"
radius={0.0001}
widthSegments={50}
heightSegments={50}
/>
<sphereGeometry
resourceId="particleGeometryLow"
radius={0.1}
widthSegments={10}
heightSegments={10}
/>
<texture
resourceId="texture"
url={textureImage}
wrapS={THREE.RepeatWrapping}
wrapT={THREE.RepeatWrapping}
anisotropy={16}
/>
<meshLambertMaterial
resourceId="particleMaterial"
side={THREE.DoubleSide}
>
<textureResource
resourceId="texture"
/>
</meshLambertMaterial>
</resources>
<scene
fog={this.fog}
ref="mainScene"
>
<perspectiveCamera
name="mainCamera"
fov={75}
aspect={viewerWidth / viewerHeight}
near={0.1}
far={1000}
position={this.cameraPosition}
rotation={this.cameraRotation}
ref="mainCamera"
/>
<ambientLight
color={0x404040}
/>
<directionalLight
color={0xffffff}
position={this.directionalLightPosition}
lookAt={this.scenePosition}
/>
<ParticleField
numberOfParticles = {3}
particleFieldRadius = {5}
particleFieldCenter = {this.particlePosition}
particleScale = {0.1}
particleGeometryResourceId = "particleGeometry"
particleMaterialResourceId = "cellMaterial"
ref = "CellParticlesSuperClose"
/>
<ParticleField
numberOfParticles = {20}
particleFieldRadius = {5}
particleFieldCenter = {this.cameraPosition}
particleScale = {1}
particleGeometryResourceId = "particleGeometry"
particleMaterialResourceId = "particleMaterial"
ref = "CellParticlesClose"
/>
<ParticleField
numberOfParticles = {50}
particleFieldRadius = {10}
particleFieldCenter = {this.cameraPosition}
particleScale = {1}
particleGeometryResourceId = "particleGeometryLow"
particleMaterialResourceId = "particleMaterial"
ref = "CellParticlesMed"
/>
<ParticleField
numberOfParticles = {300}
particleFieldRadius = {50}
particleFieldCenter = {this.cameraPosition}
particleScale = {1}
particleGeometryResourceId = "particleGeometryLow"
particleMaterialResourceId = "particleMaterial"
ref = "CellParticlesFar"
/>
</scene>
</React3></div>);
}
}
Hi,
have you found any solution? I've got the same issue.
Thanks
@FredHasselot does https://github.com/toxicFork/react-three-renderer/wiki/react3#onrendererupdated work for your problem? If not we can improve it :)
@iDVB apologies I thought I had responded but it seems the response didn't go through github...
It looks like it should work but it's hard to guess what may have gone wrong without stepping into the code unfortunately
Hi,
I tried to add : composer.render(); after a list of effects on the onRenderUpdated event function.
something like:
onRendererUpdated={this.renderedUpdated.bind(this)}
on the React3 tag
then something like:
renderedUpdated(r3nderer) {
composer = new THREE.EffectComposer( r3nderer);
composer.addPass( new THREE.RenderPass( this.refs.scene, this.refs.mainCamera ) );
let dotScreenEffect = new THREE.ShaderPass( THREE.DotScreenShader );
dotScreenEffect.uniforms[ 'scale' ].value = 4;
composer.addPass( dotScreenEffect );
let rgbEffect = new THREE.ShaderPass( THREE.RGBShiftShader );
rgbEffect.uniforms[ 'amount' ].value = 0.0015;
rgbEffect.renderToScreen = true;
composer.addPass( rgbEffect );
composer.render()
}
But this.refs.scene and this.refs.mainCamera were undefined if i remember... So i did something similar on the componentDidMount event and later i tried on the update function as well. without success.
I read, somewhere on the EffectComposer documentation, that the render have to be done this way : composer.render() and not this way : renderer.render() maybe the issue is related to that?
If you do the binding within render function it may get called repeatedly, and in some cases the r3nderer variable will be undefined (for example when a canvas needs to be re-created)
Yes composer.render sounds better, but still if you can provide an example that I can run, it will be easier to look at what's going on :)
Has anybody had any luck getting post-processing working with an EffectComposer? We're trying to implement an object "outline" feature, and it seems like the best way to do it is with EventComposer post-processing.
I've tried putting the composer in a few places, but haven't had any luck yet. Any info about successfully using an EventComposer with this library would be very appreciated.
Yes @oortlieb -- after reading this thread and doing a little digging, I got this working, applying the shader examples provided by iDVB as a test case. (Cool effect btw @iDVB )
I will provide a walkthrough of my steps here to help anyone who stumbles across this and is in a similar predicament. Be warned however that this is a little hacky and very dependent on the specific "internal" variable arrangement of r3r types, which is very prone to change as it continues to develop -- so if your version doesn't match mine (3.2.4), you may need to do some digging in the source and make some adjustments. (At least until a clean API is provided for this case, s'il vous plaît @toxicFork )
I hooked up React3
in the following manner for reference:
<React3 ref={react3 => (this.react3 = react3) }
Then, in componentDidMount()
, after creating this.composer
, I added the following line:
this.react3._canvas.userData.markup.childrenMarkup[0].threeObject._renderScene = camera => { this.composer.render(); }
This effectively replaces what would be a call to WebGLRenderer.renderScene()
with a call to EffectComposer.render()
-- the fundamental otherwise missing step to get this post-process effect working.
I arrived at this from starting from toxicFork's comment https://github.com/toxicFork/react-three-renderer/issues/27#issuecomment-185429288. I ran a text search through the source for react-three-renderer
and found where .render
is called -- which is only in React3Instance.js
, in the one call _renderScene()
(which makes it easy).
Note that this effectively skips some debug logic which looks like it shows some overlaid highlight scene for non-production builds; in my case I don't care about this. Ideally though r3r would provide some hook to override (or add another layer of processing) around the render
call (which would I think be all that is necessary to support this).
Hi there!
I am trying to implement the Stereo Effect, but as an argument it takes the renderer. Is there any way I can pass the Three.WebGLRenderer used to the StereoEffect function?
Thanks so much! — Maxi