gpt4 book ai didi

javascript - 如何在 ShaderMaterial 上获得正确的阴影

转载 作者:行者123 更新时间:2023-11-30 19:24:13 28 4
gpt4 key购买 nike

我使用 InstancedBufferGeometry 创建了很多框,然后使用 Perlin 噪声更新位置。但是网格已经转换并收到了错误的阴影。如何计算右阴影?

顶点着色器

attribute vec3 offset;
attribute vec4 orientation;
attribute vec3 color;

varying vec3 pos;
varying vec3 vNormal;
varying vec3 vWorldPosition;
varying vec3 vColor;

vec3 applyQuaternionToVector( vec4 q, vec3 v ){
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}

THREE.ShaderChunk["common"]
THREE.ShaderChunk["shadowmap_pars_vertex"]

void main() {
vColor = color;

vec3 vPosition = applyQuaternionToVector( orientation, position );
pos = vPosition + offset;

vNormal = normalMatrix * vec3(normal + normalize(offset) * 0.3);

vec4 worldPosition = modelMatrix * vec4(pos, 1.0);
vWorldPosition = worldPosition.xyz;

gl_Position = projectionMatrix * modelViewMatrix * worldPosition;
THREE.ShaderChunk["shadowmap_vertex"]
}

片段着色器

THREE.ShaderChunk['common']
THREE.ShaderChunk['packing']
varying vec3 pos;
varying vec3 vNormal;
varying vec3 vWorldPosition;
varying vec3 vColor;

uniform vec3 lightPosition;

THREE.ShaderChunk['shadowmap_pars_fragment']
void main() {
vec3 lightDirection = normalize(lightPosition + pos);

float c = max(0.0, dot(vNormal, lightDirection)) * 2.;
gl_FragColor = vec4(.3+c , .3+c , .3+c , 1.);
THREE.ShaderChunk['shadowmap_fragment']
}

demo link is here

three.js r.106
谢谢

var scene, camera, renderer;
var plane, temp, vnh, point;
var radius = 10;
var stats = new Stats();
var start = Date.now();
var options = {
scale: 200,
density: 2.5
}
var currentQ = new THREE.Quaternion();
var initedBoxes = false;

var init = function() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 25;
var controls = new THREE.OrbitControls(camera);

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);

var gui = new dat.GUI({
width: 300
});
gui.add(options, 'scale').min(0).max(200).name('Scale');
gui.add(options, 'density').min(0).max(10).name('Density');

// stats
stats.showPanel(0);
stats.domElement.style.position = 'fixed';
stats.domElement.style.top = 0;
document.body.appendChild(stats.domElement);

initLights();
initSphere();
initBoxes();

renderer.setAnimationLoop(function() {
update();
render();
});
}

var initLights = function() {
var ambientLight = new THREE.AmbientLight(0x555555);
scene.add(ambientLight);
light1 = new THREE.SpotLight(0xffffff, 2, 200, 10);
light1.position.set(-30, 30, 40);
light1.castShadow = true;
scene.add(light1);

light1Helper = new THREE.SpotLightHelper(light1, 0xffffff);
scene.add(light1Helper);
}

var initSphere = function() {
var geometry = new THREE.IcosahedronGeometry(radius, 3);
var material = new THREE.MeshPhongMaterial({
color: 0x999999,
wireframe: false
});
material.shininess = 0;
sphere = new THREE.Mesh(geometry, material);
// sphere.castShadow = true;
// sphere.receiveShadow = true;
// scene.add(sphere);

tempGeo = new THREE.Geometry();
tempGeo.copy(geometry);
temp = new THREE.Mesh(tempGeo, material);

var pGeo = new THREE.PlaneGeometry(100, 100, 1, 1);
plane = new THREE.Mesh(pGeo, material);
plane.receiveShadow = true;
plane.position.y = -radius - 3;
plane.rotation.x = -90 * Math.PI / 180;
scene.add(plane);
}

