有没有办法在aframe中为照明对象部件设置特殊纹理?例如,我想为地球设置夜间纹理,其中一侧未被照亮的另一面具有另一种纹理。
编辑:我似乎需要某种着色器,但我找不到任何有用的问题。
编辑2:着色器必须灵活,必须使用不同类型的光源和不是完美球体的物体。
答案 0 :(得分:3)
下面的演示代码。三个文件index.html
,sky.js
和earth.js
。
主要从loading textures和fragment shaders的两个样本拼接在一起。主要贡献是:
1-1。着色器worldDayTex: { type: 'map', is: 'uniform' }
中的行uniform sampler2D worldDayTex;
和earth.js
。这里是WebGL着色器
声明输入的纹理贴图均匀。
1-2。行skyEl.setAttribute('material', 'worldDayTex', '#worldDay' );
index.html
。这里,纹理贴图从HTML-> WebGL输入并分配给制服。
白天遮蔽地球,你可能想知道太阳落在地球上一个特定的点上。我们能安全地认为太阳是你唯一的光源吗?如果是这样的话,它就是每个给定点的地球表面法线的简单方程,与太阳的方向。因此,这个例子不是基于采样光强度本身,而是基于两个矢量之间的等式。
动画看起来很慢(在我的测试中为5 fps),我不知道为什么。官方片段着色器示例的方式相同。
您需要提供自己的纹理worldDay.png
和worldNight.png
。为了测试,我使用了this site上的图片。
可能很明显,但在使用之前,您需要修补aframe-master.min.js
的路径,或将其下载到同一目录进行测试。
在Windows上使用64位版本的Firefox版本进行测试。在我的测试中,Chrome无法支持A-Frame纹理处理。
的index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Earth day to night example — A-Frame</title>
<meta name="description" content="Earth day to night example — A-Frame">
<script src="./aframe-master.min.js"></script>
<script src="./sky.js"></script>
<script src="./earth.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent('sun-position-setter', {
init: function () {
var skyEl = this.el;
var orbitEl = this.el.sceneEl.querySelector('#orbit');
orbitEl.addEventListener('componentchanged',
function changeSun (evt)
{
var sunPosition;
var phase;
var phi;
if (evt.detail.name !== 'rotation') { return; }
sunPosition = orbitEl.getAttribute('rotation');
if(sunPosition === null) { return; }
phase = (sunPosition.y / 360); // varies from 0 to 1
phi = 2 * Math.PI * (phase - 0.5); // varies from 0 to two pi
skyEl.setAttribute('material', 'sunDirection',
{
x: Math.cos(phi), // use x and y to indicate 2D rotation vector
y: Math.sin(phi),
z: phase // use z to indicate the phase
}
);
skyEl.setAttribute('material', 'worldDayTex', '#worldDay' );
skyEl.setAttribute('material', 'worldNightTex', '#worldNight' );
}
);
}
});
</script>
<a-scene background="color: #ECECEC">
<a-assets>
<img id="worldDay" src="./worldDay.png">
<img id="worldNight" src="./worldNight.png">
</a-assets>
<a-entity id="earth" position="0 0 -5" geometry="primitive: sphere; radius: 2" material="shader: earth" sun-position-setter>
<a-entity id="orbit">
<a-animation attribute="rotation" from="0 0 0" to="0 360 0" dur="5000" repeat="indefinite" easing="linear"></a-animation>
</a-entity>
</a-entity>
<a-entity id="sky" geometry="primitive: sphere; radius: 100;" material="shader: sky; side: back" sun-position-setter>
</a-entity>
</a-scene>
</body>
</html>
sky.js
/* global AFRAME */
AFRAME.registerShader('sky', {
schema: {
worldDayTex: { type: 'map', is: 'uniform' },
worldNightTex: { type: 'map', is: 'uniform' },
sunDirection: { type: 'vec3', default: 'vec3(1,0,0)', is: 'uniform' }
},
vertexShader:
` // use backtick for multi-line text
varying vec3 vWorldPosition;
varying vec2 vUV;
void main() {
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vWorldPosition = worldPosition.xyz;
vUV = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`
,
fragmentShader:
` // use backtick for multi-line text
uniform vec3 sunDirection;
varying vec3 vWorldPosition;
varying vec2 vUV;
void main()
{
vec2 sunUV = vec2( sunDirection.z, 0.5 );
vec2 cmpUV = vec2( 1.0-vUV.x, vUV.y );
vec2 diffUV = vec2( sunUV.x-cmpUV.x, sunUV.y-cmpUV.y );
float dist = sqrt( (diffUV.x*diffUV.x) + (diffUV.y*diffUV.y) );
if( dist<0.01 )
gl_FragColor.rgb = vec3(1,0.98,0.7);
else
gl_FragColor.rgb = vec3(0,0,0);
gl_FragColor.a = 1.0;
}
`
});
earth.js
/* global AFRAME */
AFRAME.registerShader('earth', {
schema: {
worldDayTex: { type: 'map', is: 'uniform' },
worldNightTex: { type: 'map', is: 'uniform' },
sunDirection: { type: 'vec3', default: 'vec3(1,0,0)', is: 'uniform' }
},
vertexShader:
` // use backtick for multi-line text
varying vec3 vWorldPosition;
varying vec2 vUV;
varying vec3 vNormal;
void main() {
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vWorldPosition = worldPosition.xyz;
vUV = uv;
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`
,
fragmentShader:
` // use backtick for multi-line text
uniform sampler2D worldDayTex;
uniform sampler2D worldNightTex;
uniform vec3 sunDirection;
varying vec3 vWorldPosition;
varying vec2 vUV;
varying vec3 vNormal;
void main()
{
vec3 worldDayColor = texture2D(worldDayTex, vUV).rgb;
vec3 worldNightColor = texture2D(worldNightTex, vUV).rgb;
// 2D rotational direction of the sun is stored in x and y
// but we need it to rotate around the y axis, so shuffle components
vec3 sunDir = vec3( sunDirection.x, 0, sunDirection.y );
// sunFactor +1 means sun directly overhead, noon
// sunFactor -1 means sun directly behind, midnight',
// sunFactor 0 means sun at horizon, sunset or sunrise',
float sunFactor = dot( vNormal, sunDir );
// amplify so we tend more towards pure day or pure night
if( sunFactor>0.0 )
sunFactor = sqrt( sunFactor );
else
sunFactor = -sqrt( -sunFactor );
float sunFactorNorm = (sunFactor + 1.0) * 0.5;
gl_FragColor.rgb = mix( worldNightColor, worldDayColor, sunFactorNorm );
gl_FragColor.a = 1.0;
}
`
});
答案 1 :(得分:2)
非常粗略(因为如果你是3D的新手,这是很多工作):
答案 2 :(得分:1)
I Hope this will solve your issue
<!DOCTYPE html>
<html>
<head>
<title>Hello, WebVR! - A-Frame</title>
<meta name="description" content="Hello, WebVR! - A-Frame">
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" width="1" height="3" color="#4CC3D9" shadow></a-box>
<a-plane position="0 0 -3" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>