{"_id":"5a06037234873d0010b39249","category":{"_id":"5a06037134873d0010b39202","version":"5a06037134873d0010b391fe","project":"578c4badbd223d2000cc1441","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-07-18T21:08:45.730Z","from_sync":false,"order":3,"slug":"develop","title":"Develop"},"parentDoc":null,"project":"578c4badbd223d2000cc1441","user":"578c4a62bd223d2000cc143e","version":{"_id":"5a06037134873d0010b391fe","project":"578c4badbd223d2000cc1441","__v":1,"createdAt":"2017-11-10T19:52:17.163Z","releaseDate":"2017-11-10T19:52:17.163Z","categories":["5a06037134873d0010b391ff","5a06037134873d0010b39200","5a06037134873d0010b39201","5a06037134873d0010b39202","5a06037134873d0010b39203","5a06037134873d0010b39204"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"2.1.0","version":"2.1.0"},"__v":0,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-07-18T19:33:45.498Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":8,"body":"You illuminate scenes in Viro by adding lights to your ```<ViroNode>``` objects. For example, in the scene below, a grey spotlight and a blue ambient light illuminate a 3D object.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<ViroScene>\\n  <ViroOrbitCamera position={[0, 0, -0]} focalPoint={[0, 0, -1.15]} />\\n  <ViroSpotLight position={[0, -0.25, 0]}\\n                 color=\\\"#777777\\\"\\n                 direction={[0, 0, -1]}\\n                 attenuationStartDistance={5}\\n                 attenuationEndDistance={10}\\n                 innerAngle={5}\\n                 outerAngle={20}/>\\n\\n  <ViroAmbientLight color=\\\"#FF0000\\\" />\\n\\n  <Viro3DObject source={require('./res/heart.obj')}\\n                position={[-0.0, -5.5, -1.15]}\\n                materials={[\\\"heart\\\"]} />\\n</ViroScene>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe impact of a light's illumination on a component is determined by two things: the light's properties, and the component's materials. This guide covers both [lights](#light-types) and [materials](#materials). \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Constant Lighting\"\n}\n[/block]\nFor basic scenes with only UI elements and a background (```<Viro360Image>``` or ```<ViroSkybox>```), lights can effectively be ignored. By default, all elements use *Constant* lighting. Components with Constant lighting ignore the lights in the scene altogether; they are displayed in full color.\n\nTo apply lighting, one or more [lights](#light-types) must be added to the scene, *and* the [lighting models](#lighting-models) of the components you want to respond to light must be set. The next few sections go into more detail.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Materials\"\n}\n[/block]\nFor more advanced scenes, we use lights and materials to control the illumination of objects.\n\nMaterials are the set of shading attributes that define the appearance of a geometry's surface when rendered. Each object in a scene can be assigned one or more materials. All UI elements, and most basic 3D models, utilize only one material. Complex 3D objects, represented by ```<Viro3DObject>```, can have multiple materials, one for each defined mesh surface in the 3D object.\n\nMaterials are assigned via the object's ```materials``` property. The following is a simple example:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<Viro3DObject source={require('./res/heart.obj')}\\n                      position={[-0.0, -5.5, -1.15]}\\n                      materials={[\\\"heart\\\"]} />\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe material itself is then defined as follows:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"ViroMaterials.createMaterials({\\n  heart: {\\n     lightingModel: \\\"Blinn\\\",\\n     diffuseTexture: require('./res/Heart_D3.jpg'),\\n     specularTexture: require('./res/Heart_S2.jpg'),\\n   },\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe following material properties determine how a material is rendered in light:\n\n* ```diffuseTexture``` and ```diffuseColor```: describe the color of light reflected equally in all directions from the material’s surface. The diffuse property of a pixel is independent of the point of view, so it can be thought of as a material’s “base” color or texture. The diffuse property be set as a texture (via ```diffuseTexture```), and/or as a uniform color (via ```diffuseColor```). If both are set, the two will be multiplied together at each pixel.\n\n* ```specularTexture```: describes the color of light reflected by the material directly toward the viewer. The specular color forms a bright highlight on the surface, simulating a glossy or shiny appearance. \n\n* ```shininess```: describes the sharpness of specular highlights. Ranges from 0 to 1.\n\n* ```lightingModel```: defines how material properties and the lights in the scene are combined to create the color for each pixel on the material's surface. Set to one of ```Constant```, ```Lambert```, ```Phong```, or ```Blinn```. See the next section for details.\n\n* ```normalTexture```: defines the orientation of the surface at each point for use in lighting. Viro treats the R, G, and B components of each pixel in the normal map as the X, Y, and Z components of a surface normal vector. Normal maps are often used to simulate rough surfaces or to add details to otherwise smooth surfaces.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Lighting Models\"\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/678338b-viro_lighting_models.jpg\",\n        \"viro_lighting_models.jpg\",\n        754,\n        201,\n        \"#93086f\"\n      ]\n    }\n  ]\n}\n[/block]\nViro supports four traditional lighting models: ```Constant```, ```Lambert```, ```Phong```, or ```Blinn```. Each of these lighting models defines a formula for combining a material’s diffuse and specular properties with the lights in the scene and the point of view, to create the color of each rendered pixel.\n\nIn the examples below, ```diffuseMaterial``` refers to either the material's ```diffuseTexture``` or ```diffuseColor```, whichever is defined. If both are defined it refers to the material's ```diffuseTexture``` multiplied by its ```diffuseColor```.\n\n## Constant\n\nThe ```diffuseMaterial``` wholly determines the color of the surface. Lights are ignored.\n\n```color = diffuseMaterial```\n\n## Lambert\n\nLambert’s Law of diffuse reflectance determines the color of the surface. The formula is as follows:\n\n```color = (∑ambientLight + ∑diffuseLight) * diffuseMaterial```\n\n```∑ambientLight```: the sum of all ambient lights in the scene, as contributed by ```ViroAmbientLight``` objects\n\n```∑diffuseLight```: the sum of each non-ambient light's diffuse contribution. Each light's contribution is defined as follows\n\n```diffuseLight = max(0, dot(N, L))```\n\nwhere N is the surface normal vector at the point being shaded, and L is the normalized vector from the point being shaded to the light source.\n\n## Phong\n\nThe Phong approximation of real-world reflectance adds a specular contribution to the calculation:\n\n```color = (∑ambientLight + ∑diffuseLight) * diffuseMaterial + ∑specularLight * specularTexture```\n\n```∑specularLight```: the sum of each non-ambient light's specular contribution. Each light's specular contribution is defined as follows\n\n```specularLight = pow(max(0, dot(R, E)), shininess)```\n\nwhere E is the normalized vector from the point being shaded to the viewer, R is the reflection of the light vector L across the normal vector N, and shininess is the value of the material's shininess property.\n\n## Blinn\n\nThe Blinn-Phong approximation of real-world reflectance is similar to Phong, but uses a different formula for the specular contribution\n\n```specularLight = pow(max(0, dot(H, N)), shininess)```\n\nwhere H is the vector halfway between the light vector L and the eye vector E, and shininess is the value of the material's shininess property.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Light Types\"\n}\n[/block]\nThe lighting models above determine how a set of lights impact a surface. The influence of a given light is also determined by the properties of the lights *themselves.* Light properties determine things like the directionality of the light, the color of the light, and how the light impacts objects over a distance. Viro supports four light types.\n\n# Ambient Light\n```<ViroAmbientLight>``` illuminates all objects in the view (and its subviews) with equal intensity from all directions. Only the ```color``` of am ambient light needs to be set.\n\n# Directional Light\n```<ViroDirectionalLight>``` represents a light source with uniform direction and constant intensity. The sun is a canonical example of a directional light. Directional lights have a ```color``` property and a ```direction``` property.\n\n# Omni Light\n```<ViroOmniLight>``` is a light source that casts light in all directions from a given position. Omni lights have a ```color``` property and a ```position``` property. Additionally, the illumination of an omni light can attenuate over distance. This attenuation is controlled by the ```attenuationStartDistance``` and ```attenuationEndDistance``` properties.\n\n# Spot Light\n```<ViroSpotLight>``` is a light source that illuminates a cone-shaped area determined by its ```position``` and ```direction```. The color of the spot light is determined by its ```color``` property. The edges of the cone are controlled by ```innerAngle```, the angle at which the cone begins to fade, and ```outerAngle```, the angle at which the cone has faded completely. Additionally, spot lights, like omni lights, can also attenuate with distance. This is controlled via the ```attenuationStartDistance``` and ```attenuationEndDistance``` properties.\n[block:api-header]\n{\n  \"title\": \"Shadows\"\n}\n[/block]\nViro renders shadows through shadow mapping, a technique where the silhouettes of objects are rendered to an image, and that image is then reprojected onto the screen. Viro will generate shadows for all lights that have their ```castsShadow``` property set to true.\n\nShadows are particularly important for AR, in that they provide a visual cue about what real-world surface a virtual object is resting on. However, because casting shadows involves re-rendering the scene multiple times, they do incur a performance cost.\n\nShadows are only supported for directional and spot lights. The following snippet shows how to create a spotlight that casts shadows:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<ViroScene>\\n  <ViroSpotLight position={[0, -0.25, 0]}\\n                 color=\\\"#777777\\\"\\n                 direction={[0, 0, -1]}\\n                 attenuationStartDistance={5}\\n                 attenuationEndDistance={10}\\n                 innerAngle={5}\\n                 outerAngle={20}\\n                 castsShadow={true} />\\n</ViroScene>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThere are a multitude of parameters that can be tuned for shadow maps. Most of these involve a tradeoff between performance and quality. The ```shadowMapSize``` parameter, in particular, controls the resolution of the shadow map. Increasing this value yields a higher resolution shadow at a higher performance cost. Decreasing this value results in lower resolution shadows (pixelated at the edges) but higher performance. In general it is best to keep this value as power of 2. The deafult is 1024.\n\nThe other key determinant of shadow quality is the shadow *frustum*. For a spotlight, this is essentially the cone of the light. It is determined by the spotlight's ```innerAngle``` and ```outerAngle```, and by the ```shadowNearZ``` and ```shadowFarZ```. The smaller the cone, the better the shadow quality. If the cone is too large, the shadows will become pixelated. The ```shadowNearZ``` and ```shadowFarZ``` parameters determine the extent of the cone in the direction of the light. Tightening these together as well will improve the precision of the shadow. For more detail on these parameters, see the [ViroSpotLight](doc:virospotlight1) reference.\n\nFor directional lights, shadows have some additional parameters. Directional lights have no position --- they are ubiquitous -- so in theory they should cast shadows on all objects in the scene. However, doing so would be prohibitively expensive, so Viro requires that we choose an area for the directional light to cast shadows. To do this, set the ```shadowOrthographicPosition``` property to the *center* of the shadowed region, and set the ```shadowOrthographicSize``` property to the size of the shadowed region (specifically, this sets the shadow region's width and height). Finally, the ```shadowNearZ``` and ```shadowFarZ``` parameters should be set as well. Again, the tighter the shadow region, the higher resolution the shadows will appear. The following example shows a directional light casting shadows over a 10x10 meter area, 5 meters away from the origin in the Z direction.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<ViroScene>\\n  <ViroDirectionalLight color=\\\"#FFFFFF\\\"\\n                        direction={[0, -1, 0]}\\n                        shadowOrthographicPosition={[0, 3, -5]}\\n                        shadowOrthographicSize={10}\\n                        shadowNearZ={2}\\n                        shadowFarZ={9}\\n                        castsShadow={true} />\\n\\n  <ViroBox position={[-1, 2, -5]}\\n           width={0.5} height={0.5}\\n           materials={[\\\"grid\\\"]} />\\n\\n  <ViroBox position={[1, -1, -5]}\\n           width={0.5} height={0.5}\\n           materials={[\\\"grid\\\"]} />\\n\\n  <ViroSurface position={[0, -2, -3]}\\n               rotation={[-90, 0, 0]}\\n               width={20} height={20}\\n               materials={[\\\"grid\\\"]} />\\n</ViroScene>\\n               \\n...\\n\\nViroMaterials.createMaterials({\\n  grid: {\\n    diffuseTexture: require('./res/grid_bg.jpg'),\\n    lightingModel: \\\"Lambert\\\",\\n  },\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/f20be77-IMG_4168.PNG\",\n        \"IMG_4168.PNG\",\n        1334,\n        750,\n        \"#ab7e8a\"\n      ]\n    }\n  ]\n}\n[/block]\nIn the scene depicted above, the directional light casts shadows onto the horizontal ```<ViroSurface>```. Note, however, that  the directional light will *only* cast a shadow for the second box. The first box does not cast a shadow because it's not within the shadow region. The shadow region in this example ranges from -5 to 5 on the X axis and 0 to -10 along the Z axis (determined by ```shadowOrthographicPosition```, ```direction```, and ```shadowOrthographicSize```), and +1 to -6 in the Y direction (determined by ```shadowOrthographicPosition```, ```direction```, ```shadowNearZ```, and ```shadowFarZ```). Specifically, the first box is cut off from the shadow region by ```shadowNearZ```.\n\nNote that shadows are:\n1. Only *cast by* objects within the shadow region.\n2. Only *rendered on* objects within the shadow region. \n[block:api-header]\n{\n  \"title\": \"AR Shadow Surfaces\"\n}\n[/block]\nWhen rendering in augmented reality, it's common to want to render shadows onto *real world* surfaces. To do this, we have to specify the position of the surface we want to render the shadows onto, and set its ```arShadowReceiver``` property to true. To ensure the surface we're rendering onto truly does correspond to a real-world surface, typically we place the surface within a ```<ViroARPlaneSelector>``` or similar component, as shown below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<ViroARScene>\\n  <ViroARPlaneSelector>\\n    <ViroSpotLight\\n            innerAngle={5}\\n            outerAngle={25}\\n            direction={[0, -1, -.2]}\\n            position={[0, 3, 1]}\\n            color=\\\"#ffffff\\\"\\n            castsShadow={true}\\n            shadowMapSize={2048}\\n            shadowNearZ={2}\\n            shadowFarZ={5}\\n            shadowOpacity={.7} />\\n\\n    <Viro3DObject\\n      source={require('./res/pug.vrx')}\\n      position={[0, 0, 0]}\\n      scale={[.2, .2, .2]}\\n      type=\\\"VRX\\\" />\\n\\n    <ViroSurface\\n      position={[0, 0, 0]}\\n      rotation={[-90, 0, 0]}\\n      width={4} height={4}\\n      arShadowReceiver={true} />\\n</ViroARPlaneSelector>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/e41a235-IMG_4169.JPG\",\n        \"IMG_4169.JPG\",\n        750,\n        1334,\n        \"#7a6c68\"\n      ]\n    }\n  ]\n}\n[/block]\nIn the scene above the ```<ViroSurface>``` will be coincident with the detected horizontal plane, and will have no \"virtual\" appearance; it simply designates a real-world surface on which virtual shadows should be rendered. The spotlight will cast a shadow of the ```<Viro3DObject>``` onto this surface.\n[block:api-header]\n{\n  \"title\": \"Light Influence Bit Masks\"\n}\n[/block]\nViro supports creating *categories* of lights, so that specific lights can influence specific nodes. To do this, lights and nodes in the scene can be assigned bit-masks.\n\nDuring rendering, Viro compares each light's ```influenceBitMask``` with each node's ```lightReceivingBitMask``` and ```shadowCastingBitMask```. The bit-masks are compared using a bitwise AND operation.\n\nIf (influenceBitMask & lightReceivingBitMask) != 0, then the light will illuminate the node, and the node will receive shadows cast from objects occluding the light.\n\nIf (influenceBitMask & shadowCastingBitMask) != 0, then the node will cast shadows from the light.\n\nThis feature can be used to limit the scope of a given light, or to limit what objects cast shadows for a given light. In the following example, the first box will cast shadows and the second will not, and only the first surface will receive shadows from the spotlight. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<ViroScene>\\n    <ViroDirectionalLight color=\\\"#777777\\\"\\n                          direction={[0, -1, 0]}\\n                   \\t      shadowOrthographicPosition={[0, 8, -5]}\\n                          shadowOrthographicSize={10}\\n                          shadowNearZ={2}\\n                          shadowFarZ={9}\\n                          lightInfluenceBitMask={2}\\n                   \\t\\t\\t  castsShadow={true} />\\n                        \\n    <ViroBox position={[-3, 3, -5]}\\n             width={0.5} height={0.5}\\n             shadowCastingBitMask={2} />\\n          \\n    <ViroBox position={[3, 3, -5]}\\n             width={0.5} height={0.5} />\\n          \\n    <ViroSurface position={[0, 0, 0]}\\n                 rotation={[-90, 0, 0]}\\n                 lightReceivingBitMask={2}\\n                 width={2} height={2} />\\n                 \\n    <ViroSurface position={[0, 0, 0]}\\n                 rotation={[-90, 0, 0]}\\n                 width={2} height={2} />\\n</ViroScene>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe default mask is 0x1.\n[block:api-header]\n{\n  \"title\": \"Bloom\"\n}\n[/block]\nBloom is an effect used to simulate extremely bright light overwhelming a camera capturing a scene. It's often referred to as \"glow\" as well. Because Viro supports High Dynamic Range (HDR) rendering, you can integrate bloom into your scenes.\n\nTo do this, set the ```bloomThreshold``` of the material you would like to glow. This value specifies at what 'brightness' the pixels of the surfaces using this material should start to bloom. Brightness is effectively the magnitude of the final color of a pixel (modified for the human eye: specifically, it is the dot product of the final color with (0.2126, 0.7152, 0.0722)). \n\nFor example, if ```bloomThreshold``` is set to 0.0, then all surfaces using the material will bloom. If ```bloomThreshold``` is set to 1.0, then only those pixels of the surface whose brightness exceeds 1.0 (after lights are applied) will bloom.\n\nThe following example creates a glow on the box by using a ```bloomThreshold``` of 0.5 and a combination of lights that exceeds 0.5 brightness on the box's surfaces.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<ViroScene>\\n      <ViroAmbientLight color=\\\"#FFFFFF\\\" intensity={250} />\\n      <ViroDirectionalLight color=\\\"#FFFFFF\\\" direction={[0, -1,  0]}/>\\n      <ViroDirectionalLight color=\\\"#FFFFFF\\\" direction={[0,  0, -1]}/>\\n\\n      <ViroBox position={[0, -.5, -1]}\\n               rotation={[0, 45, 0]}   \\n               scale={[.3, .3, .1]} materials={[\\\"grid\\\"]} />\\n</ViroScene>\\n        \\n...\\n\\nViroMaterials.createMaterials({\\n  grid: {\\n    diffuseTexture: require('./res/grid_bg.jpg'),\\n    lightingModel: \\\"Lambert\\\",\\n    bloomThreshold: 0.5,\\n  },\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/f7f1bee-IMG_4176.PNG\",\n        \"IMG_4176.PNG\",\n        1334,\n        750,\n        \"#040404\"\n      ]\n    }\n  ]\n}\n[/block]","excerpt":"Illuminating Scenes","slug":"3d-scene-lighting","type":"basic","title":"Lighting and Materials"}

Lighting and Materials

Illuminating Scenes

You illuminate scenes in Viro by adding lights to your ```<ViroNode>``` objects. For example, in the scene below, a grey spotlight and a blue ambient light illuminate a 3D object. [block:code] { "codes": [ { "code": "<ViroScene>\n <ViroOrbitCamera position={[0, 0, -0]} focalPoint={[0, 0, -1.15]} />\n <ViroSpotLight position={[0, -0.25, 0]}\n color=\"#777777\"\n direction={[0, 0, -1]}\n attenuationStartDistance={5}\n attenuationEndDistance={10}\n innerAngle={5}\n outerAngle={20}/>\n\n <ViroAmbientLight color=\"#FF0000\" />\n\n <Viro3DObject source={require('./res/heart.obj')}\n position={[-0.0, -5.5, -1.15]}\n materials={[\"heart\"]} />\n</ViroScene>", "language": "javascript" } ] } [/block] The impact of a light's illumination on a component is determined by two things: the light's properties, and the component's materials. This guide covers both [lights](#light-types) and [materials](#materials). [block:api-header] { "type": "basic", "title": "Constant Lighting" } [/block] For basic scenes with only UI elements and a background (```<Viro360Image>``` or ```<ViroSkybox>```), lights can effectively be ignored. By default, all elements use *Constant* lighting. Components with Constant lighting ignore the lights in the scene altogether; they are displayed in full color. To apply lighting, one or more [lights](#light-types) must be added to the scene, *and* the [lighting models](#lighting-models) of the components you want to respond to light must be set. The next few sections go into more detail. [block:api-header] { "type": "basic", "title": "Materials" } [/block] For more advanced scenes, we use lights and materials to control the illumination of objects. Materials are the set of shading attributes that define the appearance of a geometry's surface when rendered. Each object in a scene can be assigned one or more materials. All UI elements, and most basic 3D models, utilize only one material. Complex 3D objects, represented by ```<Viro3DObject>```, can have multiple materials, one for each defined mesh surface in the 3D object. Materials are assigned via the object's ```materials``` property. The following is a simple example: [block:code] { "codes": [ { "code": "<Viro3DObject source={require('./res/heart.obj')}\n position={[-0.0, -5.5, -1.15]}\n materials={[\"heart\"]} />", "language": "javascript" } ] } [/block] The material itself is then defined as follows: [block:code] { "codes": [ { "code": "ViroMaterials.createMaterials({\n heart: {\n lightingModel: \"Blinn\",\n diffuseTexture: require('./res/Heart_D3.jpg'),\n specularTexture: require('./res/Heart_S2.jpg'),\n },\n});", "language": "javascript" } ] } [/block] The following material properties determine how a material is rendered in light: * ```diffuseTexture``` and ```diffuseColor```: describe the color of light reflected equally in all directions from the material’s surface. The diffuse property of a pixel is independent of the point of view, so it can be thought of as a material’s “base” color or texture. The diffuse property be set as a texture (via ```diffuseTexture```), and/or as a uniform color (via ```diffuseColor```). If both are set, the two will be multiplied together at each pixel. * ```specularTexture```: describes the color of light reflected by the material directly toward the viewer. The specular color forms a bright highlight on the surface, simulating a glossy or shiny appearance. * ```shininess```: describes the sharpness of specular highlights. Ranges from 0 to 1. * ```lightingModel```: defines how material properties and the lights in the scene are combined to create the color for each pixel on the material's surface. Set to one of ```Constant```, ```Lambert```, ```Phong```, or ```Blinn```. See the next section for details. * ```normalTexture```: defines the orientation of the surface at each point for use in lighting. Viro treats the R, G, and B components of each pixel in the normal map as the X, Y, and Z components of a surface normal vector. Normal maps are often used to simulate rough surfaces or to add details to otherwise smooth surfaces. [block:api-header] { "type": "basic", "title": "Lighting Models" } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/678338b-viro_lighting_models.jpg", "viro_lighting_models.jpg", 754, 201, "#93086f" ] } ] } [/block] Viro supports four traditional lighting models: ```Constant```, ```Lambert```, ```Phong```, or ```Blinn```. Each of these lighting models defines a formula for combining a material’s diffuse and specular properties with the lights in the scene and the point of view, to create the color of each rendered pixel. In the examples below, ```diffuseMaterial``` refers to either the material's ```diffuseTexture``` or ```diffuseColor```, whichever is defined. If both are defined it refers to the material's ```diffuseTexture``` multiplied by its ```diffuseColor```. ## Constant The ```diffuseMaterial``` wholly determines the color of the surface. Lights are ignored. ```color = diffuseMaterial``` ## Lambert Lambert’s Law of diffuse reflectance determines the color of the surface. The formula is as follows: ```color = (∑ambientLight + ∑diffuseLight) * diffuseMaterial``` ```∑ambientLight```: the sum of all ambient lights in the scene, as contributed by ```ViroAmbientLight``` objects ```∑diffuseLight```: the sum of each non-ambient light's diffuse contribution. Each light's contribution is defined as follows ```diffuseLight = max(0, dot(N, L))``` where N is the surface normal vector at the point being shaded, and L is the normalized vector from the point being shaded to the light source. ## Phong The Phong approximation of real-world reflectance adds a specular contribution to the calculation: ```color = (∑ambientLight + ∑diffuseLight) * diffuseMaterial + ∑specularLight * specularTexture``` ```∑specularLight```: the sum of each non-ambient light's specular contribution. Each light's specular contribution is defined as follows ```specularLight = pow(max(0, dot(R, E)), shininess)``` where E is the normalized vector from the point being shaded to the viewer, R is the reflection of the light vector L across the normal vector N, and shininess is the value of the material's shininess property. ## Blinn The Blinn-Phong approximation of real-world reflectance is similar to Phong, but uses a different formula for the specular contribution ```specularLight = pow(max(0, dot(H, N)), shininess)``` where H is the vector halfway between the light vector L and the eye vector E, and shininess is the value of the material's shininess property. [block:api-header] { "type": "basic", "title": "Light Types" } [/block] The lighting models above determine how a set of lights impact a surface. The influence of a given light is also determined by the properties of the lights *themselves.* Light properties determine things like the directionality of the light, the color of the light, and how the light impacts objects over a distance. Viro supports four light types. # Ambient Light ```<ViroAmbientLight>``` illuminates all objects in the view (and its subviews) with equal intensity from all directions. Only the ```color``` of am ambient light needs to be set. # Directional Light ```<ViroDirectionalLight>``` represents a light source with uniform direction and constant intensity. The sun is a canonical example of a directional light. Directional lights have a ```color``` property and a ```direction``` property. # Omni Light ```<ViroOmniLight>``` is a light source that casts light in all directions from a given position. Omni lights have a ```color``` property and a ```position``` property. Additionally, the illumination of an omni light can attenuate over distance. This attenuation is controlled by the ```attenuationStartDistance``` and ```attenuationEndDistance``` properties. # Spot Light ```<ViroSpotLight>``` is a light source that illuminates a cone-shaped area determined by its ```position``` and ```direction```. The color of the spot light is determined by its ```color``` property. The edges of the cone are controlled by ```innerAngle```, the angle at which the cone begins to fade, and ```outerAngle```, the angle at which the cone has faded completely. Additionally, spot lights, like omni lights, can also attenuate with distance. This is controlled via the ```attenuationStartDistance``` and ```attenuationEndDistance``` properties. [block:api-header] { "title": "Shadows" } [/block] Viro renders shadows through shadow mapping, a technique where the silhouettes of objects are rendered to an image, and that image is then reprojected onto the screen. Viro will generate shadows for all lights that have their ```castsShadow``` property set to true. Shadows are particularly important for AR, in that they provide a visual cue about what real-world surface a virtual object is resting on. However, because casting shadows involves re-rendering the scene multiple times, they do incur a performance cost. Shadows are only supported for directional and spot lights. The following snippet shows how to create a spotlight that casts shadows: [block:code] { "codes": [ { "code": "<ViroScene>\n <ViroSpotLight position={[0, -0.25, 0]}\n color=\"#777777\"\n direction={[0, 0, -1]}\n attenuationStartDistance={5}\n attenuationEndDistance={10}\n innerAngle={5}\n outerAngle={20}\n castsShadow={true} />\n</ViroScene>", "language": "javascript" } ] } [/block] There are a multitude of parameters that can be tuned for shadow maps. Most of these involve a tradeoff between performance and quality. The ```shadowMapSize``` parameter, in particular, controls the resolution of the shadow map. Increasing this value yields a higher resolution shadow at a higher performance cost. Decreasing this value results in lower resolution shadows (pixelated at the edges) but higher performance. In general it is best to keep this value as power of 2. The deafult is 1024. The other key determinant of shadow quality is the shadow *frustum*. For a spotlight, this is essentially the cone of the light. It is determined by the spotlight's ```innerAngle``` and ```outerAngle```, and by the ```shadowNearZ``` and ```shadowFarZ```. The smaller the cone, the better the shadow quality. If the cone is too large, the shadows will become pixelated. The ```shadowNearZ``` and ```shadowFarZ``` parameters determine the extent of the cone in the direction of the light. Tightening these together as well will improve the precision of the shadow. For more detail on these parameters, see the [ViroSpotLight](doc:virospotlight1) reference. For directional lights, shadows have some additional parameters. Directional lights have no position --- they are ubiquitous -- so in theory they should cast shadows on all objects in the scene. However, doing so would be prohibitively expensive, so Viro requires that we choose an area for the directional light to cast shadows. To do this, set the ```shadowOrthographicPosition``` property to the *center* of the shadowed region, and set the ```shadowOrthographicSize``` property to the size of the shadowed region (specifically, this sets the shadow region's width and height). Finally, the ```shadowNearZ``` and ```shadowFarZ``` parameters should be set as well. Again, the tighter the shadow region, the higher resolution the shadows will appear. The following example shows a directional light casting shadows over a 10x10 meter area, 5 meters away from the origin in the Z direction. [block:code] { "codes": [ { "code": "<ViroScene>\n <ViroDirectionalLight color=\"#FFFFFF\"\n direction={[0, -1, 0]}\n shadowOrthographicPosition={[0, 3, -5]}\n shadowOrthographicSize={10}\n shadowNearZ={2}\n shadowFarZ={9}\n castsShadow={true} />\n\n <ViroBox position={[-1, 2, -5]}\n width={0.5} height={0.5}\n materials={[\"grid\"]} />\n\n <ViroBox position={[1, -1, -5]}\n width={0.5} height={0.5}\n materials={[\"grid\"]} />\n\n <ViroSurface position={[0, -2, -3]}\n rotation={[-90, 0, 0]}\n width={20} height={20}\n materials={[\"grid\"]} />\n</ViroScene>\n \n...\n\nViroMaterials.createMaterials({\n grid: {\n diffuseTexture: require('./res/grid_bg.jpg'),\n lightingModel: \"Lambert\",\n },\n});", "language": "javascript" } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/f20be77-IMG_4168.PNG", "IMG_4168.PNG", 1334, 750, "#ab7e8a" ] } ] } [/block] In the scene depicted above, the directional light casts shadows onto the horizontal ```<ViroSurface>```. Note, however, that the directional light will *only* cast a shadow for the second box. The first box does not cast a shadow because it's not within the shadow region. The shadow region in this example ranges from -5 to 5 on the X axis and 0 to -10 along the Z axis (determined by ```shadowOrthographicPosition```, ```direction```, and ```shadowOrthographicSize```), and +1 to -6 in the Y direction (determined by ```shadowOrthographicPosition```, ```direction```, ```shadowNearZ```, and ```shadowFarZ```). Specifically, the first box is cut off from the shadow region by ```shadowNearZ```. Note that shadows are: 1. Only *cast by* objects within the shadow region. 2. Only *rendered on* objects within the shadow region. [block:api-header] { "title": "AR Shadow Surfaces" } [/block] When rendering in augmented reality, it's common to want to render shadows onto *real world* surfaces. To do this, we have to specify the position of the surface we want to render the shadows onto, and set its ```arShadowReceiver``` property to true. To ensure the surface we're rendering onto truly does correspond to a real-world surface, typically we place the surface within a ```<ViroARPlaneSelector>``` or similar component, as shown below: [block:code] { "codes": [ { "code": "<ViroARScene>\n <ViroARPlaneSelector>\n <ViroSpotLight\n innerAngle={5}\n outerAngle={25}\n direction={[0, -1, -.2]}\n position={[0, 3, 1]}\n color=\"#ffffff\"\n castsShadow={true}\n shadowMapSize={2048}\n shadowNearZ={2}\n shadowFarZ={5}\n shadowOpacity={.7} />\n\n <Viro3DObject\n source={require('./res/pug.vrx')}\n position={[0, 0, 0]}\n scale={[.2, .2, .2]}\n type=\"VRX\" />\n\n <ViroSurface\n position={[0, 0, 0]}\n rotation={[-90, 0, 0]}\n width={4} height={4}\n arShadowReceiver={true} />\n</ViroARPlaneSelector>", "language": "javascript" } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/e41a235-IMG_4169.JPG", "IMG_4169.JPG", 750, 1334, "#7a6c68" ] } ] } [/block] In the scene above the ```<ViroSurface>``` will be coincident with the detected horizontal plane, and will have no "virtual" appearance; it simply designates a real-world surface on which virtual shadows should be rendered. The spotlight will cast a shadow of the ```<Viro3DObject>``` onto this surface. [block:api-header] { "title": "Light Influence Bit Masks" } [/block] Viro supports creating *categories* of lights, so that specific lights can influence specific nodes. To do this, lights and nodes in the scene can be assigned bit-masks. During rendering, Viro compares each light's ```influenceBitMask``` with each node's ```lightReceivingBitMask``` and ```shadowCastingBitMask```. The bit-masks are compared using a bitwise AND operation. If (influenceBitMask & lightReceivingBitMask) != 0, then the light will illuminate the node, and the node will receive shadows cast from objects occluding the light. If (influenceBitMask & shadowCastingBitMask) != 0, then the node will cast shadows from the light. This feature can be used to limit the scope of a given light, or to limit what objects cast shadows for a given light. In the following example, the first box will cast shadows and the second will not, and only the first surface will receive shadows from the spotlight. [block:code] { "codes": [ { "code": "<ViroScene>\n <ViroDirectionalLight color=\"#777777\"\n direction={[0, -1, 0]}\n \t shadowOrthographicPosition={[0, 8, -5]}\n shadowOrthographicSize={10}\n shadowNearZ={2}\n shadowFarZ={9}\n lightInfluenceBitMask={2}\n \t\t\t castsShadow={true} />\n \n <ViroBox position={[-3, 3, -5]}\n width={0.5} height={0.5}\n shadowCastingBitMask={2} />\n \n <ViroBox position={[3, 3, -5]}\n width={0.5} height={0.5} />\n \n <ViroSurface position={[0, 0, 0]}\n rotation={[-90, 0, 0]}\n lightReceivingBitMask={2}\n width={2} height={2} />\n \n <ViroSurface position={[0, 0, 0]}\n rotation={[-90, 0, 0]}\n width={2} height={2} />\n</ViroScene>", "language": "javascript" } ] } [/block] The default mask is 0x1. [block:api-header] { "title": "Bloom" } [/block] Bloom is an effect used to simulate extremely bright light overwhelming a camera capturing a scene. It's often referred to as "glow" as well. Because Viro supports High Dynamic Range (HDR) rendering, you can integrate bloom into your scenes. To do this, set the ```bloomThreshold``` of the material you would like to glow. This value specifies at what 'brightness' the pixels of the surfaces using this material should start to bloom. Brightness is effectively the magnitude of the final color of a pixel (modified for the human eye: specifically, it is the dot product of the final color with (0.2126, 0.7152, 0.0722)). For example, if ```bloomThreshold``` is set to 0.0, then all surfaces using the material will bloom. If ```bloomThreshold``` is set to 1.0, then only those pixels of the surface whose brightness exceeds 1.0 (after lights are applied) will bloom. The following example creates a glow on the box by using a ```bloomThreshold``` of 0.5 and a combination of lights that exceeds 0.5 brightness on the box's surfaces. [block:code] { "codes": [ { "code": "<ViroScene>\n <ViroAmbientLight color=\"#FFFFFF\" intensity={250} />\n <ViroDirectionalLight color=\"#FFFFFF\" direction={[0, -1, 0]}/>\n <ViroDirectionalLight color=\"#FFFFFF\" direction={[0, 0, -1]}/>\n\n <ViroBox position={[0, -.5, -1]}\n rotation={[0, 45, 0]} \n scale={[.3, .3, .1]} materials={[\"grid\"]} />\n</ViroScene>\n \n...\n\nViroMaterials.createMaterials({\n grid: {\n diffuseTexture: require('./res/grid_bg.jpg'),\n lightingModel: \"Lambert\",\n bloomThreshold: 0.5,\n },\n});", "language": "javascript" } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/f7f1bee-IMG_4176.PNG", "IMG_4176.PNG", 1334, 750, "#040404" ] } ] } [/block]