var initBoxes = function() {
initedBoxes = true;
var bufferGeometry = new THREE.BoxBufferGeometry(1, 1, 1);
var geometry = new THREE.InstancedBufferGeometry();
geometry.index = bufferGeometry.index;
geometry.attributes.position = bufferGeometry.attributes.position;
// geometry.attributes.normal = bufferGeometry.attributes.normal;

// per instance data
var offsets = [];
var orientations = [];
var colors = [];
var vector = new THREE.Vector4();
var x, y, z, w;
var cscale = chroma.scale(['#ff0000', '#00ff00', '#0000ff']).classes(10);

for (var i = 0; i < sphere.geometry.faces.length; i++) {
center = getCenter(sphere.geometry.faces[i]);
x = center.x;
y = center.y;
z = center.z;
vector.set(x, y, z, 0).normalize();

offsets.push(x + vector.x, y + vector.y, z + vector.z);

// rotate

rotation = getRotation(sphere.geometry.faces[i].normal);
vector.copy(rotation).normalize();

orientations.push(vector.x, vector.y, vector.z, vector.w);

var color = chroma(cscale(THREE.Math.randFloat(0, 1))).brighten(1).hex();
color = new THREE.Color(color);
colors.push(color.r, color.g, color.b);
}
offsetAttribute = new THREE.InstancedBufferAttribute(new Float32Array(offsets), 3);
orientationAttribute = new THREE.InstancedBufferAttribute(new Float32Array(orientations), 4);
colorAttribute = new THREE.InstancedBufferAttribute(new Float32Array(colors), 3);

geometry.addAttribute('offset', offsetAttribute);
geometry.addAttribute('orientation', orientationAttribute);
geometry.addAttribute('color', colorAttribute);

var material = new THREE.ShaderMaterial({
lights: true,
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib["shadowmap"],
THREE.UniformsLib["lights"],
{
lightPosition: {
type: 'v3',
value: light1.position
},
time: {
type: 'f',
value: 0
}
}
]),
vertexShader: [
'attribute vec3 offset;',
'attribute vec4 orientation;',
'attribute vec3 color;',

'varying vec3 pos;',
'varying vec3 vNormal;',
'varying vec3 vWorldPosition;',
'varying vec3 vColor;',

'vec3 applyQuaternionToVector( vec4 q, vec3 v ){',
'return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );',
'}',

THREE.ShaderChunk["common"],
THREE.ShaderChunk["shadowmap_pars_vertex"],

'void main() {',
'vColor = color;',

'vec3 vPosition = applyQuaternionToVector( orientation, position );',
'pos = vPosition + offset;',

'vNormal = normalMatrix * vec3(normal + normalize(offset) * 0.3);',

'vec4 worldPosition = modelMatrix * vec4(pos, 1.0);',
'vWorldPosition = worldPosition.xyz;',

'gl_Position = projectionMatrix * modelViewMatrix * worldPosition;',
THREE.ShaderChunk["shadowmap_vertex"],
'}'
].join('\n'),
fragmentShader: [
THREE.ShaderChunk['common'],
THREE.ShaderChunk['packing'],
'varying vec3 pos;',
'varying vec3 vNormal;',
'varying vec3 vWorldPosition;',
'varying vec3 vColor;',

'uniform vec3 lightPosition;',

THREE.ShaderChunk['shadowmap_pars_fragment'],
'void main() {',
'vec3 lightDirection = normalize(lightPosition + pos);',

'float c = max(0.0, dot(vNormal, lightDirection)) * 2.;',
// 'gl_FragColor = vec4(vColor.r + c , vColor.g + c , vColor.b + c , 1.);',
'gl_FragColor = vec4(.3+c , .3+c , .3+c , 1.);',
THREE.ShaderChunk['shadowmap_fragment'],
'}'
].join('\n')
});

boxes = new THREE.Mesh(geometry, material);
boxes.castShadow = true;
boxes.receiveShadow = true;
scene.add(boxes);
}

// find center position from 3 vertices
function getCenter(face) {
var centroid = new THREE.Vector3(0, 0, 0);
centroid.add(sphere.geometry.vertices[face.a]);
centroid.add(sphere.geometry.vertices[face.b]);
centroid.add(sphere.geometry.vertices[face.c]);
centroid.divideScalar(3);
return centroid;
}

