- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用 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']
}
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/
我正在为我的雇主编写脚本,以从他们自己的站点获取某些数据。出于一长串原因,我需要从网站上获取数据,如图所示。我发现,其中一些数据是通过 js 调用检索的... 回想起来,我应该选择 Mechanize
我正在使用 python 和 cryptography.io 来签署和验证消息。我可以通过以下方式获得签名的 DER 编码字节表示: cryptography_priv_key.sign(messag
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 6年前关闭。 Improve thi
是否可以区分 ECDF?以下面得到的为例。 set.seed(1) a <- sort(rnorm(100)) b <- ecdf(a) plot(b) 我想对 b 求导以获得它的概率密度函数 (PD
我找到了如何从 navigator.mimeTypes 获取 mimetypes: function GetMimeTypes() { var message = ""; var mi
我在表单中使用单选按钮来隐藏/显示联系人表单中的成员 ID 字段。问题是,当 javascript 更改 html 中包含的隐藏 id 字段(该字段设置为“无”值)时,该字段将不再通过 post 可用
我正在做单元测试。我必须测试所有可能的if..else情况。但是在此if语句中: int32_t i32Res = snprintf(buffer, len, "The%d_String_%d", 0
我有一个 Facebook 应用程序,我想从中获取“喜欢”的总数。我想知道这是否可能。 其中 ID 是应用程序的 ID,ACCESS_TOKEN 是我尝试过的应用程序的当前访问 token : gra
如果我有多个计算实例尝试同时获取同一个 blob 的租约,则似乎经常会成功。我的印象是,一旦租约发出(并因此被客户获得),就不可能同时发出另一个租约? 我希望情况确实如此,我一直在 Azure 中使用
这是我的索引 POST /blogs/1 { "name" : "learn java", "popularity" : 100 } POST /blogs/2 { "name" : "l
我正在将 Symfony2 与 FOSUserBundle 一起使用。我需要为用户获得最高角色。 role_hierarchy: ROLE_CONTRIBUTOR: ROLE_USER
我正在向服务器发送基于 REST 的请求。我希望尽快得到答复,并希望了解可以进行的各种优化。 一种方法当然是在线程中并行发送这些请求。还有哪些其他选项可用于优化此功能? 在服务器上,可以添加哪些配置?
这可能是某种重复的问题,但我似乎找不到合适的解决方案。我正在使用 git4idea.history.GitHistoryUtils.history() 获取提交列表。如果 checkout 其中一个较
我正在做一个程序,可以输入每周的工资和那一周的总工作时间。它应该以小时工资率显示答案。但是我无法显示正确的“centavos/2 decimal places”公式并且它不想使用 float % fl
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我已经尝试了 mContext.getMainLooper() 和 Looper.getMainLooper()。两者都返回相同的结果,但我想知道哪种方法正确? 我还从 Android 开发人员链接中
我有一个“affiliates”表,其中包含“user”和“referredBy”列。 给定一个用户,我希望获得该用户推荐的所有“n 级”玩家。对于 n=1,我们只关心您直接推荐的玩家数量: SELE
我在 PostgreSQL 9.5 数据库中有两个表: project - id - name task - id - project_id - name - updated_
请帮助我怎样才能得到我预期的结果,在此先感谢并抱歉我的英语不好。 PHP: $dog = implode(',', $data['dogbreed']); $query .= "AND `do
我有 let impulse = CGVectorMake(CGFloat(Constants.impulse), 0) 如何在不创建另一个 CGVector 的情况下得到它的负值? 我正在考虑在 C
我是一名优秀的程序员,十分优秀!