function getRotation(normal) {
var planeVector1 = new THREE.Vector3(0, 1, 0);
var matrix1 = new THREE.Matrix4();
var quaternion = new THREE.Quaternion().setFromUnitVectors(planeVector1, normal);
var matrix = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
var a = new THREE.Euler();
a.setFromRotationMatrix(matrix, 'XYZ')
// return a.toVector3();
return quaternion;
}

// noise.seed(Math.random());
var update = function() {
stats.update();
var timer = (Date.now() - start) * .0002;

// animate vertices of sphere with noise
for (var i = 0; i < sphere.geometry.vertices.length; i++) {
var p = sphere.geometry.vertices[i];
var tp = temp.geometry.vertices[i];
var n = noise.perlin3(tp.x / (10 - options.density) + timer, tp.y / (10 - options.density) + timer, tp.z / (10 - options.density) + timer) * options.scale;

// move vertices with noise
p.normalize().multiplyScalar(radius + n / 100);
}

sphere.geometry.verticesNeedUpdate = true;
sphere.geometry.normalsNeedUpdate = true;
sphere.geometry.computeVertexNormals();
sphere.geometry.computeFaceNormals();


// animate boxes
if (initedBoxes) {
for (var i = 0; i < sphere.geometry.faces.length; i++) {
center = getCenter(sphere.geometry.faces[i]);
x = center.x;
y = center.y;
z = center.z;
offsetAttribute.setXYZ(i, center.x, center.y, center.z);

rotation = getRotation(sphere.geometry.faces[i].normal);
currentQ.copy(rotation).normalize();
orientationAttribute.setXYZW(i, currentQ.x, currentQ.y, currentQ.z, currentQ.w);
}
offsetAttribute.needsUpdate = true;
orientationAttribute.needsUpdate = true;
}
}


var animate = function() {
draw();
}

var render = function() {
renderer.render(scene, camera);
}

init();
<html>

<head>
<title>Instanced buffer test</title>
<style>
* {
padding: 0px;
margin: 0px;
}

html,
body {
overflow: hidden;
}
</style>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.min.js"></script>
<script src="https://josephg.github.io/noisejs/perlin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.0.3/chroma.min.js"></script>
<script src="https://unpkg.com/three@0.85.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
</head>

<body>
</body>

</html>

最佳答案

如果您希望网格转换适当的阴影,使用 ShaderMaterial 是不够的对于.material网格的属性。
点光源的阴影取决于 .customDepthMaterial属性(property)。这意味着您必须编写一个着色器 (ShaderMaterial),该着色器将模型转换为阴影贴图来渲染对象。


网格的阴影被阴影相机的近平面部分裁剪。
通过设置 .near 使用更近的近平面(例如 0.1 而不是 0.5)透视阴影相机(light1.shadow.camera)的属性,解决问题:

light1 = new THREE.SpotLight( 0xffffff, 2, 200, 10 );
light1.position.set( -30, 30, 40 );
light1.castShadow = true;
light1.shadow.mapSize.x = 2048;
light1.shadow.mapSize.y = 2048;
light1.shadow.camera.near = 0.1;
scene.add(light1);

此外,着色器中还有一些问题。声明

vec3 lightDirection = normalize(lightPosition + pos);

没有任何意义,因为方向是从一个点到另一个点的向量,由 (-)-运算符计算(例如 lightPosition - pos).
但这并不能解决问题,因为 lightPosition 是世界空间中的一个点,而 pos 是模型空间中的一个点。

你必须计算 View 空间中的向量,因为在

float c = max(0.0, dot(vNormal, lightDirection)) * 2.;

vNormal 是 View 空间中的向量。

我建议在顶点着色器 (vLightDir) 中计算光线方向并将其传递给片段着色器。
计算世界空间中的方向并通过 View 矩阵的上 3x3 变换它 (mat3(viewMatrix)):

vLightDir = mat3(viewMatrix) * (lightPosition - vWorldPosition);

因为 worldPosition(顾名思义)是世界空间中的一个位置,它必须由 viewMatrix 而不是 modelViewMatrix:

gl_Position = projectionMatrix * viewMatrix * worldPosition;

请注意,modelViewMatrix 从对象空间转换为 View 空间。 viewMatrix 从世界空间转换到 View 空间。另见 WebGLProgram .

顶点着色器:

vertexShader:
[
'attribute vec3 offset;',
'attribute vec4 orientation;',
'attribute vec3 color;',

'varying vec3 pos;',
'varying vec3 vNormal;',
'varying vec3 vWorldPosition;',
'varying vec3 vColor;',
'varying vec3 vLightDir;',

'uniform vec3 lightPosition;',

'vec3 applyQuaternionToVector( vec4 q, vec3 v ){',
'return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );',
'}',

THREE.ShaderChunk["common"],
THREE.ShaderChunk["shadowmap_pars_vertex"],

'void main() {',
'vColor = color;',

'vec3 vPosition = applyQuaternionToVector( orientation, position );',
'pos = vPosition + offset;',

'vNormal = normalMatrix * vec3(normal + normalize(offset) * 0.3);',

'vec4 worldPosition = modelMatrix * vec4(pos, 1.0);',
'vWorldPosition = worldPosition.xyz;',

'vLightDir = mat3(viewMatrix) * (lightPosition - vWorldPosition);',

'gl_Position = projectionMatrix * viewMatrix * worldPosition;',
THREE.ShaderChunk["shadowmap_vertex"],
'}'
].join('\n')

片段着色器:

fragmentShader:
[
THREE.ShaderChunk['common'],
THREE.ShaderChunk['packing'],
'varying vec3 pos;',
'varying vec3 vNormal;',
'varying vec3 vWorldPosition;',
'varying vec3 vColor;',
'varying vec3 vLightDir;',

THREE.ShaderChunk['shadowmap_pars_fragment'],
'void main() {',
'vec3 lightDirection = normalize(vLightDir);',

'float c = max(0.0, dot(vNormal, lightDirection)) * 2.;',
// 'gl_FragColor = vec4(vColor.r + c , vColor.g + c , vColor.b + c , 1.);',
'gl_FragColor = vec4(.3+c , .3+c , .3+c , 1.);',
THREE.ShaderChunk['shadowmap_fragment'],
'}'
].join('\n')

var scene,camera,renderer;
var plane, temp, vnh, point;
var radius = 10;
var stats = new Stats();
var start = Date.now();
var options = {
scale:200,
density:2.5
}
var currentQ = new THREE.Quaternion();
var initedBoxes = false;

var init = function(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 25;
var controls = new THREE.OrbitControls( camera );

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild( renderer.domElement );

window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}

var gui = new dat.GUI({width: 300});
gui.add(options,'scale').min(0).max(200).name('Scale');
gui.add(options,'density').min(0).max(10).name('Density');

// stats
stats.showPanel(0);
stats.domElement.style.position = 'fixed';
stats.domElement.style.top = 0;
document.body.appendChild( stats.domElement );

initLights();
initSphere();
initBoxes();

renderer.setAnimationLoop(function(){
update();
render();
});
}

var initLights = function(){
var ambientLight = new THREE.AmbientLight( 0x555555 );
scene.add( ambientLight );
light1 = new THREE.SpotLight( 0xffffff, 2, 200, 10 );
light1.position.set( -30, 30, 40 );
light1.castShadow = true;
light1.shadow.mapSize.x = 2048;
light1.shadow.mapSize.y = 2048;
light1.shadow.camera.near = 0.1;
scene.add(light1);

light1Helper = new THREE.SpotLightHelper(light1, 0xffffff);
scene.add(light1Helper);
}

var initSphere = function(){
var geometry = new THREE.IcosahedronGeometry( radius, 3 );
var material = new THREE.MeshPhongMaterial( {color: 0x999999, wireframe:false} );
// var material = new THREE.ShaderMaterial({
// vertexShader: document.getElementById('vertexShader').innerHTML,
// fragmentShader: document.getElementById('fragmentShader').innerHTML
// });
material.shininess = 0;
sphere = new THREE.Mesh( geometry, material );
sphere.castShadow = true;
sphere.receiveShadow = true;
// scene.add(sphere);

tempGeo = new THREE.Geometry();
tempGeo.copy(geometry);
temp = new THREE.Mesh( tempGeo, material );

var pGeo = new THREE.PlaneGeometry(200, 200, 1, 1);
plane = new THREE.Mesh( pGeo, material );
plane.receiveShadow = true;
plane.position.y = -radius - 10;
plane.rotation.x = -90 * Math.PI/180;
scene.add(plane);
}

var initBoxes = function(){
initedBoxes = true;
var bufferGeometry = new THREE.BoxBufferGeometry(1,1,1);
var geometry = new THREE.InstancedBufferGeometry();
geometry.index = bufferGeometry.index;
geometry.attributes.position = bufferGeometry.attributes.position;
// geometry.attributes.normal = bufferGeometry.attributes.normal;

// per instance data
var offsets = [];
var orientations = [];
var colors = [];
var vector = new THREE.Vector4();
var x, y, z, w;
var cscale = chroma.scale(['#ff0000','#00ff00','#0000ff']).classes(10);

for(var i=0; i<sphere.geometry.faces.length; i++){
center = getCenter(sphere.geometry.faces[i]);
x = center.x;
y = center.y;
z = center.z;
vector.set( x, y, z, 0 ).normalize();

offsets.push( x + vector.x, y + vector.y, z + vector.z );

// rotate

rotation = getRotation(sphere.geometry.faces[i].normal);
vector.copy(rotation).normalize();

orientations.push( vector.x, vector.y, vector.z, vector.w );

var color = chroma(cscale(THREE.Math.randFloat(0,1))).brighten(1).hex();
color = new THREE.Color(color);
colors.push(color.r, color.g, color.b);
}
offsetAttribute = new THREE.InstancedBufferAttribute( new Float32Array( offsets ), 3 );
orientationAttribute = new THREE.InstancedBufferAttribute( new Float32Array( orientations ), 4 );
colorAttribute = new THREE.InstancedBufferAttribute( new Float32Array( colors ), 3 );

geometry.addAttribute( 'offset', offsetAttribute );
geometry.addAttribute( 'orientation', orientationAttribute );
geometry.addAttribute( 'color', colorAttribute );

var material = new THREE.ShaderMaterial( {
lights: true,
uniforms: THREE.UniformsUtils.merge([
// THREE.UniformsLib["shadowmap"],
THREE.UniformsLib["lights"],
{
lightPosition: {type: 'v3', value: light1.position},
time: {type: 'f', value: 0}
}
]),
vertexShader:
[
'attribute vec3 offset;',
'attribute vec4 orientation;',
'attribute vec3 color;',

'varying vec3 pos;',
'varying vec3 vNormal;',
'varying vec3 vWorldPosition;',
'varying vec3 vColor;',
'varying vec3 vLightDir;',

'uniform vec3 lightPosition;',

'vec3 applyQuaternionToVector( vec4 q, vec3 v ){',
'return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );',
'}',

THREE.ShaderChunk["common"],
THREE.ShaderChunk["shadowmap_pars_vertex"],

'void main() {',
'vColor = color;',

'vec3 vPosition = applyQuaternionToVector( orientation, position );',
'pos = vPosition + offset;',

'vNormal = normalMatrix * vec3(normal + normalize(offset) * 0.3);',

'vec4 worldPosition = modelMatrix * vec4(pos, 1.0);',
'vWorldPosition = worldPosition.xyz;',

'vLightDir = mat3(viewMatrix) * (lightPosition - vWorldPosition);',

'gl_Position = projectionMatrix * viewMatrix * worldPosition;',
THREE.ShaderChunk["shadowmap_vertex"],
'}'
].join('\n')
,
fragmentShader:
[
THREE.ShaderChunk['common'],
THREE.ShaderChunk['packing'],
'varying vec3 pos;',
'varying vec3 vNormal;',
'varying vec3 vWorldPosition;',
'varying vec3 vColor;',
'varying vec3 vLightDir;',

THREE.ShaderChunk['shadowmap_pars_fragment'],
'void main() {',
'vec3 lightDirection = normalize(vLightDir);',

'float c = max(0.0, dot(vNormal, lightDirection)) * 2.;',
// 'gl_FragColor = vec4(vColor.r + c , vColor.g + c , vColor.b + c , 1.);',
'gl_FragColor = vec4(.3+c , .3+c , .3+c , 1.);',
THREE.ShaderChunk['shadowmap_fragment'],
'}'
].join('\n')
});

boxes = new THREE.Mesh( geometry, material );
boxes.castShadow = true;
boxes.receiveShadow = true;

boxes.customDepthMaterial = new THREE.ShaderMaterial({
vertexShader:
[
'attribute vec3 offset;',
'attribute vec4 orientation;',

'varying vec3 vWorldPosition;',

'vec3 applyQuaternionToVector( vec4 q, vec3 v ){',
'return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );',
'}',

'void main() {',
'vec3 vPosition = applyQuaternionToVector( orientation, position );',
'vec3 pos = vPosition + offset;',

'vec4 worldPosition = modelMatrix * vec4(pos, 1.0);',
'vWorldPosition = worldPosition.xyz;',

'gl_Position = projectionMatrix * viewMatrix * worldPosition;',
'}',
].join('\n')
,
fragmentShader: THREE.ShaderLib.distanceRGBA.fragmentShader,
uniforms: material.uniforms
});
scene.add(boxes);
}

// find center position from 3 vertices
function getCenter(face){
var centroid = new THREE.Vector3(0,0,0);
centroid.add(sphere.geometry.vertices[face.a]);
centroid.add(sphere.geometry.vertices[face.b]);
centroid.add(sphere.geometry.vertices[face.c]);
centroid.divideScalar(3);
return centroid;
}

function getRotation(normal){
var planeVector1 = new THREE.Vector3(0,1,0);
var matrix1 = new THREE.Matrix4();
var quaternion = new THREE.Quaternion().setFromUnitVectors(planeVector1, normal);
var matrix = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
var a = new THREE.Euler( );
a.setFromRotationMatrix ( matrix, 'XYZ' )
// return a.toVector3();
return quaternion;
}

// noise.seed(Math.random());
var update = function(){
stats.update();
var timer = (Date.now() - start) * .0002;

// animate vertices of sphere with noise
for(var i=0; i<sphere.geometry.vertices.length; i++){
var p = sphere.geometry.vertices[i];
var tp = temp.geometry.vertices[i];
var n = noise.perlin3(tp.x / (10-options.density) + timer, tp.y / (10-options.density) + timer, tp.z / (10-options.density) + timer) * options.scale;

// move vertices with noise
p.normalize().multiplyScalar(radius + n/100);
}

sphere.geometry.verticesNeedUpdate = true;
sphere.geometry.normalsNeedUpdate = true;
sphere.geometry.computeVertexNormals();
sphere.geometry.computeFaceNormals();


// animate boxes
if(initedBoxes){
for(var i=0; i<sphere.geometry.faces.length; i++){
center = getCenter(sphere.geometry.faces[i]);
x = center.x;
y = center.y;
z = center.z;
offsetAttribute.setXYZ(i, center.x, center.y, center.z);

rotation = getRotation(sphere.geometry.faces[i].normal);
currentQ.copy(rotation).normalize();
orientationAttribute.setXYZW( i, currentQ.x, currentQ.y, currentQ.z, currentQ.w );
}
offsetAttribute.needsUpdate = true;
orientationAttribute.needsUpdate = true;
}
}


var animate = function(){
draw();
}

var render = function(){
renderer.render( scene, camera );
}

init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.min.js"></script>
<script src="https://josephg.github.io/noisejs/perlin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.0.3/chroma.min.js"></script>
<script src="https://unpkg.com/three@0.85.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>

关于javascript - 如何在 ShaderMaterial 上获得正确的阴影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57093387/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com